diff options
547 files changed, 19522 insertions, 13099 deletions
diff --git a/Documentation/ABI/README b/Documentation/ABI/README new file mode 100644 index 000000000000..9feaf16f1617 --- /dev/null +++ b/Documentation/ABI/README | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | This directory attempts to document the ABI between the Linux kernel and | ||
| 2 | userspace, and the relative stability of these interfaces. Due to the | ||
| 3 | everchanging nature of Linux, and the differing maturity levels, these | ||
| 4 | interfaces should be used by userspace programs in different ways. | ||
| 5 | |||
| 6 | We have four different levels of ABI stability, as shown by the four | ||
| 7 | different subdirectories in this location. Interfaces may change levels | ||
| 8 | of stability according to the rules described below. | ||
| 9 | |||
| 10 | The different levels of stability are: | ||
| 11 | |||
| 12 | stable/ | ||
| 13 | This directory documents the interfaces that the developer has | ||
| 14 | defined to be stable. Userspace programs are free to use these | ||
| 15 | interfaces with no restrictions, and backward compatibility for | ||
| 16 | them will be guaranteed for at least 2 years. Most interfaces | ||
| 17 | (like syscalls) are expected to never change and always be | ||
| 18 | available. | ||
| 19 | |||
| 20 | testing/ | ||
| 21 | This directory documents interfaces that are felt to be stable, | ||
| 22 | as the main development of this interface has been completed. | ||
| 23 | The interface can be changed to add new features, but the | ||
| 24 | current interface will not break by doing this, unless grave | ||
| 25 | errors or security problems are found in them. Userspace | ||
| 26 | programs can start to rely on these interfaces, but they must be | ||
| 27 | aware of changes that can occur before these interfaces move to | ||
| 28 | be marked stable. Programs that use these interfaces are | ||
| 29 | strongly encouraged to add their name to the description of | ||
| 30 | these interfaces, so that the kernel developers can easily | ||
| 31 | notify them if any changes occur (see the description of the | ||
| 32 | layout of the files below for details on how to do this.) | ||
| 33 | |||
| 34 | obsolete/ | ||
| 35 | This directory documents interfaces that are still remaining in | ||
| 36 | the kernel, but are marked to be removed at some later point in | ||
| 37 | time. The description of the interface will document the reason | ||
| 38 | why it is obsolete and when it can be expected to be removed. | ||
| 39 | The file Documentation/feature-removal-schedule.txt may describe | ||
| 40 | some of these interfaces, giving a schedule for when they will | ||
| 41 | be removed. | ||
| 42 | |||
| 43 | removed/ | ||
| 44 | This directory contains a list of the old interfaces that have | ||
| 45 | been removed from the kernel. | ||
| 46 | |||
| 47 | Every file in these directories will contain the following information: | ||
| 48 | |||
| 49 | What: Short description of the interface | ||
| 50 | Date: Date created | ||
| 51 | KernelVersion: Kernel version this feature first showed up in. | ||
| 52 | Contact: Primary contact for this interface (may be a mailing list) | ||
| 53 | Description: Long description of the interface and how to use it. | ||
| 54 | Users: All users of this interface who wish to be notified when | ||
| 55 | it changes. This is very important for interfaces in | ||
| 56 | the "testing" stage, so that kernel developers can work | ||
| 57 | with userspace developers to ensure that things do not | ||
| 58 | break in ways that are unacceptable. It is also | ||
| 59 | important to get feedback for these interfaces to make | ||
| 60 | sure they are working in a proper way and do not need to | ||
| 61 | be changed further. | ||
| 62 | |||
| 63 | |||
| 64 | How things move between levels: | ||
| 65 | |||
| 66 | Interfaces in stable may move to obsolete, as long as the proper | ||
| 67 | notification is given. | ||
| 68 | |||
| 69 | Interfaces may be removed from obsolete and the kernel as long as the | ||
| 70 | documented amount of time has gone by. | ||
| 71 | |||
| 72 | Interfaces in the testing state can move to the stable state when the | ||
| 73 | developers feel they are finished. They cannot be removed from the | ||
| 74 | kernel tree without going through the obsolete state first. | ||
| 75 | |||
| 76 | It's up to the developer to place their interfaces in the category they | ||
| 77 | wish for it to start out in. | ||
diff --git a/Documentation/ABI/obsolete/devfs b/Documentation/ABI/obsolete/devfs new file mode 100644 index 000000000000..b8b87399bc8f --- /dev/null +++ b/Documentation/ABI/obsolete/devfs | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | What: devfs | ||
| 2 | Date: July 2005 | ||
| 3 | Contact: Greg Kroah-Hartman <gregkh@suse.de> | ||
| 4 | Description: | ||
| 5 | devfs has been unmaintained for a number of years, has unfixable | ||
| 6 | races, contains a naming policy within the kernel that is | ||
| 7 | against the LSB, and can be replaced by using udev. | ||
| 8 | The files fs/devfs/*, include/linux/devfs_fs*.h will be removed, | ||
| 9 | along with the the assorted devfs function calls throughout the | ||
| 10 | kernel tree. | ||
| 11 | |||
| 12 | Users: | ||
| 13 | |||
diff --git a/Documentation/ABI/stable/syscalls b/Documentation/ABI/stable/syscalls new file mode 100644 index 000000000000..c3ae3e7d6a0c --- /dev/null +++ b/Documentation/ABI/stable/syscalls | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | What: The kernel syscall interface | ||
| 2 | Description: | ||
| 3 | This interface matches much of the POSIX interface and is based | ||
| 4 | on it and other Unix based interfaces. It will only be added to | ||
| 5 | over time, and not have things removed from it. | ||
| 6 | |||
| 7 | Note that this interface is different for every architecture | ||
| 8 | that Linux supports. Please see the architecture-specific | ||
| 9 | documentation for details on the syscall numbers that are to be | ||
| 10 | mapped to each syscall. | ||
diff --git a/Documentation/ABI/stable/sysfs-module b/Documentation/ABI/stable/sysfs-module new file mode 100644 index 000000000000..75be43118335 --- /dev/null +++ b/Documentation/ABI/stable/sysfs-module | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | What: /sys/module | ||
| 2 | Description: | ||
| 3 | The /sys/module tree consists of the following structure: | ||
| 4 | |||
| 5 | /sys/module/MODULENAME | ||
| 6 | The name of the module that is in the kernel. This | ||
| 7 | module name will show up either if the module is built | ||
| 8 | directly into the kernel, or if it is loaded as a | ||
| 9 | dyanmic module. | ||
| 10 | |||
| 11 | /sys/module/MODULENAME/parameters | ||
| 12 | This directory contains individual files that are each | ||
| 13 | individual parameters of the module that are able to be | ||
| 14 | changed at runtime. See the individual module | ||
| 15 | documentation as to the contents of these parameters and | ||
| 16 | what they accomplish. | ||
| 17 | |||
| 18 | Note: The individual parameter names and values are not | ||
| 19 | considered stable, only the fact that they will be | ||
| 20 | placed in this location within sysfs. See the | ||
| 21 | individual driver documentation for details as to the | ||
| 22 | stability of the different parameters. | ||
| 23 | |||
| 24 | /sys/module/MODULENAME/refcnt | ||
| 25 | If the module is able to be unloaded from the kernel, this file | ||
| 26 | will contain the current reference count of the module. | ||
| 27 | |||
| 28 | Note: If the module is built into the kernel, or if the | ||
| 29 | CONFIG_MODULE_UNLOAD kernel configuration value is not enabled, | ||
| 30 | this file will not be present. | ||
diff --git a/Documentation/ABI/testing/sysfs-class b/Documentation/ABI/testing/sysfs-class new file mode 100644 index 000000000000..4b0cb891e46e --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | What: /sys/class/ | ||
| 2 | Date: Febuary 2006 | ||
| 3 | Contact: Greg Kroah-Hartman <gregkh@suse.de> | ||
| 4 | Description: | ||
| 5 | The /sys/class directory will consist of a group of | ||
| 6 | subdirectories describing individual classes of devices | ||
| 7 | in the kernel. The individual directories will consist | ||
| 8 | of either subdirectories, or symlinks to other | ||
| 9 | directories. | ||
| 10 | |||
| 11 | All programs that use this directory tree must be able | ||
| 12 | to handle both subdirectories or symlinks in order to | ||
| 13 | work properly. | ||
| 14 | |||
| 15 | Users: | ||
| 16 | udev <linux-hotplug-devel@lists.sourceforge.net> | ||
diff --git a/Documentation/ABI/testing/sysfs-devices b/Documentation/ABI/testing/sysfs-devices new file mode 100644 index 000000000000..6a25671ee5f6 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | What: /sys/devices | ||
| 2 | Date: February 2006 | ||
| 3 | Contact: Greg Kroah-Hartman <gregkh@suse.de> | ||
| 4 | Description: | ||
| 5 | The /sys/devices tree contains a snapshot of the | ||
| 6 | internal state of the kernel device tree. Devices will | ||
| 7 | be added and removed dynamically as the machine runs, | ||
| 8 | and between different kernel versions, the layout of the | ||
| 9 | devices within this tree will change. | ||
| 10 | |||
| 11 | Please do not rely on the format of this tree because of | ||
| 12 | this. If a program wishes to find different things in | ||
| 13 | the tree, please use the /sys/class structure and rely | ||
| 14 | on the symlinks there to point to the proper location | ||
| 15 | within the /sys/devices tree of the individual devices. | ||
| 16 | Or rely on the uevent messages to notify programs of | ||
| 17 | devices being added and removed from this tree to find | ||
| 18 | the location of those devices. | ||
| 19 | |||
| 20 | Note that sometimes not all devices along the directory | ||
| 21 | chain will have emitted uevent messages, so userspace | ||
| 22 | programs must be able to handle such occurrences. | ||
| 23 | |||
| 24 | Users: | ||
| 25 | udev <linux-hotplug-devel@lists.sourceforge.net> | ||
diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/README.gigaset index 85a64defd385..fa0d4cca964a 100644 --- a/Documentation/isdn/README.gigaset +++ b/Documentation/isdn/README.gigaset | |||
| @@ -124,7 +124,8 @@ GigaSet 307x Device Driver | |||
| 124 | 124 | ||
| 125 | You can use some configuration tool of your distribution to configure this | 125 | You can use some configuration tool of your distribution to configure this |
| 126 | "modem" or configure pppd/wvdial manually. There are some example ppp | 126 | "modem" or configure pppd/wvdial manually. There are some example ppp |
| 127 | configuration files and chat scripts in the gigaset-VERSION/ppp directory. | 127 | configuration files and chat scripts in the gigaset-VERSION/ppp directory |
| 128 | in the driver packages from http://sourceforge.net/projects/gigaset307x/. | ||
| 128 | Please note that the USB drivers are not able to change the state of the | 129 | Please note that the USB drivers are not able to change the state of the |
| 129 | control lines (the M105 driver can be configured to use some undocumented | 130 | control lines (the M105 driver can be configured to use some undocumented |
| 130 | control requests, if you really need the control lines, though). This means | 131 | control requests, if you really need the control lines, though). This means |
| @@ -164,8 +165,8 @@ GigaSet 307x Device Driver | |||
| 164 | 165 | ||
| 165 | If you want both of these at once, you are out of luck. | 166 | If you want both of these at once, you are out of luck. |
| 166 | 167 | ||
| 167 | You can also use /sys/module/<name>/parameters/cidmode for changing | 168 | You can also use /sys/class/tty/ttyGxy/cidmode for changing the CID mode |
| 168 | the CID mode setting (<name> is usb_gigaset or bas_gigaset). | 169 | setting (ttyGxy is ttyGU0 or ttyGB0). |
| 169 | 170 | ||
| 170 | 171 | ||
| 171 | 3. Troubleshooting | 172 | 3. Troubleshooting |
diff --git a/Documentation/keys.txt b/Documentation/keys.txt index aaa01b0e3ee9..3bbe157b45e4 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt | |||
| @@ -19,6 +19,7 @@ This document has the following sections: | |||
| 19 | - Key overview | 19 | - Key overview |
| 20 | - Key service overview | 20 | - Key service overview |
| 21 | - Key access permissions | 21 | - Key access permissions |
| 22 | - SELinux support | ||
| 22 | - New procfs files | 23 | - New procfs files |
| 23 | - Userspace system call interface | 24 | - Userspace system call interface |
| 24 | - Kernel services | 25 | - Kernel services |
| @@ -232,6 +233,34 @@ For changing the ownership, group ID or permissions mask, being the owner of | |||
| 232 | the key or having the sysadmin capability is sufficient. | 233 | the key or having the sysadmin capability is sufficient. |
| 233 | 234 | ||
| 234 | 235 | ||
| 236 | =============== | ||
| 237 | SELINUX SUPPORT | ||
| 238 | =============== | ||
| 239 | |||
| 240 | The security class "key" has been added to SELinux so that mandatory access | ||
| 241 | controls can be applied to keys created within various contexts. This support | ||
| 242 | is preliminary, and is likely to change quite significantly in the near future. | ||
| 243 | Currently, all of the basic permissions explained above are provided in SELinux | ||
| 244 | as well; SE Linux is simply invoked after all basic permission checks have been | ||
| 245 | performed. | ||
| 246 | |||
| 247 | Each key is labeled with the same context as the task to which it belongs. | ||
| 248 | Typically, this is the same task that was running when the key was created. | ||
| 249 | The default keyrings are handled differently, but in a way that is very | ||
| 250 | intuitive: | ||
| 251 | |||
| 252 | (*) The user and user session keyrings that are created when the user logs in | ||
| 253 | are currently labeled with the context of the login manager. | ||
| 254 | |||
| 255 | (*) The keyrings associated with new threads are each labeled with the context | ||
| 256 | of their associated thread, and both session and process keyrings are | ||
| 257 | handled similarly. | ||
| 258 | |||
| 259 | Note, however, that the default keyrings associated with the root user are | ||
| 260 | labeled with the default kernel context, since they are created early in the | ||
| 261 | boot process, before root has a chance to log in. | ||
| 262 | |||
| 263 | |||
| 235 | ================ | 264 | ================ |
| 236 | NEW PROCFS FILES | 265 | NEW PROCFS FILES |
| 237 | ================ | 266 | ================ |
| @@ -935,6 +964,16 @@ The structure has a number of fields, some of which are mandatory: | |||
| 935 | It is not safe to sleep in this method; the caller may hold spinlocks. | 964 | It is not safe to sleep in this method; the caller may hold spinlocks. |
| 936 | 965 | ||
| 937 | 966 | ||
| 967 | (*) void (*revoke)(struct key *key); | ||
| 968 | |||
| 969 | This method is optional. It is called to discard part of the payload | ||
| 970 | data upon a key being revoked. The caller will have the key semaphore | ||
| 971 | write-locked. | ||
| 972 | |||
| 973 | It is safe to sleep in this method, though care should be taken to avoid | ||
| 974 | a deadlock against the key semaphore. | ||
| 975 | |||
| 976 | |||
| 938 | (*) void (*destroy)(struct key *key); | 977 | (*) void (*destroy)(struct key *key); |
| 939 | 978 | ||
| 940 | This method is optional. It is called to discard the payload data on a key | 979 | This method is optional. It is called to discard the payload data on a key |
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index f987afe43e28..fba1e05c47c7 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt | |||
| @@ -135,96 +135,6 @@ HW. | |||
| 135 | 135 | ||
| 136 | FREEZE -- stop DMA and interrupts, and be prepared to reinit HW from | 136 | FREEZE -- stop DMA and interrupts, and be prepared to reinit HW from |
| 137 | scratch. That probably means stop accepting upstream requests, the | 137 | scratch. That probably means stop accepting upstream requests, the |
| 138 | actual policy of what to do with them beeing specific to a given | ||
| 139 | driver. It's acceptable for a network driver to just drop packets | ||
| 140 | while a block driver is expected to block the queue so no request is | ||
| 141 | lost. (Use IDE as an example on how to do that). FREEZE requires no | ||
| 142 | power state change, and it's expected for drivers to be able to | ||
| 143 | quickly transition back to operating state. | ||
| 144 | |||
| 145 | SUSPEND -- like FREEZE, but also put hardware into low-power state. If | ||
| 146 | there's need to distinguish several levels of sleep, additional flag | ||
| 147 | is probably best way to do that. | ||
| 148 | |||
| 149 | Transitions are only from a resumed state to a suspended state, never | ||
| 150 | between 2 suspended states. (ON -> FREEZE or ON -> SUSPEND can happen, | ||
| 151 | FREEZE -> SUSPEND or SUSPEND -> FREEZE can not). | ||
| 152 | |||
| 153 | All events are: | ||
| 154 | |||
| 155 | [NOTE NOTE NOTE: If you are driver author, you should not care; you | ||
| 156 | should only look at event, and ignore flags.] | ||
| 157 | |||
| 158 | #Prepare for suspend -- userland is still running but we are going to | ||
| 159 | #enter suspend state. This gives drivers chance to load firmware from | ||
| 160 | #disk and store it in memory, or do other activities taht require | ||
| 161 | #operating userland, ability to kmalloc GFP_KERNEL, etc... All of these | ||
| 162 | #are forbiden once the suspend dance is started.. event = ON, flags = | ||
| 163 | #PREPARE_TO_SUSPEND | ||
| 164 | |||
| 165 | Apm standby -- prepare for APM event. Quiesce devices to make life | ||
| 166 | easier for APM BIOS. event = FREEZE, flags = APM_STANDBY | ||
| 167 | |||
| 168 | Apm suspend -- same as APM_STANDBY, but it we should probably avoid | ||
| 169 | spinning down disks. event = FREEZE, flags = APM_SUSPEND | ||
| 170 | |||
| 171 | System halt, reboot -- quiesce devices to make life easier for BIOS. event | ||
| 172 | = FREEZE, flags = SYSTEM_HALT or SYSTEM_REBOOT | ||
| 173 | |||
| 174 | System shutdown -- at least disks need to be spun down, or data may be | ||
| 175 | lost. Quiesce devices, just to make life easier for BIOS. event = | ||
| 176 | FREEZE, flags = SYSTEM_SHUTDOWN | ||
| 177 | |||
| 178 | Kexec -- turn off DMAs and put hardware into some state where new | ||
| 179 | kernel can take over. event = FREEZE, flags = KEXEC | ||
| 180 | |||
| 181 | Powerdown at end of swsusp -- very similar to SYSTEM_SHUTDOWN, except wake | ||
| 182 | may need to be enabled on some devices. This actually has at least 3 | ||
| 183 | subtypes, system can reboot, enter S4 and enter S5 at the end of | ||
| 184 | swsusp. event = FREEZE, flags = SWSUSP and one of SYSTEM_REBOOT, | ||
| 185 | SYSTEM_SHUTDOWN, SYSTEM_S4 | ||
| 186 | |||
| 187 | Suspend to ram -- put devices into low power state. event = SUSPEND, | ||
| 188 | flags = SUSPEND_TO_RAM | ||
| 189 | |||
| 190 | Freeze for swsusp snapshot -- stop DMA and interrupts. No need to put | ||
| 191 | devices into low power mode, but you must be able to reinitialize | ||
| 192 | device from scratch in resume method. This has two flavors, its done | ||
| 193 | once on suspending kernel, once on resuming kernel. event = FREEZE, | ||
| 194 | flags = DURING_SUSPEND or DURING_RESUME | ||
| 195 | |||
| 196 | Device detach requested from /sys -- deinitialize device; proably same as | ||
| 197 | SYSTEM_SHUTDOWN, I do not understand this one too much. probably event | ||
| 198 | = FREEZE, flags = DEV_DETACH. | ||
| 199 | |||
| 200 | #These are not really events sent: | ||
| 201 | # | ||
| 202 | #System fully on -- device is working normally; this is probably never | ||
| 203 | #passed to suspend() method... event = ON, flags = 0 | ||
| 204 | # | ||
| 205 | #Ready after resume -- userland is now running, again. Time to free any | ||
| 206 | #memory you ate during prepare to suspend... event = ON, flags = | ||
| 207 | #READY_AFTER_RESUME | ||
| 208 | # | ||
| 209 | |||
| 210 | |||
| 211 | pm_message_t meaning | ||
| 212 | |||
| 213 | pm_message_t has two fields. event ("major"), and flags. If driver | ||
| 214 | does not know event code, it aborts the request, returning error. Some | ||
| 215 | drivers may need to deal with special cases based on the actual type | ||
| 216 | of suspend operation being done at the system level. This is why | ||
| 217 | there are flags. | ||
| 218 | |||
| 219 | Event codes are: | ||
| 220 | |||
| 221 | ON -- no need to do anything except special cases like broken | ||
| 222 | HW. | ||
| 223 | |||
| 224 | # NOTIFICATION -- pretty much same as ON? | ||
| 225 | |||
| 226 | FREEZE -- stop DMA and interrupts, and be prepared to reinit HW from | ||
| 227 | scratch. That probably means stop accepting upstream requests, the | ||
| 228 | actual policy of what to do with them being specific to a given | 138 | actual policy of what to do with them being specific to a given |
| 229 | driver. It's acceptable for a network driver to just drop packets | 139 | driver. It's acceptable for a network driver to just drop packets |
| 230 | while a block driver is expected to block the queue so no request is | 140 | while a block driver is expected to block the queue so no request is |
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt index d7814a113ee1..516c5019013b 100644 --- a/Documentation/power/swsusp.txt +++ b/Documentation/power/swsusp.txt | |||
| @@ -18,10 +18,11 @@ Some warnings, first. | |||
| 18 | * | 18 | * |
| 19 | * (*) suspend/resume support is needed to make it safe. | 19 | * (*) suspend/resume support is needed to make it safe. |
| 20 | * | 20 | * |
| 21 | * If you have any filesystems on USB devices mounted before suspend, | 21 | * If you have any filesystems on USB devices mounted before software suspend, |
| 22 | * they won't be accessible after resume and you may lose data, as though | 22 | * they won't be accessible after resume and you may lose data, as though |
| 23 | * you have unplugged the USB devices with mounted filesystems on them | 23 | * you have unplugged the USB devices with mounted filesystems on them; |
| 24 | * (see the FAQ below for details). | 24 | * see the FAQ below for details. (This is not true for more traditional |
| 25 | * power states like "standby", which normally don't turn USB off.) | ||
| 25 | 26 | ||
| 26 | You need to append resume=/dev/your_swap_partition to kernel command | 27 | You need to append resume=/dev/your_swap_partition to kernel command |
| 27 | line. Then you suspend by | 28 | line. Then you suspend by |
| @@ -204,7 +205,7 @@ Q: There don't seem to be any generally useful behavioral | |||
| 204 | distinctions between SUSPEND and FREEZE. | 205 | distinctions between SUSPEND and FREEZE. |
| 205 | 206 | ||
| 206 | A: Doing SUSPEND when you are asked to do FREEZE is always correct, | 207 | A: Doing SUSPEND when you are asked to do FREEZE is always correct, |
| 207 | but it may be unneccessarily slow. If you want USB to stay simple, | 208 | but it may be unneccessarily slow. If you want your driver to stay simple, |
| 208 | slowness may not matter to you. It can always be fixed later. | 209 | slowness may not matter to you. It can always be fixed later. |
| 209 | 210 | ||
| 210 | For devices like disk it does matter, you do not want to spindown for | 211 | For devices like disk it does matter, you do not want to spindown for |
| @@ -357,17 +358,25 @@ Q: Is this true that if I have a mounted filesystem on a USB device and | |||
| 357 | I suspend to disk, I can lose data unless the filesystem has been mounted | 358 | I suspend to disk, I can lose data unless the filesystem has been mounted |
| 358 | with "sync"? | 359 | with "sync"? |
| 359 | 360 | ||
| 360 | A: That's right. It depends on your hardware, and it could be true even for | 361 | A: That's right ... if you disconnect that device, you may lose data. |
| 361 | suspend-to-RAM. In fact, even with "-o sync" you can lose data if your | 362 | In fact, even with "-o sync" you can lose data if your programs have |
| 362 | programs have information in buffers they haven't written out to disk. | 363 | information in buffers they haven't written out to a disk you disconnect, |
| 364 | or if you disconnect before the device finished saving data you wrote. | ||
| 363 | 365 | ||
| 364 | If you're lucky, your hardware will support low-power modes for USB | 366 | Software suspend normally powers down USB controllers, which is equivalent |
| 365 | controllers while the system is asleep. Lots of hardware doesn't, | 367 | to disconnecting all USB devices attached to your system. |
| 366 | however. Shutting off the power to a USB controller is equivalent to | 368 | |
| 367 | unplugging all the attached devices. | 369 | Your system might well support low-power modes for its USB controllers |
| 370 | while the system is asleep, maintaining the connection, using true sleep | ||
| 371 | modes like "suspend-to-RAM" or "standby". (Don't write "disk" to the | ||
| 372 | /sys/power/state file; write "standby" or "mem".) We've not seen any | ||
| 373 | hardware that can use these modes through software suspend, although in | ||
| 374 | theory some systems might support "platform" or "firmware" modes that | ||
| 375 | won't break the USB connections. | ||
| 368 | 376 | ||
| 369 | Remember that it's always a bad idea to unplug a disk drive containing a | 377 | Remember that it's always a bad idea to unplug a disk drive containing a |
| 370 | mounted filesystem. With USB that's true even when your system is asleep! | 378 | mounted filesystem. That's true even when your system is asleep! The |
| 371 | The safest thing is to unmount all USB-based filesystems before suspending | 379 | safest thing is to unmount all filesystems on removable media (such USB, |
| 372 | and remount them after resuming. | 380 | Firewire, CompactFlash, MMC, external SATA, or even IDE hotplug bays) |
| 381 | before suspending; then remount them after resuming. | ||
| 373 | 382 | ||
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 0ee2c7dfc482..87d76a5c73d0 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
| @@ -366,7 +366,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 366 | 366 | ||
| 367 | Module for C-Media CMI8338 and 8738 PCI sound cards. | 367 | Module for C-Media CMI8338 and 8738 PCI sound cards. |
| 368 | 368 | ||
| 369 | mpu_port - 0x300,0x310,0x320,0x330, 0 = disable (default) | 369 | mpu_port - 0x300,0x310,0x320,0x330 = legacy port, |
| 370 | 1 = integrated PCI port, | ||
| 371 | 0 = disable (default) | ||
| 370 | fm_port - 0x388 (default), 0 = disable (default) | 372 | fm_port - 0x388 (default), 0 = disable (default) |
| 371 | soft_ac3 - Software-conversion of raw SPDIF packets (model 033 only) | 373 | soft_ac3 - Software-conversion of raw SPDIF packets (model 033 only) |
| 372 | (default = 1) | 374 | (default = 1) |
| @@ -468,7 +470,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 468 | 470 | ||
| 469 | Module for multifunction CS5535 companion PCI device | 471 | Module for multifunction CS5535 companion PCI device |
| 470 | 472 | ||
| 471 | This module supports multiple cards. | 473 | The power-management is supported. |
| 472 | 474 | ||
| 473 | Module snd-dt019x | 475 | Module snd-dt019x |
| 474 | ----------------- | 476 | ----------------- |
| @@ -707,8 +709,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 707 | Module snd-hda-intel | 709 | Module snd-hda-intel |
| 708 | -------------------- | 710 | -------------------- |
| 709 | 711 | ||
| 710 | Module for Intel HD Audio (ICH6, ICH6M, ICH7), ATI SB450, | 712 | Module for Intel HD Audio (ICH6, ICH6M, ESB2, ICH7, ICH8), |
| 711 | VIA VT8251/VT8237A | 713 | ATI SB450, SB600, RS600, |
| 714 | VIA VT8251/VT8237A, | ||
| 715 | SIS966, ULI M5461 | ||
| 712 | 716 | ||
| 713 | model - force the model name | 717 | model - force the model name |
| 714 | position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size) | 718 | position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size) |
| @@ -778,6 +782,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 778 | AD1981 | 782 | AD1981 |
| 779 | basic 3-jack (default) | 783 | basic 3-jack (default) |
| 780 | hp HP nx6320 | 784 | hp HP nx6320 |
| 785 | thinkpad Lenovo Thinkpad T60/X60/Z60 | ||
| 781 | 786 | ||
| 782 | AD1986A | 787 | AD1986A |
| 783 | 6stack 6-jack, separate surrounds (default) | 788 | 6stack 6-jack, separate surrounds (default) |
| @@ -1633,9 +1638,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 1633 | 1638 | ||
| 1634 | About capture IBL, see the description of snd-vx222 module. | 1639 | About capture IBL, see the description of snd-vx222 module. |
| 1635 | 1640 | ||
| 1636 | Note: the driver is build only when CONFIG_ISA is set. | 1641 | Note: snd-vxp440 driver is merged to snd-vxpocket driver since |
| 1637 | |||
| 1638 | Note2: snd-vxp440 driver is merged to snd-vxpocket driver since | ||
| 1639 | ALSA 1.0.10. | 1642 | ALSA 1.0.10. |
| 1640 | 1643 | ||
| 1641 | The power-management is supported. | 1644 | The power-management is supported. |
| @@ -1662,8 +1665,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 1662 | 1665 | ||
| 1663 | Module for Sound Core PDAudioCF sound card. | 1666 | Module for Sound Core PDAudioCF sound card. |
| 1664 | 1667 | ||
| 1665 | Note: the driver is build only when CONFIG_ISA is set. | ||
| 1666 | |||
| 1667 | The power-management is supported. | 1668 | The power-management is supported. |
| 1668 | 1669 | ||
| 1669 | 1670 | ||
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 1faf76383bab..635cbb94357c 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl | |||
| @@ -4215,7 +4215,7 @@ struct _snd_pcm_runtime { | |||
| 4215 | <programlisting> | 4215 | <programlisting> |
| 4216 | <![CDATA[ | 4216 | <![CDATA[ |
| 4217 | struct snd_rawmidi *rmidi; | 4217 | struct snd_rawmidi *rmidi; |
| 4218 | snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port, integrated, | 4218 | snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port, info_flags, |
| 4219 | irq, irq_flags, &rmidi); | 4219 | irq, irq_flags, &rmidi); |
| 4220 | ]]> | 4220 | ]]> |
| 4221 | </programlisting> | 4221 | </programlisting> |
| @@ -4242,15 +4242,36 @@ struct _snd_pcm_runtime { | |||
| 4242 | </para> | 4242 | </para> |
| 4243 | 4243 | ||
| 4244 | <para> | 4244 | <para> |
| 4245 | The 5th argument is bitflags for additional information. | ||
| 4245 | When the i/o port address above is a part of the PCI i/o | 4246 | When the i/o port address above is a part of the PCI i/o |
| 4246 | region, the MPU401 i/o port might have been already allocated | 4247 | region, the MPU401 i/o port might have been already allocated |
| 4247 | (reserved) by the driver itself. In such a case, pass non-zero | 4248 | (reserved) by the driver itself. In such a case, pass a bit flag |
| 4248 | to the 5th argument | 4249 | <constant>MPU401_INFO_INTEGRATED</constant>, |
| 4249 | (<parameter>integrated</parameter>). Otherwise, pass 0 to it, | ||
| 4250 | and | 4250 | and |
| 4251 | the mpu401-uart layer will allocate the i/o ports by itself. | 4251 | the mpu401-uart layer will allocate the i/o ports by itself. |
| 4252 | </para> | 4252 | </para> |
| 4253 | 4253 | ||
| 4254 | <para> | ||
| 4255 | When the controller supports only the input or output MIDI stream, | ||
| 4256 | pass <constant>MPU401_INFO_INPUT</constant> or | ||
| 4257 | <constant>MPU401_INFO_OUTPUT</constant> bitflag, respectively. | ||
| 4258 | Then the rawmidi instance is created as a single stream. | ||
| 4259 | </para> | ||
| 4260 | |||
| 4261 | <para> | ||
| 4262 | <constant>MPU401_INFO_MMIO</constant> bitflag is used to change | ||
| 4263 | the access method to MMIO (via readb and writeb) instead of | ||
| 4264 | iob and outb. In this case, you have to pass the iomapped address | ||
| 4265 | to <function>snd_mpu401_uart_new()</function>. | ||
| 4266 | </para> | ||
| 4267 | |||
| 4268 | <para> | ||
| 4269 | When <constant>MPU401_INFO_TX_IRQ</constant> is set, the output | ||
| 4270 | stream isn't checked in the default interrupt handler. The driver | ||
| 4271 | needs to call <function>snd_mpu401_uart_interrupt_tx()</function> | ||
| 4272 | by itself to start processing the output stream in irq handler. | ||
| 4273 | </para> | ||
| 4274 | |||
| 4254 | <para> | 4275 | <para> |
| 4255 | Usually, the port address corresponds to the command port and | 4276 | Usually, the port address corresponds to the command port and |
| 4256 | port + 1 corresponds to the data port. If not, you may change | 4277 | port + 1 corresponds to the data port. If not, you may change |
| @@ -5333,7 +5354,7 @@ struct _snd_pcm_runtime { | |||
| 5333 | <informalexample> | 5354 | <informalexample> |
| 5334 | <programlisting> | 5355 | <programlisting> |
| 5335 | <![CDATA[ | 5356 | <![CDATA[ |
| 5336 | snd_info_set_text_ops(entry, chip, read_size, my_proc_read); | 5357 | snd_info_set_text_ops(entry, chip, my_proc_read); |
| 5337 | ]]> | 5358 | ]]> |
| 5338 | </programlisting> | 5359 | </programlisting> |
| 5339 | </informalexample> | 5360 | </informalexample> |
| @@ -5394,7 +5415,6 @@ struct _snd_pcm_runtime { | |||
| 5394 | <informalexample> | 5415 | <informalexample> |
| 5395 | <programlisting> | 5416 | <programlisting> |
| 5396 | <![CDATA[ | 5417 | <![CDATA[ |
| 5397 | entry->c.text.write_size = 256; | ||
| 5398 | entry->c.text.write = my_proc_write; | 5418 | entry->c.text.write = my_proc_write; |
| 5399 | ]]> | 5419 | ]]> |
| 5400 | </programlisting> | 5420 | </programlisting> |
| @@ -5402,22 +5422,6 @@ struct _snd_pcm_runtime { | |||
| 5402 | </para> | 5422 | </para> |
| 5403 | 5423 | ||
| 5404 | <para> | 5424 | <para> |
| 5405 | The buffer size for read is set to 1024 implicitly by | ||
| 5406 | <function>snd_info_set_text_ops()</function>. It should suffice | ||
| 5407 | in most cases (the size will be aligned to | ||
| 5408 | <constant>PAGE_SIZE</constant> anyway), but if you need to handle | ||
| 5409 | very large text files, you can set it explicitly, too. | ||
| 5410 | |||
| 5411 | <informalexample> | ||
| 5412 | <programlisting> | ||
| 5413 | <![CDATA[ | ||
| 5414 | entry->c.text.read_size = 65536; | ||
| 5415 | ]]> | ||
| 5416 | </programlisting> | ||
| 5417 | </informalexample> | ||
| 5418 | </para> | ||
| 5419 | |||
| 5420 | <para> | ||
| 5421 | For the write callback, you can use | 5425 | For the write callback, you can use |
| 5422 | <function>snd_info_get_line()</function> to get a text line, and | 5426 | <function>snd_info_get_line()</function> to get a text line, and |
| 5423 | <function>snd_info_get_str()</function> to retrieve a string from | 5427 | <function>snd_info_get_str()</function> to retrieve a string from |
| @@ -5562,7 +5566,7 @@ struct _snd_pcm_runtime { | |||
| 5562 | power status.</para></listitem> | 5566 | power status.</para></listitem> |
| 5563 | <listitem><para>Call <function>snd_pcm_suspend_all()</function> to suspend the running PCM streams.</para></listitem> | 5567 | <listitem><para>Call <function>snd_pcm_suspend_all()</function> to suspend the running PCM streams.</para></listitem> |
| 5564 | <listitem><para>If AC97 codecs are used, call | 5568 | <listitem><para>If AC97 codecs are used, call |
| 5565 | <function>snd_ac97_resume()</function> for each codec.</para></listitem> | 5569 | <function>snd_ac97_suspend()</function> for each codec.</para></listitem> |
| 5566 | <listitem><para>Save the register values if necessary.</para></listitem> | 5570 | <listitem><para>Save the register values if necessary.</para></listitem> |
| 5567 | <listitem><para>Stop the hardware if necessary.</para></listitem> | 5571 | <listitem><para>Stop the hardware if necessary.</para></listitem> |
| 5568 | <listitem><para>Disable the PCI device by calling | 5572 | <listitem><para>Disable the PCI device by calling |
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index 63cb7edd177e..e65ec828d7aa 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt | |||
| @@ -29,14 +29,13 @@ if usbmon is built into the kernel. | |||
| 29 | 29 | ||
| 30 | # mount -t debugfs none_debugs /sys/kernel/debug | 30 | # mount -t debugfs none_debugs /sys/kernel/debug |
| 31 | # modprobe usbmon | 31 | # modprobe usbmon |
| 32 | # | ||
| 32 | 33 | ||
| 33 | Verify that bus sockets are present. | 34 | Verify that bus sockets are present. |
| 34 | 35 | ||
| 35 | [root@lembas zaitcev]# ls /sys/kernel/debug/usbmon | 36 | # ls /sys/kernel/debug/usbmon |
| 36 | 1s 1t 2s 2t 3s 3t 4s 4t | 37 | 1s 1t 2s 2t 3s 3t 4s 4t |
| 37 | [root@lembas zaitcev]# | 38 | # |
| 38 | |||
| 39 | # ls /sys/kernel | ||
| 40 | 39 | ||
| 41 | 2. Find which bus connects to the desired device | 40 | 2. Find which bus connects to the desired device |
| 42 | 41 | ||
| @@ -76,7 +75,7 @@ that the file size is not excessive for your favourite editor. | |||
| 76 | 75 | ||
| 77 | * Raw text data format | 76 | * Raw text data format |
| 78 | 77 | ||
| 79 | The '0t' type data consists of a stream of events, such as URB submission, | 78 | The '1t' type data consists of a stream of events, such as URB submission, |
| 80 | URB callback, submission error. Every event is a text line, which consists | 79 | URB callback, submission error. Every event is a text line, which consists |
| 81 | of whitespace separated words. The number of position of words may depend | 80 | of whitespace separated words. The number of position of words may depend |
| 82 | on the event type, but there is a set of words, common for all types. | 81 | on the event type, but there is a set of words, common for all types. |
| @@ -97,20 +96,25 @@ Here is the list of words, from left to right: | |||
| 97 | Zi Zo Isochronous input and output | 96 | Zi Zo Isochronous input and output |
| 98 | Ii Io Interrupt input and output | 97 | Ii Io Interrupt input and output |
| 99 | Bi Bo Bulk input and output | 98 | Bi Bo Bulk input and output |
| 100 | Device address and Endpoint number are decimal numbers with leading zeroes | 99 | Device address and Endpoint number are 3-digit and 2-digit (respectively) |
| 101 | or 3 and 2 positions, correspondingly. | 100 | decimal numbers, with leading zeroes. |
| 102 | - URB Status. This field makes no sense for submissions, but is present | 101 | - URB Status. In most cases, this field contains a number, sometimes negative, |
| 103 | to help scripts with parsing. In error case, it contains the error code. | 102 | which represents a "status" field of the URB. This field makes no sense for |
| 104 | In case of a setup packet, it contains a Setup Tag. If scripts read a number | 103 | submissions, but is present anyway to help scripts with parsing. When an |
| 105 | in this field, they proceed to read Data Length. Otherwise, they read | 104 | error occurs, the field contains the error code. In case of a submission of |
| 106 | the setup packet before reading the Data Length. | 105 | a Control packet, this field contains a Setup Tag instead of an error code. |
| 106 | It is easy to tell whether the Setup Tag is present because it is never a | ||
| 107 | number. Thus if scripts find a number in this field, they proceed to read | ||
| 108 | Data Length. If they find something else, like a letter, they read the setup | ||
| 109 | packet before reading the Data Length. | ||
| 107 | - Setup packet, if present, consists of 5 words: one of each for bmRequestType, | 110 | - Setup packet, if present, consists of 5 words: one of each for bmRequestType, |
| 108 | bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0. | 111 | bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0. |
| 109 | These words are safe to decode if Setup Tag was 's'. Otherwise, the setup | 112 | These words are safe to decode if Setup Tag was 's'. Otherwise, the setup |
| 110 | packet was present, but not captured, and the fields contain filler. | 113 | packet was present, but not captured, and the fields contain filler. |
| 111 | - Data Length. This is the actual length in the URB. | 114 | - Data Length. For submissions, this is the requested length. For callbacks, |
| 115 | this is the actual length. | ||
| 112 | - Data tag. The usbmon may not always capture data, even if length is nonzero. | 116 | - Data tag. The usbmon may not always capture data, even if length is nonzero. |
| 113 | Only if tag is '=', the data words are present. | 117 | The data words are present only if this tag is '='. |
| 114 | - Data words follow, in big endian hexadecimal format. Notice that they are | 118 | - Data words follow, in big endian hexadecimal format. Notice that they are |
| 115 | not machine words, but really just a byte stream split into words to make | 119 | not machine words, but really just a byte stream split into words to make |
| 116 | it easier to read. Thus, the last word may contain from one to four bytes. | 120 | it easier to read. Thus, the last word may contain from one to four bytes. |
diff --git a/MAINTAINERS b/MAINTAINERS index 0692c33d13cd..d10e629db563 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -3191,7 +3191,7 @@ XFS FILESYSTEM | |||
| 3191 | P: Silicon Graphics Inc | 3191 | P: Silicon Graphics Inc |
| 3192 | M: xfs-masters@oss.sgi.com | 3192 | M: xfs-masters@oss.sgi.com |
| 3193 | M: nathans@sgi.com | 3193 | M: nathans@sgi.com |
| 3194 | L: linux-xfs@oss.sgi.com | 3194 | L: xfs@oss.sgi.com |
| 3195 | W: http://oss.sgi.com/projects/xfs | 3195 | W: http://oss.sgi.com/projects/xfs |
| 3196 | S: Supported | 3196 | S: Supported |
| 3197 | 3197 | ||
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 840ae595a617..d961bfeed05f 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile | |||
| @@ -29,8 +29,8 @@ OBJCOPYFLAGS := contents,alloc,load,readonly,data | |||
| 29 | OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000 | 29 | OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000 |
| 30 | OBJCOPY_MIB_ARGS := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment | 30 | OBJCOPY_MIB_ARGS := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment |
| 31 | 31 | ||
| 32 | zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c | 32 | zlib := inffast.c inflate.c inftrees.c |
| 33 | zlibheader := infblock.h infcodes.h inffast.h inftrees.h infutil.h | 33 | zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h |
| 34 | zliblinuxheader := zlib.h zconf.h zutil.h | 34 | zliblinuxheader := zlib.h zconf.h zutil.h |
| 35 | 35 | ||
| 36 | $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader)) | 36 | $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader)) |
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index ceb584682fa3..71a3275935ec 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
| @@ -372,7 +372,7 @@ static int __init fsl_usb_of_init(void) | |||
| 372 | { | 372 | { |
| 373 | struct device_node *np; | 373 | struct device_node *np; |
| 374 | unsigned int i; | 374 | unsigned int i; |
| 375 | struct platform_device *usb_dev; | 375 | struct platform_device *usb_dev_mph = NULL, *usb_dev_dr = NULL; |
| 376 | int ret; | 376 | int ret; |
| 377 | 377 | ||
| 378 | for (np = NULL, i = 0; | 378 | for (np = NULL, i = 0; |
| @@ -393,15 +393,15 @@ static int __init fsl_usb_of_init(void) | |||
| 393 | r[1].end = np->intrs[0].line; | 393 | r[1].end = np->intrs[0].line; |
| 394 | r[1].flags = IORESOURCE_IRQ; | 394 | r[1].flags = IORESOURCE_IRQ; |
| 395 | 395 | ||
| 396 | usb_dev = | 396 | usb_dev_mph = |
| 397 | platform_device_register_simple("fsl-usb2-mph", i, r, 2); | 397 | platform_device_register_simple("fsl-ehci", i, r, 2); |
| 398 | if (IS_ERR(usb_dev)) { | 398 | if (IS_ERR(usb_dev_mph)) { |
| 399 | ret = PTR_ERR(usb_dev); | 399 | ret = PTR_ERR(usb_dev_mph); |
| 400 | goto err; | 400 | goto err; |
| 401 | } | 401 | } |
| 402 | 402 | ||
| 403 | usb_dev->dev.coherent_dma_mask = 0xffffffffUL; | 403 | usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL; |
| 404 | usb_dev->dev.dma_mask = &usb_dev->dev.coherent_dma_mask; | 404 | usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask; |
| 405 | 405 | ||
| 406 | usb_data.operating_mode = FSL_USB2_MPH_HOST; | 406 | usb_data.operating_mode = FSL_USB2_MPH_HOST; |
| 407 | 407 | ||
| @@ -417,31 +417,14 @@ static int __init fsl_usb_of_init(void) | |||
| 417 | usb_data.phy_mode = determine_usb_phy(prop); | 417 | usb_data.phy_mode = determine_usb_phy(prop); |
| 418 | 418 | ||
| 419 | ret = | 419 | ret = |
| 420 | platform_device_add_data(usb_dev, &usb_data, | 420 | platform_device_add_data(usb_dev_mph, &usb_data, |
| 421 | sizeof(struct | 421 | sizeof(struct |
| 422 | fsl_usb2_platform_data)); | 422 | fsl_usb2_platform_data)); |
| 423 | if (ret) | 423 | if (ret) |
| 424 | goto unreg; | 424 | goto unreg_mph; |
| 425 | } | 425 | } |
| 426 | 426 | ||
| 427 | return 0; | 427 | for (np = NULL; |
| 428 | |||
| 429 | unreg: | ||
| 430 | platform_device_unregister(usb_dev); | ||
| 431 | err: | ||
| 432 | return ret; | ||
| 433 | } | ||
| 434 | |||
| 435 | arch_initcall(fsl_usb_of_init); | ||
| 436 | |||
| 437 | static int __init fsl_usb_dr_of_init(void) | ||
| 438 | { | ||
| 439 | struct device_node *np; | ||
| 440 | unsigned int i; | ||
| 441 | struct platform_device *usb_dev; | ||
| 442 | int ret; | ||
| 443 | |||
| 444 | for (np = NULL, i = 0; | ||
| 445 | (np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL; | 428 | (np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL; |
| 446 | i++) { | 429 | i++) { |
| 447 | struct resource r[2]; | 430 | struct resource r[2]; |
| @@ -453,21 +436,21 @@ static int __init fsl_usb_dr_of_init(void) | |||
| 453 | 436 | ||
| 454 | ret = of_address_to_resource(np, 0, &r[0]); | 437 | ret = of_address_to_resource(np, 0, &r[0]); |
| 455 | if (ret) | 438 | if (ret) |
| 456 | goto err; | 439 | goto unreg_mph; |
| 457 | 440 | ||
| 458 | r[1].start = np->intrs[0].line; | 441 | r[1].start = np->intrs[0].line; |
| 459 | r[1].end = np->intrs[0].line; | 442 | r[1].end = np->intrs[0].line; |
| 460 | r[1].flags = IORESOURCE_IRQ; | 443 | r[1].flags = IORESOURCE_IRQ; |
| 461 | 444 | ||
| 462 | usb_dev = | 445 | usb_dev_dr = |
| 463 | platform_device_register_simple("fsl-usb2-dr", i, r, 2); | 446 | platform_device_register_simple("fsl-ehci", i, r, 2); |
| 464 | if (IS_ERR(usb_dev)) { | 447 | if (IS_ERR(usb_dev_dr)) { |
| 465 | ret = PTR_ERR(usb_dev); | 448 | ret = PTR_ERR(usb_dev_dr); |
| 466 | goto err; | 449 | goto err; |
| 467 | } | 450 | } |
| 468 | 451 | ||
| 469 | usb_dev->dev.coherent_dma_mask = 0xffffffffUL; | 452 | usb_dev_dr->dev.coherent_dma_mask = 0xffffffffUL; |
| 470 | usb_dev->dev.dma_mask = &usb_dev->dev.coherent_dma_mask; | 453 | usb_dev_dr->dev.dma_mask = &usb_dev_dr->dev.coherent_dma_mask; |
| 471 | 454 | ||
| 472 | usb_data.operating_mode = FSL_USB2_DR_HOST; | 455 | usb_data.operating_mode = FSL_USB2_DR_HOST; |
| 473 | 456 | ||
| @@ -475,19 +458,22 @@ static int __init fsl_usb_dr_of_init(void) | |||
| 475 | usb_data.phy_mode = determine_usb_phy(prop); | 458 | usb_data.phy_mode = determine_usb_phy(prop); |
| 476 | 459 | ||
| 477 | ret = | 460 | ret = |
| 478 | platform_device_add_data(usb_dev, &usb_data, | 461 | platform_device_add_data(usb_dev_dr, &usb_data, |
| 479 | sizeof(struct | 462 | sizeof(struct |
| 480 | fsl_usb2_platform_data)); | 463 | fsl_usb2_platform_data)); |
| 481 | if (ret) | 464 | if (ret) |
| 482 | goto unreg; | 465 | goto unreg_dr; |
| 483 | } | 466 | } |
| 484 | |||
| 485 | return 0; | 467 | return 0; |
| 486 | 468 | ||
| 487 | unreg: | 469 | unreg_dr: |
| 488 | platform_device_unregister(usb_dev); | 470 | if (usb_dev_dr) |
| 471 | platform_device_unregister(usb_dev_dr); | ||
| 472 | unreg_mph: | ||
| 473 | if (usb_dev_mph) | ||
| 474 | platform_device_unregister(usb_dev_mph); | ||
| 489 | err: | 475 | err: |
| 490 | return ret; | 476 | return ret; |
| 491 | } | 477 | } |
| 492 | 478 | ||
| 493 | arch_initcall(fsl_usb_dr_of_init); | 479 | arch_initcall(fsl_usb_of_init); |
diff --git a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile index 80c84d562fa4..2f995f712ec5 100644 --- a/arch/ppc/boot/lib/Makefile +++ b/arch/ppc/boot/lib/Makefile | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | CFLAGS_kbd.o := -Idrivers/char | 5 | CFLAGS_kbd.o := -Idrivers/char |
| 6 | CFLAGS_vreset.o := -Iarch/ppc/boot/include | 6 | CFLAGS_vreset.o := -Iarch/ppc/boot/include |
| 7 | 7 | ||
| 8 | zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c | 8 | zlib := inffast.c inflate.c inftrees.c |
| 9 | 9 | ||
| 10 | lib-y += $(zlib:.c=.o) div64.o | 10 | lib-y += $(zlib:.c=.o) div64.o |
| 11 | lib-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o | 11 | lib-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o |
diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c index 1af2c000fcfa..5c4932ca8e9b 100644 --- a/arch/ppc/syslib/mpc83xx_devices.c +++ b/arch/ppc/syslib/mpc83xx_devices.c | |||
| @@ -186,7 +186,7 @@ struct platform_device ppc_sys_platform_devices[] = { | |||
| 186 | }, | 186 | }, |
| 187 | }, | 187 | }, |
| 188 | [MPC83xx_USB2_DR] = { | 188 | [MPC83xx_USB2_DR] = { |
| 189 | .name = "fsl-usb2-dr", | 189 | .name = "fsl-ehci", |
| 190 | .id = 1, | 190 | .id = 1, |
| 191 | .num_resources = 2, | 191 | .num_resources = 2, |
| 192 | .resource = (struct resource[]) { | 192 | .resource = (struct resource[]) { |
| @@ -203,8 +203,8 @@ struct platform_device ppc_sys_platform_devices[] = { | |||
| 203 | }, | 203 | }, |
| 204 | }, | 204 | }, |
| 205 | [MPC83xx_USB2_MPH] = { | 205 | [MPC83xx_USB2_MPH] = { |
| 206 | .name = "fsl-usb2-mph", | 206 | .name = "fsl-ehci", |
| 207 | .id = 1, | 207 | .id = 2, |
| 208 | .num_resources = 2, | 208 | .num_resources = 2, |
| 209 | .resource = (struct resource[]) { | 209 | .resource = (struct resource[]) { |
| 210 | { | 210 | { |
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 2cbf282f0d00..a893a9cc9534 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c | |||
| @@ -332,7 +332,7 @@ void __init setup_arch(char **cmdline_p) | |||
| 332 | if (!root_flags) | 332 | if (!root_flags) |
| 333 | root_mountflags &= ~MS_RDONLY; | 333 | root_mountflags &= ~MS_RDONLY; |
| 334 | ROOT_DEV = old_decode_dev(root_dev); | 334 | ROOT_DEV = old_decode_dev(root_dev); |
| 335 | #ifdef CONFIG_BLK_DEV_INITRD | 335 | #ifdef CONFIG_BLK_DEV_RAM |
| 336 | rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK; | 336 | rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK; |
| 337 | rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); | 337 | rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0); |
| 338 | rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); | 338 | rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0); |
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 86f51d04c98d..87cdbc560d36 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c | |||
| @@ -87,7 +87,7 @@ void timer_irq(union uml_pt_regs *regs) | |||
| 87 | 87 | ||
| 88 | void time_init_kern(void) | 88 | void time_init_kern(void) |
| 89 | { | 89 | { |
| 90 | unsigned long long nsecs; | 90 | long long nsecs; |
| 91 | 91 | ||
| 92 | nsecs = os_nsecs(); | 92 | nsecs = os_nsecs(); |
| 93 | set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION, | 93 | set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION, |
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 408d44a59756..7d3bc5ac5db0 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig | |||
| @@ -389,6 +389,7 @@ config GART_IOMMU | |||
| 389 | bool "K8 GART IOMMU support" | 389 | bool "K8 GART IOMMU support" |
| 390 | default y | 390 | default y |
| 391 | select SWIOTLB | 391 | select SWIOTLB |
| 392 | select AGP | ||
| 392 | depends on PCI | 393 | depends on PCI |
| 393 | help | 394 | help |
| 394 | Support for hardware IOMMU in AMD's Opteron/Athlon64 Processors | 395 | Support for hardware IOMMU in AMD's Opteron/Athlon64 Processors |
| @@ -401,11 +402,9 @@ config GART_IOMMU | |||
| 401 | northbridge and a software emulation used on other systems without | 402 | northbridge and a software emulation used on other systems without |
| 402 | hardware IOMMU. If unsure, say Y. | 403 | hardware IOMMU. If unsure, say Y. |
| 403 | 404 | ||
| 404 | # need this always enabled with GART_IOMMU for the VIA workaround | 405 | # need this always selected by GART_IOMMU for the VIA workaround |
| 405 | config SWIOTLB | 406 | config SWIOTLB |
| 406 | bool | 407 | bool |
| 407 | default y | ||
| 408 | depends on GART_IOMMU | ||
| 409 | 408 | ||
| 410 | config X86_MCE | 409 | config X86_MCE |
| 411 | bool "Machine check support" if EMBEDDED | 410 | bool "Machine check support" if EMBEDDED |
diff --git a/arch/xtensa/boot/lib/Makefile b/arch/xtensa/boot/lib/Makefile index 9e73bb8aeb7a..d3d2aa2d883a 100644 --- a/arch/xtensa/boot/lib/Makefile +++ b/arch/xtensa/boot/lib/Makefile | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # Makefile for some libs needed by zImage. | 2 | # Makefile for some libs needed by zImage. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c | 5 | zlib := inffast.c inflate.c inftrees.c |
| 6 | 6 | ||
| 7 | lib-y += $(zlib:.c=.o) zmem.o | 7 | lib-y += $(zlib:.c=.o) zmem.o |
| 8 | 8 | ||
diff --git a/block/genhd.c b/block/genhd.c index 5a8d3bf02f17..8d7339511e5e 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
| @@ -17,8 +17,7 @@ | |||
| 17 | #include <linux/buffer_head.h> | 17 | #include <linux/buffer_head.h> |
| 18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
| 19 | 19 | ||
| 20 | static struct subsystem block_subsys; | 20 | struct subsystem block_subsys; |
| 21 | |||
| 22 | static DEFINE_MUTEX(block_subsys_lock); | 21 | static DEFINE_MUTEX(block_subsys_lock); |
| 23 | 22 | ||
| 24 | /* | 23 | /* |
| @@ -511,9 +510,7 @@ static struct kset_uevent_ops block_uevent_ops = { | |||
| 511 | .uevent = block_uevent, | 510 | .uevent = block_uevent, |
| 512 | }; | 511 | }; |
| 513 | 512 | ||
| 514 | /* declare block_subsys. */ | 513 | decl_subsys(block, &ktype_block, &block_uevent_ops); |
| 515 | static decl_subsys(block, &ktype_block, &block_uevent_ops); | ||
| 516 | |||
| 517 | 514 | ||
| 518 | /* | 515 | /* |
| 519 | * aggregate disk stat collector. Uses the same stats that the sysfs | 516 | * aggregate disk stat collector. Uses the same stats that the sysfs |
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index f0eff3dac58d..80502dc6ed66 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig | |||
| @@ -38,3 +38,7 @@ config DEBUG_DRIVER | |||
| 38 | If you are unsure about this, say N here. | 38 | If you are unsure about this, say N here. |
| 39 | 39 | ||
| 40 | endmenu | 40 | endmenu |
| 41 | |||
| 42 | config SYS_HYPERVISOR | ||
| 43 | bool | ||
| 44 | default n | ||
diff --git a/drivers/base/Makefile b/drivers/base/Makefile index e99471d3232b..b539e5e75b56 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile | |||
| @@ -5,10 +5,12 @@ obj-y := core.o sys.o bus.o dd.o \ | |||
| 5 | cpu.o firmware.o init.o map.o dmapool.o \ | 5 | cpu.o firmware.o init.o map.o dmapool.o \ |
| 6 | attribute_container.o transport_class.o | 6 | attribute_container.o transport_class.o |
| 7 | obj-y += power/ | 7 | obj-y += power/ |
| 8 | obj-$(CONFIG_ISA) += isa.o | ||
| 8 | obj-$(CONFIG_FW_LOADER) += firmware_class.o | 9 | obj-$(CONFIG_FW_LOADER) += firmware_class.o |
| 9 | obj-$(CONFIG_NUMA) += node.o | 10 | obj-$(CONFIG_NUMA) += node.o |
| 10 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o | 11 | obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o |
| 11 | obj-$(CONFIG_SMP) += topology.o | 12 | obj-$(CONFIG_SMP) += topology.o |
| 13 | obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o | ||
| 12 | 14 | ||
| 13 | ifeq ($(CONFIG_DEBUG_DRIVER),y) | 15 | ifeq ($(CONFIG_DEBUG_DRIVER),y) |
| 14 | EXTRA_CFLAGS += -DDEBUG | 16 | EXTRA_CFLAGS += -DDEBUG |
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 2a7d7ae83e1e..22220733f76f 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c | |||
| @@ -236,7 +236,6 @@ attribute_container_remove_device(struct device *dev, | |||
| 236 | } | 236 | } |
| 237 | up(&attribute_container_mutex); | 237 | up(&attribute_container_mutex); |
| 238 | } | 238 | } |
| 239 | EXPORT_SYMBOL_GPL(attribute_container_remove_device); | ||
| 240 | 239 | ||
| 241 | /** | 240 | /** |
| 242 | * attribute_container_device_trigger - execute a trigger for each matching classdev | 241 | * attribute_container_device_trigger - execute a trigger for each matching classdev |
| @@ -276,7 +275,6 @@ attribute_container_device_trigger(struct device *dev, | |||
| 276 | } | 275 | } |
| 277 | up(&attribute_container_mutex); | 276 | up(&attribute_container_mutex); |
| 278 | } | 277 | } |
| 279 | EXPORT_SYMBOL_GPL(attribute_container_device_trigger); | ||
| 280 | 278 | ||
| 281 | /** | 279 | /** |
| 282 | * attribute_container_trigger - trigger a function for each matching container | 280 | * attribute_container_trigger - trigger a function for each matching container |
| @@ -304,7 +302,6 @@ attribute_container_trigger(struct device *dev, | |||
| 304 | } | 302 | } |
| 305 | up(&attribute_container_mutex); | 303 | up(&attribute_container_mutex); |
| 306 | } | 304 | } |
| 307 | EXPORT_SYMBOL_GPL(attribute_container_trigger); | ||
| 308 | 305 | ||
| 309 | /** | 306 | /** |
| 310 | * attribute_container_add_attrs - add attributes | 307 | * attribute_container_add_attrs - add attributes |
| @@ -333,7 +330,6 @@ attribute_container_add_attrs(struct class_device *classdev) | |||
| 333 | 330 | ||
| 334 | return 0; | 331 | return 0; |
| 335 | } | 332 | } |
| 336 | EXPORT_SYMBOL_GPL(attribute_container_add_attrs); | ||
| 337 | 333 | ||
| 338 | /** | 334 | /** |
| 339 | * attribute_container_add_class_device - same function as class_device_add | 335 | * attribute_container_add_class_device - same function as class_device_add |
| @@ -352,7 +348,6 @@ attribute_container_add_class_device(struct class_device *classdev) | |||
| 352 | return error; | 348 | return error; |
| 353 | return attribute_container_add_attrs(classdev); | 349 | return attribute_container_add_attrs(classdev); |
| 354 | } | 350 | } |
| 355 | EXPORT_SYMBOL_GPL(attribute_container_add_class_device); | ||
| 356 | 351 | ||
| 357 | /** | 352 | /** |
| 358 | * attribute_container_add_class_device_adapter - simple adapter for triggers | 353 | * attribute_container_add_class_device_adapter - simple adapter for triggers |
| @@ -367,7 +362,6 @@ attribute_container_add_class_device_adapter(struct attribute_container *cont, | |||
| 367 | { | 362 | { |
| 368 | return attribute_container_add_class_device(classdev); | 363 | return attribute_container_add_class_device(classdev); |
| 369 | } | 364 | } |
| 370 | EXPORT_SYMBOL_GPL(attribute_container_add_class_device_adapter); | ||
| 371 | 365 | ||
| 372 | /** | 366 | /** |
| 373 | * attribute_container_remove_attrs - remove any attribute files | 367 | * attribute_container_remove_attrs - remove any attribute files |
| @@ -389,7 +383,6 @@ attribute_container_remove_attrs(struct class_device *classdev) | |||
| 389 | for (i = 0; attrs[i]; i++) | 383 | for (i = 0; attrs[i]; i++) |
| 390 | class_device_remove_file(classdev, attrs[i]); | 384 | class_device_remove_file(classdev, attrs[i]); |
| 391 | } | 385 | } |
| 392 | EXPORT_SYMBOL_GPL(attribute_container_remove_attrs); | ||
| 393 | 386 | ||
| 394 | /** | 387 | /** |
| 395 | * attribute_container_class_device_del - equivalent of class_device_del | 388 | * attribute_container_class_device_del - equivalent of class_device_del |
| @@ -405,7 +398,6 @@ attribute_container_class_device_del(struct class_device *classdev) | |||
| 405 | attribute_container_remove_attrs(classdev); | 398 | attribute_container_remove_attrs(classdev); |
| 406 | class_device_del(classdev); | 399 | class_device_del(classdev); |
| 407 | } | 400 | } |
| 408 | EXPORT_SYMBOL_GPL(attribute_container_class_device_del); | ||
| 409 | 401 | ||
| 410 | /** | 402 | /** |
| 411 | * attribute_container_find_class_device - find the corresponding class_device | 403 | * attribute_container_find_class_device - find the corresponding class_device |
diff --git a/drivers/base/base.h b/drivers/base/base.h index 5735b38582d0..c3b8dc98b8a7 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h | |||
| @@ -5,13 +5,21 @@ extern int devices_init(void); | |||
| 5 | extern int buses_init(void); | 5 | extern int buses_init(void); |
| 6 | extern int classes_init(void); | 6 | extern int classes_init(void); |
| 7 | extern int firmware_init(void); | 7 | extern int firmware_init(void); |
| 8 | #ifdef CONFIG_SYS_HYPERVISOR | ||
| 9 | extern int hypervisor_init(void); | ||
| 10 | #else | ||
| 11 | static inline int hypervisor_init(void) { return 0; } | ||
| 12 | #endif | ||
| 8 | extern int platform_bus_init(void); | 13 | extern int platform_bus_init(void); |
| 9 | extern int system_bus_init(void); | 14 | extern int system_bus_init(void); |
| 10 | extern int cpu_dev_init(void); | 15 | extern int cpu_dev_init(void); |
| 11 | extern int attribute_container_init(void); | 16 | extern int attribute_container_init(void); |
| 12 | 17 | ||
| 13 | extern int bus_add_device(struct device * dev); | 18 | extern int bus_add_device(struct device * dev); |
| 19 | extern void bus_attach_device(struct device * dev); | ||
| 14 | extern void bus_remove_device(struct device * dev); | 20 | extern void bus_remove_device(struct device * dev); |
| 21 | extern struct bus_type *get_bus(struct bus_type * bus); | ||
| 22 | extern void put_bus(struct bus_type * bus); | ||
| 15 | 23 | ||
| 16 | extern int bus_add_driver(struct device_driver *); | 24 | extern int bus_add_driver(struct device_driver *); |
| 17 | extern void bus_remove_driver(struct device_driver *); | 25 | extern void bus_remove_driver(struct device_driver *); |
| @@ -34,4 +42,5 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) | |||
| 34 | return container_of(_attr, struct class_device_attribute, attr); | 42 | return container_of(_attr, struct class_device_attribute, attr); |
| 35 | } | 43 | } |
| 36 | 44 | ||
| 45 | extern char *make_class_name(const char *name, struct kobject *kobj); | ||
| 37 | 46 | ||
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 76656acd00d4..050d86d0b872 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
| @@ -362,8 +362,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev) | |||
| 362 | * @dev: device being added | 362 | * @dev: device being added |
| 363 | * | 363 | * |
| 364 | * - Add the device to its bus's list of devices. | 364 | * - Add the device to its bus's list of devices. |
| 365 | * - Try to attach to driver. | 365 | * - Create link to device's bus. |
| 366 | * - Create link to device's physical location. | ||
| 367 | */ | 366 | */ |
| 368 | int bus_add_device(struct device * dev) | 367 | int bus_add_device(struct device * dev) |
| 369 | { | 368 | { |
| @@ -372,11 +371,10 @@ int bus_add_device(struct device * dev) | |||
| 372 | 371 | ||
| 373 | if (bus) { | 372 | if (bus) { |
| 374 | pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); | 373 | pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); |
| 375 | device_attach(dev); | ||
| 376 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); | ||
| 377 | error = device_add_attrs(bus, dev); | 374 | error = device_add_attrs(bus, dev); |
| 378 | if (!error) { | 375 | if (!error) { |
| 379 | sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); | 376 | sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); |
| 377 | sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "subsystem"); | ||
| 380 | sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus"); | 378 | sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus"); |
| 381 | } | 379 | } |
| 382 | } | 380 | } |
| @@ -384,6 +382,22 @@ int bus_add_device(struct device * dev) | |||
| 384 | } | 382 | } |
| 385 | 383 | ||
| 386 | /** | 384 | /** |
| 385 | * bus_attach_device - add device to bus | ||
| 386 | * @dev: device tried to attach to a driver | ||
| 387 | * | ||
| 388 | * - Try to attach to driver. | ||
| 389 | */ | ||
| 390 | void bus_attach_device(struct device * dev) | ||
| 391 | { | ||
| 392 | struct bus_type * bus = dev->bus; | ||
| 393 | |||
| 394 | if (bus) { | ||
| 395 | device_attach(dev); | ||
| 396 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | /** | ||
| 387 | * bus_remove_device - remove device from bus | 401 | * bus_remove_device - remove device from bus |
| 388 | * @dev: device to be removed | 402 | * @dev: device to be removed |
| 389 | * | 403 | * |
| @@ -395,6 +409,7 @@ int bus_add_device(struct device * dev) | |||
| 395 | void bus_remove_device(struct device * dev) | 409 | void bus_remove_device(struct device * dev) |
| 396 | { | 410 | { |
| 397 | if (dev->bus) { | 411 | if (dev->bus) { |
| 412 | sysfs_remove_link(&dev->kobj, "subsystem"); | ||
| 398 | sysfs_remove_link(&dev->kobj, "bus"); | 413 | sysfs_remove_link(&dev->kobj, "bus"); |
| 399 | sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); | 414 | sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); |
| 400 | device_remove_attrs(dev->bus, dev); | 415 | device_remove_attrs(dev->bus, dev); |
| @@ -732,14 +747,9 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev); | |||
| 732 | EXPORT_SYMBOL_GPL(bus_find_device); | 747 | EXPORT_SYMBOL_GPL(bus_find_device); |
| 733 | EXPORT_SYMBOL_GPL(bus_for_each_drv); | 748 | EXPORT_SYMBOL_GPL(bus_for_each_drv); |
| 734 | 749 | ||
| 735 | EXPORT_SYMBOL_GPL(bus_add_device); | ||
| 736 | EXPORT_SYMBOL_GPL(bus_remove_device); | ||
| 737 | EXPORT_SYMBOL_GPL(bus_register); | 750 | EXPORT_SYMBOL_GPL(bus_register); |
| 738 | EXPORT_SYMBOL_GPL(bus_unregister); | 751 | EXPORT_SYMBOL_GPL(bus_unregister); |
| 739 | EXPORT_SYMBOL_GPL(bus_rescan_devices); | 752 | EXPORT_SYMBOL_GPL(bus_rescan_devices); |
| 740 | EXPORT_SYMBOL_GPL(get_bus); | ||
| 741 | EXPORT_SYMBOL_GPL(put_bus); | ||
| 742 | EXPORT_SYMBOL_GPL(find_bus); | ||
| 743 | 753 | ||
| 744 | EXPORT_SYMBOL_GPL(bus_create_file); | 754 | EXPORT_SYMBOL_GPL(bus_create_file); |
| 745 | EXPORT_SYMBOL_GPL(bus_remove_file); | 755 | EXPORT_SYMBOL_GPL(bus_remove_file); |
diff --git a/drivers/base/class.c b/drivers/base/class.c index b1ea4df85c7d..9aa127460262 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
| @@ -91,14 +91,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) | |||
| 91 | sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr); | 91 | sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr); |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | struct class * class_get(struct class * cls) | 94 | static struct class *class_get(struct class *cls) |
| 95 | { | 95 | { |
| 96 | if (cls) | 96 | if (cls) |
| 97 | return container_of(subsys_get(&cls->subsys), struct class, subsys); | 97 | return container_of(subsys_get(&cls->subsys), struct class, subsys); |
| 98 | return NULL; | 98 | return NULL; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | void class_put(struct class * cls) | 101 | static void class_put(struct class * cls) |
| 102 | { | 102 | { |
| 103 | if (cls) | 103 | if (cls) |
| 104 | subsys_put(&cls->subsys); | 104 | subsys_put(&cls->subsys); |
| @@ -142,6 +142,7 @@ int class_register(struct class * cls) | |||
| 142 | pr_debug("device class '%s': registering\n", cls->name); | 142 | pr_debug("device class '%s': registering\n", cls->name); |
| 143 | 143 | ||
| 144 | INIT_LIST_HEAD(&cls->children); | 144 | INIT_LIST_HEAD(&cls->children); |
| 145 | INIT_LIST_HEAD(&cls->devices); | ||
| 145 | INIT_LIST_HEAD(&cls->interfaces); | 146 | INIT_LIST_HEAD(&cls->interfaces); |
| 146 | init_MUTEX(&cls->sem); | 147 | init_MUTEX(&cls->sem); |
| 147 | error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); | 148 | error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); |
| @@ -504,22 +505,21 @@ void class_device_initialize(struct class_device *class_dev) | |||
| 504 | INIT_LIST_HEAD(&class_dev->node); | 505 | INIT_LIST_HEAD(&class_dev->node); |
| 505 | } | 506 | } |
| 506 | 507 | ||
| 507 | static char *make_class_name(struct class_device *class_dev) | 508 | char *make_class_name(const char *name, struct kobject *kobj) |
| 508 | { | 509 | { |
| 509 | char *name; | 510 | char *class_name; |
| 510 | int size; | 511 | int size; |
| 511 | 512 | ||
| 512 | size = strlen(class_dev->class->name) + | 513 | size = strlen(name) + strlen(kobject_name(kobj)) + 2; |
| 513 | strlen(kobject_name(&class_dev->kobj)) + 2; | ||
| 514 | 514 | ||
| 515 | name = kmalloc(size, GFP_KERNEL); | 515 | class_name = kmalloc(size, GFP_KERNEL); |
| 516 | if (!name) | 516 | if (!class_name) |
| 517 | return ERR_PTR(-ENOMEM); | 517 | return ERR_PTR(-ENOMEM); |
| 518 | 518 | ||
| 519 | strcpy(name, class_dev->class->name); | 519 | strcpy(class_name, name); |
| 520 | strcat(name, ":"); | 520 | strcat(class_name, ":"); |
| 521 | strcat(name, kobject_name(&class_dev->kobj)); | 521 | strcat(class_name, kobject_name(kobj)); |
| 522 | return name; | 522 | return class_name; |
| 523 | } | 523 | } |
| 524 | 524 | ||
| 525 | int class_device_add(struct class_device *class_dev) | 525 | int class_device_add(struct class_device *class_dev) |
| @@ -535,18 +535,22 @@ int class_device_add(struct class_device *class_dev) | |||
| 535 | return -EINVAL; | 535 | return -EINVAL; |
| 536 | 536 | ||
| 537 | if (!strlen(class_dev->class_id)) | 537 | if (!strlen(class_dev->class_id)) |
| 538 | goto register_done; | 538 | goto out1; |
| 539 | 539 | ||
| 540 | parent_class = class_get(class_dev->class); | 540 | parent_class = class_get(class_dev->class); |
| 541 | if (!parent_class) | 541 | if (!parent_class) |
| 542 | goto register_done; | 542 | goto out1; |
| 543 | |||
| 543 | parent_class_dev = class_device_get(class_dev->parent); | 544 | parent_class_dev = class_device_get(class_dev->parent); |
| 544 | 545 | ||
| 545 | pr_debug("CLASS: registering class device: ID = '%s'\n", | 546 | pr_debug("CLASS: registering class device: ID = '%s'\n", |
| 546 | class_dev->class_id); | 547 | class_dev->class_id); |
| 547 | 548 | ||
| 548 | /* first, register with generic layer. */ | 549 | /* first, register with generic layer. */ |
| 549 | kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id); | 550 | error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id); |
| 551 | if (error) | ||
| 552 | goto out2; | ||
| 553 | |||
| 550 | if (parent_class_dev) | 554 | if (parent_class_dev) |
| 551 | class_dev->kobj.parent = &parent_class_dev->kobj; | 555 | class_dev->kobj.parent = &parent_class_dev->kobj; |
| 552 | else | 556 | else |
| @@ -554,41 +558,58 @@ int class_device_add(struct class_device *class_dev) | |||
| 554 | 558 | ||
| 555 | error = kobject_add(&class_dev->kobj); | 559 | error = kobject_add(&class_dev->kobj); |
| 556 | if (error) | 560 | if (error) |
| 557 | goto register_done; | 561 | goto out2; |
| 558 | 562 | ||
| 559 | /* add the needed attributes to this device */ | 563 | /* add the needed attributes to this device */ |
| 564 | sysfs_create_link(&class_dev->kobj, &parent_class->subsys.kset.kobj, "subsystem"); | ||
| 560 | class_dev->uevent_attr.attr.name = "uevent"; | 565 | class_dev->uevent_attr.attr.name = "uevent"; |
| 561 | class_dev->uevent_attr.attr.mode = S_IWUSR; | 566 | class_dev->uevent_attr.attr.mode = S_IWUSR; |
| 562 | class_dev->uevent_attr.attr.owner = parent_class->owner; | 567 | class_dev->uevent_attr.attr.owner = parent_class->owner; |
| 563 | class_dev->uevent_attr.store = store_uevent; | 568 | class_dev->uevent_attr.store = store_uevent; |
| 564 | class_device_create_file(class_dev, &class_dev->uevent_attr); | 569 | error = class_device_create_file(class_dev, &class_dev->uevent_attr); |
| 570 | if (error) | ||
| 571 | goto out3; | ||
| 565 | 572 | ||
| 566 | if (MAJOR(class_dev->devt)) { | 573 | if (MAJOR(class_dev->devt)) { |
| 567 | struct class_device_attribute *attr; | 574 | struct class_device_attribute *attr; |
| 568 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | 575 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); |
| 569 | if (!attr) { | 576 | if (!attr) { |
| 570 | error = -ENOMEM; | 577 | error = -ENOMEM; |
| 571 | kobject_del(&class_dev->kobj); | 578 | goto out4; |
| 572 | goto register_done; | ||
| 573 | } | 579 | } |
| 574 | attr->attr.name = "dev"; | 580 | attr->attr.name = "dev"; |
| 575 | attr->attr.mode = S_IRUGO; | 581 | attr->attr.mode = S_IRUGO; |
| 576 | attr->attr.owner = parent_class->owner; | 582 | attr->attr.owner = parent_class->owner; |
| 577 | attr->show = show_dev; | 583 | attr->show = show_dev; |
| 578 | class_device_create_file(class_dev, attr); | 584 | error = class_device_create_file(class_dev, attr); |
| 585 | if (error) { | ||
| 586 | kfree(attr); | ||
| 587 | goto out4; | ||
| 588 | } | ||
| 589 | |||
| 579 | class_dev->devt_attr = attr; | 590 | class_dev->devt_attr = attr; |
| 580 | } | 591 | } |
| 581 | 592 | ||
| 582 | class_device_add_attrs(class_dev); | 593 | error = class_device_add_attrs(class_dev); |
| 594 | if (error) | ||
| 595 | goto out5; | ||
| 596 | |||
| 583 | if (class_dev->dev) { | 597 | if (class_dev->dev) { |
| 584 | class_name = make_class_name(class_dev); | 598 | class_name = make_class_name(class_dev->class->name, |
| 585 | sysfs_create_link(&class_dev->kobj, | 599 | &class_dev->kobj); |
| 586 | &class_dev->dev->kobj, "device"); | 600 | error = sysfs_create_link(&class_dev->kobj, |
| 587 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | 601 | &class_dev->dev->kobj, "device"); |
| 588 | class_name); | 602 | if (error) |
| 603 | goto out6; | ||
| 604 | error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | ||
| 605 | class_name); | ||
| 606 | if (error) | ||
| 607 | goto out7; | ||
| 589 | } | 608 | } |
| 590 | 609 | ||
| 591 | class_device_add_groups(class_dev); | 610 | error = class_device_add_groups(class_dev); |
| 611 | if (error) | ||
| 612 | goto out8; | ||
| 592 | 613 | ||
| 593 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); | 614 | kobject_uevent(&class_dev->kobj, KOBJ_ADD); |
| 594 | 615 | ||
| @@ -601,11 +622,28 @@ int class_device_add(struct class_device *class_dev) | |||
| 601 | } | 622 | } |
| 602 | up(&parent_class->sem); | 623 | up(&parent_class->sem); |
| 603 | 624 | ||
| 604 | register_done: | 625 | goto out1; |
| 605 | if (error) { | 626 | |
| 606 | class_put(parent_class); | 627 | out8: |
| 628 | if (class_dev->dev) | ||
| 629 | sysfs_remove_link(&class_dev->kobj, class_name); | ||
| 630 | out7: | ||
| 631 | if (class_dev->dev) | ||
| 632 | sysfs_remove_link(&class_dev->kobj, "device"); | ||
| 633 | out6: | ||
| 634 | class_device_remove_attrs(class_dev); | ||
| 635 | out5: | ||
| 636 | if (class_dev->devt_attr) | ||
| 637 | class_device_remove_file(class_dev, class_dev->devt_attr); | ||
| 638 | out4: | ||
| 639 | class_device_remove_file(class_dev, &class_dev->uevent_attr); | ||
| 640 | out3: | ||
| 641 | kobject_del(&class_dev->kobj); | ||
| 642 | out2: | ||
| 643 | if(parent_class_dev) | ||
| 607 | class_device_put(parent_class_dev); | 644 | class_device_put(parent_class_dev); |
| 608 | } | 645 | class_put(parent_class); |
| 646 | out1: | ||
| 609 | class_device_put(class_dev); | 647 | class_device_put(class_dev); |
| 610 | kfree(class_name); | 648 | kfree(class_name); |
| 611 | return error; | 649 | return error; |
| @@ -695,10 +733,12 @@ void class_device_del(struct class_device *class_dev) | |||
| 695 | } | 733 | } |
| 696 | 734 | ||
| 697 | if (class_dev->dev) { | 735 | if (class_dev->dev) { |
| 698 | class_name = make_class_name(class_dev); | 736 | class_name = make_class_name(class_dev->class->name, |
| 737 | &class_dev->kobj); | ||
| 699 | sysfs_remove_link(&class_dev->kobj, "device"); | 738 | sysfs_remove_link(&class_dev->kobj, "device"); |
| 700 | sysfs_remove_link(&class_dev->dev->kobj, class_name); | 739 | sysfs_remove_link(&class_dev->dev->kobj, class_name); |
| 701 | } | 740 | } |
| 741 | sysfs_remove_link(&class_dev->kobj, "subsystem"); | ||
| 702 | class_device_remove_file(class_dev, &class_dev->uevent_attr); | 742 | class_device_remove_file(class_dev, &class_dev->uevent_attr); |
| 703 | if (class_dev->devt_attr) | 743 | if (class_dev->devt_attr) |
| 704 | class_device_remove_file(class_dev, class_dev->devt_attr); | 744 | class_device_remove_file(class_dev, class_dev->devt_attr); |
| @@ -760,14 +800,16 @@ int class_device_rename(struct class_device *class_dev, char *new_name) | |||
| 760 | new_name); | 800 | new_name); |
| 761 | 801 | ||
| 762 | if (class_dev->dev) | 802 | if (class_dev->dev) |
| 763 | old_class_name = make_class_name(class_dev); | 803 | old_class_name = make_class_name(class_dev->class->name, |
| 804 | &class_dev->kobj); | ||
| 764 | 805 | ||
| 765 | strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); | 806 | strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); |
| 766 | 807 | ||
| 767 | error = kobject_rename(&class_dev->kobj, new_name); | 808 | error = kobject_rename(&class_dev->kobj, new_name); |
| 768 | 809 | ||
| 769 | if (class_dev->dev) { | 810 | if (class_dev->dev) { |
| 770 | new_class_name = make_class_name(class_dev); | 811 | new_class_name = make_class_name(class_dev->class->name, |
| 812 | &class_dev->kobj); | ||
| 771 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, | 813 | sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, |
| 772 | new_class_name); | 814 | new_class_name); |
| 773 | sysfs_remove_link(&class_dev->dev->kobj, old_class_name); | 815 | sysfs_remove_link(&class_dev->dev->kobj, old_class_name); |
| @@ -858,8 +900,6 @@ EXPORT_SYMBOL_GPL(class_create_file); | |||
| 858 | EXPORT_SYMBOL_GPL(class_remove_file); | 900 | EXPORT_SYMBOL_GPL(class_remove_file); |
| 859 | EXPORT_SYMBOL_GPL(class_register); | 901 | EXPORT_SYMBOL_GPL(class_register); |
| 860 | EXPORT_SYMBOL_GPL(class_unregister); | 902 | EXPORT_SYMBOL_GPL(class_unregister); |
| 861 | EXPORT_SYMBOL_GPL(class_get); | ||
| 862 | EXPORT_SYMBOL_GPL(class_put); | ||
| 863 | EXPORT_SYMBOL_GPL(class_create); | 903 | EXPORT_SYMBOL_GPL(class_create); |
| 864 | EXPORT_SYMBOL_GPL(class_destroy); | 904 | EXPORT_SYMBOL_GPL(class_destroy); |
| 865 | 905 | ||
diff --git a/drivers/base/core.c b/drivers/base/core.c index 6b355bd7816d..d0f84ff78776 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
| 18 | #include <linux/kdev_t.h> | ||
| 18 | 19 | ||
| 19 | #include <asm/semaphore.h> | 20 | #include <asm/semaphore.h> |
| 20 | 21 | ||
| @@ -28,6 +29,22 @@ int (*platform_notify_remove)(struct device * dev) = NULL; | |||
| 28 | * sysfs bindings for devices. | 29 | * sysfs bindings for devices. |
| 29 | */ | 30 | */ |
| 30 | 31 | ||
| 32 | /** | ||
| 33 | * dev_driver_string - Return a device's driver name, if at all possible | ||
| 34 | * @dev: struct device to get the name of | ||
| 35 | * | ||
| 36 | * Will return the device's driver's name if it is bound to a device. If | ||
| 37 | * the device is not bound to a device, it will return the name of the bus | ||
| 38 | * it is attached to. If it is not attached to a bus either, an empty | ||
| 39 | * string will be returned. | ||
| 40 | */ | ||
| 41 | const char *dev_driver_string(struct device *dev) | ||
| 42 | { | ||
| 43 | return dev->driver ? dev->driver->name : | ||
| 44 | (dev->bus ? dev->bus->name : ""); | ||
| 45 | } | ||
| 46 | EXPORT_SYMBOL_GPL(dev_driver_string); | ||
| 47 | |||
| 31 | #define to_dev(obj) container_of(obj, struct device, kobj) | 48 | #define to_dev(obj) container_of(obj, struct device, kobj) |
| 32 | #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) | 49 | #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) |
| 33 | 50 | ||
| @@ -98,6 +115,8 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) | |||
| 98 | struct device *dev = to_dev(kobj); | 115 | struct device *dev = to_dev(kobj); |
| 99 | if (dev->bus) | 116 | if (dev->bus) |
| 100 | return 1; | 117 | return 1; |
| 118 | if (dev->class) | ||
| 119 | return 1; | ||
| 101 | } | 120 | } |
| 102 | return 0; | 121 | return 0; |
| 103 | } | 122 | } |
| @@ -106,7 +125,11 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) | |||
| 106 | { | 125 | { |
| 107 | struct device *dev = to_dev(kobj); | 126 | struct device *dev = to_dev(kobj); |
| 108 | 127 | ||
| 109 | return dev->bus->name; | 128 | if (dev->bus) |
| 129 | return dev->bus->name; | ||
| 130 | if (dev->class) | ||
| 131 | return dev->class->name; | ||
| 132 | return NULL; | ||
| 110 | } | 133 | } |
| 111 | 134 | ||
| 112 | static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | 135 | static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, |
| @@ -117,6 +140,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | |||
| 117 | int length = 0; | 140 | int length = 0; |
| 118 | int retval = 0; | 141 | int retval = 0; |
| 119 | 142 | ||
| 143 | /* add the major/minor if present */ | ||
| 144 | if (MAJOR(dev->devt)) { | ||
| 145 | add_uevent_var(envp, num_envp, &i, | ||
| 146 | buffer, buffer_size, &length, | ||
| 147 | "MAJOR=%u", MAJOR(dev->devt)); | ||
| 148 | add_uevent_var(envp, num_envp, &i, | ||
| 149 | buffer, buffer_size, &length, | ||
| 150 | "MINOR=%u", MINOR(dev->devt)); | ||
| 151 | } | ||
| 152 | |||
| 120 | /* add bus name of physical device */ | 153 | /* add bus name of physical device */ |
| 121 | if (dev->bus) | 154 | if (dev->bus) |
| 122 | add_uevent_var(envp, num_envp, &i, | 155 | add_uevent_var(envp, num_envp, &i, |
| @@ -161,6 +194,12 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, | |||
| 161 | return count; | 194 | return count; |
| 162 | } | 195 | } |
| 163 | 196 | ||
| 197 | static ssize_t show_dev(struct device *dev, struct device_attribute *attr, | ||
| 198 | char *buf) | ||
| 199 | { | ||
| 200 | return print_dev_t(buf, dev->devt); | ||
| 201 | } | ||
| 202 | |||
| 164 | /* | 203 | /* |
| 165 | * devices_subsys - structure to be registered with kobject core. | 204 | * devices_subsys - structure to be registered with kobject core. |
| 166 | */ | 205 | */ |
| @@ -231,6 +270,7 @@ void device_initialize(struct device *dev) | |||
| 231 | klist_init(&dev->klist_children, klist_children_get, | 270 | klist_init(&dev->klist_children, klist_children_get, |
| 232 | klist_children_put); | 271 | klist_children_put); |
| 233 | INIT_LIST_HEAD(&dev->dma_pools); | 272 | INIT_LIST_HEAD(&dev->dma_pools); |
| 273 | INIT_LIST_HEAD(&dev->node); | ||
| 234 | init_MUTEX(&dev->sem); | 274 | init_MUTEX(&dev->sem); |
| 235 | device_init_wakeup(dev, 0); | 275 | device_init_wakeup(dev, 0); |
| 236 | } | 276 | } |
| @@ -249,6 +289,7 @@ void device_initialize(struct device *dev) | |||
| 249 | int device_add(struct device *dev) | 289 | int device_add(struct device *dev) |
| 250 | { | 290 | { |
| 251 | struct device *parent = NULL; | 291 | struct device *parent = NULL; |
| 292 | char *class_name = NULL; | ||
| 252 | int error = -EINVAL; | 293 | int error = -EINVAL; |
| 253 | 294 | ||
| 254 | dev = get_device(dev); | 295 | dev = get_device(dev); |
| @@ -274,11 +315,44 @@ int device_add(struct device *dev) | |||
| 274 | dev->uevent_attr.store = store_uevent; | 315 | dev->uevent_attr.store = store_uevent; |
| 275 | device_create_file(dev, &dev->uevent_attr); | 316 | device_create_file(dev, &dev->uevent_attr); |
| 276 | 317 | ||
| 277 | kobject_uevent(&dev->kobj, KOBJ_ADD); | 318 | if (MAJOR(dev->devt)) { |
| 319 | struct device_attribute *attr; | ||
| 320 | attr = kzalloc(sizeof(*attr), GFP_KERNEL); | ||
| 321 | if (!attr) { | ||
| 322 | error = -ENOMEM; | ||
| 323 | goto PMError; | ||
| 324 | } | ||
| 325 | attr->attr.name = "dev"; | ||
| 326 | attr->attr.mode = S_IRUGO; | ||
| 327 | if (dev->driver) | ||
| 328 | attr->attr.owner = dev->driver->owner; | ||
| 329 | attr->show = show_dev; | ||
| 330 | error = device_create_file(dev, attr); | ||
| 331 | if (error) { | ||
| 332 | kfree(attr); | ||
| 333 | goto attrError; | ||
| 334 | } | ||
| 335 | |||
| 336 | dev->devt_attr = attr; | ||
| 337 | } | ||
| 338 | |||
| 339 | if (dev->class) { | ||
| 340 | sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj, | ||
| 341 | "subsystem"); | ||
| 342 | sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, | ||
| 343 | dev->bus_id); | ||
| 344 | |||
| 345 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); | ||
| 346 | class_name = make_class_name(dev->class->name, &dev->kobj); | ||
| 347 | sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name); | ||
| 348 | } | ||
| 349 | |||
| 278 | if ((error = device_pm_add(dev))) | 350 | if ((error = device_pm_add(dev))) |
| 279 | goto PMError; | 351 | goto PMError; |
| 280 | if ((error = bus_add_device(dev))) | 352 | if ((error = bus_add_device(dev))) |
| 281 | goto BusError; | 353 | goto BusError; |
| 354 | kobject_uevent(&dev->kobj, KOBJ_ADD); | ||
| 355 | bus_attach_device(dev); | ||
| 282 | if (parent) | 356 | if (parent) |
| 283 | klist_add_tail(&dev->knode_parent, &parent->klist_children); | 357 | klist_add_tail(&dev->knode_parent, &parent->klist_children); |
| 284 | 358 | ||
| @@ -286,11 +360,17 @@ int device_add(struct device *dev) | |||
| 286 | if (platform_notify) | 360 | if (platform_notify) |
| 287 | platform_notify(dev); | 361 | platform_notify(dev); |
| 288 | Done: | 362 | Done: |
| 363 | kfree(class_name); | ||
| 289 | put_device(dev); | 364 | put_device(dev); |
| 290 | return error; | 365 | return error; |
| 291 | BusError: | 366 | BusError: |
| 292 | device_pm_remove(dev); | 367 | device_pm_remove(dev); |
| 293 | PMError: | 368 | PMError: |
| 369 | if (dev->devt_attr) { | ||
| 370 | device_remove_file(dev, dev->devt_attr); | ||
| 371 | kfree(dev->devt_attr); | ||
| 372 | } | ||
| 373 | attrError: | ||
| 294 | kobject_uevent(&dev->kobj, KOBJ_REMOVE); | 374 | kobject_uevent(&dev->kobj, KOBJ_REMOVE); |
| 295 | kobject_del(&dev->kobj); | 375 | kobject_del(&dev->kobj); |
| 296 | Error: | 376 | Error: |
| @@ -362,9 +442,20 @@ void put_device(struct device * dev) | |||
| 362 | void device_del(struct device * dev) | 442 | void device_del(struct device * dev) |
| 363 | { | 443 | { |
| 364 | struct device * parent = dev->parent; | 444 | struct device * parent = dev->parent; |
| 445 | char *class_name = NULL; | ||
| 365 | 446 | ||
| 366 | if (parent) | 447 | if (parent) |
| 367 | klist_del(&dev->knode_parent); | 448 | klist_del(&dev->knode_parent); |
| 449 | if (dev->devt_attr) | ||
| 450 | device_remove_file(dev, dev->devt_attr); | ||
| 451 | if (dev->class) { | ||
| 452 | sysfs_remove_link(&dev->kobj, "subsystem"); | ||
| 453 | sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id); | ||
| 454 | class_name = make_class_name(dev->class->name, &dev->kobj); | ||
| 455 | sysfs_remove_link(&dev->kobj, "device"); | ||
| 456 | sysfs_remove_link(&dev->parent->kobj, class_name); | ||
| 457 | kfree(class_name); | ||
| 458 | } | ||
| 368 | device_remove_file(dev, &dev->uevent_attr); | 459 | device_remove_file(dev, &dev->uevent_attr); |
| 369 | 460 | ||
| 370 | /* Notify the platform of the removal, in case they | 461 | /* Notify the platform of the removal, in case they |
| @@ -449,3 +540,105 @@ EXPORT_SYMBOL_GPL(put_device); | |||
| 449 | 540 | ||
| 450 | EXPORT_SYMBOL_GPL(device_create_file); | 541 | EXPORT_SYMBOL_GPL(device_create_file); |
| 451 | EXPORT_SYMBOL_GPL(device_remove_file); | 542 | EXPORT_SYMBOL_GPL(device_remove_file); |
| 543 | |||
| 544 | |||
| 545 | static void device_create_release(struct device *dev) | ||
| 546 | { | ||
| 547 | pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id); | ||
| 548 | kfree(dev); | ||
| 549 | } | ||
| 550 | |||
| 551 | /** | ||
| 552 | * device_create - creates a device and registers it with sysfs | ||
| 553 | * @cs: pointer to the struct class that this device should be registered to. | ||
| 554 | * @parent: pointer to the parent struct device of this new device, if any. | ||
| 555 | * @dev: the dev_t for the char device to be added. | ||
| 556 | * @fmt: string for the class device's name | ||
| 557 | * | ||
| 558 | * This function can be used by char device classes. A struct | ||
| 559 | * device will be created in sysfs, registered to the specified | ||
| 560 | * class. | ||
| 561 | * A "dev" file will be created, showing the dev_t for the device, if | ||
| 562 | * the dev_t is not 0,0. | ||
| 563 | * If a pointer to a parent struct device is passed in, the newly | ||
| 564 | * created struct device will be a child of that device in sysfs. The | ||
| 565 | * pointer to the struct device will be returned from the call. Any | ||
| 566 | * further sysfs files that might be required can be created using this | ||
| 567 | * pointer. | ||
| 568 | * | ||
| 569 | * Note: the struct class passed to this function must have previously | ||
| 570 | * been created with a call to class_create(). | ||
| 571 | */ | ||
| 572 | struct device *device_create(struct class *class, struct device *parent, | ||
| 573 | dev_t devt, char *fmt, ...) | ||
| 574 | { | ||
| 575 | va_list args; | ||
| 576 | struct device *dev = NULL; | ||
| 577 | int retval = -ENODEV; | ||
| 578 | |||
| 579 | if (class == NULL || IS_ERR(class)) | ||
| 580 | goto error; | ||
| 581 | if (parent == NULL) { | ||
| 582 | printk(KERN_WARNING "%s does not work yet for NULL parents\n", __FUNCTION__); | ||
| 583 | goto error; | ||
| 584 | } | ||
| 585 | |||
| 586 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
| 587 | if (!dev) { | ||
| 588 | retval = -ENOMEM; | ||
| 589 | goto error; | ||
| 590 | } | ||
| 591 | |||
| 592 | dev->devt = devt; | ||
| 593 | dev->class = class; | ||
| 594 | dev->parent = parent; | ||
| 595 | dev->release = device_create_release; | ||
| 596 | |||
| 597 | va_start(args, fmt); | ||
| 598 | vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); | ||
| 599 | va_end(args); | ||
| 600 | retval = device_register(dev); | ||
| 601 | if (retval) | ||
| 602 | goto error; | ||
| 603 | |||
| 604 | /* tie the class to the device */ | ||
| 605 | down(&class->sem); | ||
| 606 | list_add_tail(&dev->node, &class->devices); | ||
| 607 | up(&class->sem); | ||
| 608 | |||
| 609 | return dev; | ||
| 610 | |||
| 611 | error: | ||
| 612 | kfree(dev); | ||
| 613 | return ERR_PTR(retval); | ||
| 614 | } | ||
| 615 | EXPORT_SYMBOL_GPL(device_create); | ||
| 616 | |||
| 617 | /** | ||
| 618 | * device_destroy - removes a device that was created with device_create() | ||
| 619 | * @class: the pointer to the struct class that this device was registered * with. | ||
| 620 | * @dev: the dev_t of the device that was previously registered. | ||
| 621 | * | ||
| 622 | * This call unregisters and cleans up a class device that was created with a | ||
| 623 | * call to class_device_create() | ||
| 624 | */ | ||
| 625 | void device_destroy(struct class *class, dev_t devt) | ||
| 626 | { | ||
| 627 | struct device *dev = NULL; | ||
| 628 | struct device *dev_tmp; | ||
| 629 | |||
| 630 | down(&class->sem); | ||
| 631 | list_for_each_entry(dev_tmp, &class->devices, node) { | ||
| 632 | if (dev_tmp->devt == devt) { | ||
| 633 | dev = dev_tmp; | ||
| 634 | break; | ||
| 635 | } | ||
| 636 | } | ||
| 637 | up(&class->sem); | ||
| 638 | |||
| 639 | if (dev) { | ||
| 640 | list_del_init(&dev->node); | ||
| 641 | device_unregister(dev); | ||
| 642 | } | ||
| 643 | } | ||
| 644 | EXPORT_SYMBOL_GPL(device_destroy); | ||
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 0c99ae6a3407..5d6c011183f5 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #include <linux/vmalloc.h> | 15 | #include <linux/vmalloc.h> |
| 16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
| 17 | #include <linux/bitops.h> | 17 | #include <linux/bitops.h> |
| 18 | #include <asm/semaphore.h> | 18 | #include <linux/mutex.h> |
| 19 | 19 | ||
| 20 | #include <linux/firmware.h> | 20 | #include <linux/firmware.h> |
| 21 | #include "base.h" | 21 | #include "base.h" |
| @@ -36,7 +36,7 @@ static int loading_timeout = 10; /* In seconds */ | |||
| 36 | 36 | ||
| 37 | /* fw_lock could be moved to 'struct firmware_priv' but since it is just | 37 | /* fw_lock could be moved to 'struct firmware_priv' but since it is just |
| 38 | * guarding for corner cases a global lock should be OK */ | 38 | * guarding for corner cases a global lock should be OK */ |
| 39 | static DECLARE_MUTEX(fw_lock); | 39 | static DEFINE_MUTEX(fw_lock); |
| 40 | 40 | ||
| 41 | struct firmware_priv { | 41 | struct firmware_priv { |
| 42 | char fw_id[FIRMWARE_NAME_MAX]; | 42 | char fw_id[FIRMWARE_NAME_MAX]; |
| @@ -142,9 +142,9 @@ firmware_loading_store(struct class_device *class_dev, | |||
| 142 | 142 | ||
| 143 | switch (loading) { | 143 | switch (loading) { |
| 144 | case 1: | 144 | case 1: |
| 145 | down(&fw_lock); | 145 | mutex_lock(&fw_lock); |
| 146 | if (!fw_priv->fw) { | 146 | if (!fw_priv->fw) { |
| 147 | up(&fw_lock); | 147 | mutex_unlock(&fw_lock); |
| 148 | break; | 148 | break; |
| 149 | } | 149 | } |
| 150 | vfree(fw_priv->fw->data); | 150 | vfree(fw_priv->fw->data); |
| @@ -152,7 +152,7 @@ firmware_loading_store(struct class_device *class_dev, | |||
| 152 | fw_priv->fw->size = 0; | 152 | fw_priv->fw->size = 0; |
| 153 | fw_priv->alloc_size = 0; | 153 | fw_priv->alloc_size = 0; |
| 154 | set_bit(FW_STATUS_LOADING, &fw_priv->status); | 154 | set_bit(FW_STATUS_LOADING, &fw_priv->status); |
| 155 | up(&fw_lock); | 155 | mutex_unlock(&fw_lock); |
| 156 | break; | 156 | break; |
| 157 | case 0: | 157 | case 0: |
| 158 | if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) { | 158 | if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) { |
| @@ -185,7 +185,7 @@ firmware_data_read(struct kobject *kobj, | |||
| 185 | struct firmware *fw; | 185 | struct firmware *fw; |
| 186 | ssize_t ret_count = count; | 186 | ssize_t ret_count = count; |
| 187 | 187 | ||
| 188 | down(&fw_lock); | 188 | mutex_lock(&fw_lock); |
| 189 | fw = fw_priv->fw; | 189 | fw = fw_priv->fw; |
| 190 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { | 190 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { |
| 191 | ret_count = -ENODEV; | 191 | ret_count = -ENODEV; |
| @@ -200,7 +200,7 @@ firmware_data_read(struct kobject *kobj, | |||
| 200 | 200 | ||
| 201 | memcpy(buffer, fw->data + offset, ret_count); | 201 | memcpy(buffer, fw->data + offset, ret_count); |
| 202 | out: | 202 | out: |
| 203 | up(&fw_lock); | 203 | mutex_unlock(&fw_lock); |
| 204 | return ret_count; | 204 | return ret_count; |
| 205 | } | 205 | } |
| 206 | 206 | ||
| @@ -253,7 +253,7 @@ firmware_data_write(struct kobject *kobj, | |||
| 253 | if (!capable(CAP_SYS_RAWIO)) | 253 | if (!capable(CAP_SYS_RAWIO)) |
| 254 | return -EPERM; | 254 | return -EPERM; |
| 255 | 255 | ||
| 256 | down(&fw_lock); | 256 | mutex_lock(&fw_lock); |
| 257 | fw = fw_priv->fw; | 257 | fw = fw_priv->fw; |
| 258 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { | 258 | if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) { |
| 259 | retval = -ENODEV; | 259 | retval = -ENODEV; |
| @@ -268,7 +268,7 @@ firmware_data_write(struct kobject *kobj, | |||
| 268 | fw->size = max_t(size_t, offset + count, fw->size); | 268 | fw->size = max_t(size_t, offset + count, fw->size); |
| 269 | retval = count; | 269 | retval = count; |
| 270 | out: | 270 | out: |
| 271 | up(&fw_lock); | 271 | mutex_unlock(&fw_lock); |
| 272 | return retval; | 272 | return retval; |
| 273 | } | 273 | } |
| 274 | 274 | ||
| @@ -436,14 +436,14 @@ _request_firmware(const struct firmware **firmware_p, const char *name, | |||
| 436 | } else | 436 | } else |
| 437 | wait_for_completion(&fw_priv->completion); | 437 | wait_for_completion(&fw_priv->completion); |
| 438 | 438 | ||
| 439 | down(&fw_lock); | 439 | mutex_lock(&fw_lock); |
| 440 | if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) { | 440 | if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) { |
| 441 | retval = -ENOENT; | 441 | retval = -ENOENT; |
| 442 | release_firmware(fw_priv->fw); | 442 | release_firmware(fw_priv->fw); |
| 443 | *firmware_p = NULL; | 443 | *firmware_p = NULL; |
| 444 | } | 444 | } |
| 445 | fw_priv->fw = NULL; | 445 | fw_priv->fw = NULL; |
| 446 | up(&fw_lock); | 446 | mutex_unlock(&fw_lock); |
| 447 | class_device_unregister(class_dev); | 447 | class_device_unregister(class_dev); |
| 448 | goto out; | 448 | goto out; |
| 449 | 449 | ||
diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c new file mode 100644 index 000000000000..0c85e9d6a448 --- /dev/null +++ b/drivers/base/hypervisor.c | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* | ||
| 2 | * hypervisor.c - /sys/hypervisor subsystem. | ||
| 3 | * | ||
| 4 | * This file is released under the GPLv2 | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/kobject.h> | ||
| 9 | #include <linux/device.h> | ||
| 10 | |||
| 11 | #include "base.h" | ||
| 12 | |||
| 13 | decl_subsys(hypervisor, NULL, NULL); | ||
| 14 | EXPORT_SYMBOL_GPL(hypervisor_subsys); | ||
| 15 | |||
| 16 | int __init hypervisor_init(void) | ||
| 17 | { | ||
| 18 | return subsystem_register(&hypervisor_subsys); | ||
| 19 | } | ||
diff --git a/drivers/base/init.c b/drivers/base/init.c index c648914b9cde..37138154f9e8 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c | |||
| @@ -27,6 +27,7 @@ void __init driver_init(void) | |||
| 27 | buses_init(); | 27 | buses_init(); |
| 28 | classes_init(); | 28 | classes_init(); |
| 29 | firmware_init(); | 29 | firmware_init(); |
| 30 | hypervisor_init(); | ||
| 30 | 31 | ||
| 31 | /* These are also core pieces, but must come after the | 32 | /* These are also core pieces, but must come after the |
| 32 | * core core pieces. | 33 | * core core pieces. |
diff --git a/drivers/base/isa.c b/drivers/base/isa.c new file mode 100644 index 000000000000..d2222397a401 --- /dev/null +++ b/drivers/base/isa.c | |||
| @@ -0,0 +1,180 @@ | |||
| 1 | /* | ||
| 2 | * ISA bus. | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include <linux/device.h> | ||
| 6 | #include <linux/kernel.h> | ||
| 7 | #include <linux/slab.h> | ||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/isa.h> | ||
| 11 | |||
| 12 | static struct device isa_bus = { | ||
| 13 | .bus_id = "isa" | ||
| 14 | }; | ||
| 15 | |||
| 16 | struct isa_dev { | ||
| 17 | struct device dev; | ||
| 18 | struct device *next; | ||
| 19 | unsigned int id; | ||
| 20 | }; | ||
| 21 | |||
| 22 | #define to_isa_dev(x) container_of((x), struct isa_dev, dev) | ||
| 23 | |||
| 24 | static int isa_bus_match(struct device *dev, struct device_driver *driver) | ||
| 25 | { | ||
| 26 | struct isa_driver *isa_driver = to_isa_driver(driver); | ||
| 27 | |||
| 28 | if (dev->platform_data == isa_driver) { | ||
| 29 | if (!isa_driver->match || | ||
| 30 | isa_driver->match(dev, to_isa_dev(dev)->id)) | ||
| 31 | return 1; | ||
| 32 | dev->platform_data = NULL; | ||
| 33 | } | ||
| 34 | return 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | static int isa_bus_probe(struct device *dev) | ||
| 38 | { | ||
| 39 | struct isa_driver *isa_driver = dev->platform_data; | ||
| 40 | |||
| 41 | if (isa_driver->probe) | ||
| 42 | return isa_driver->probe(dev, to_isa_dev(dev)->id); | ||
| 43 | |||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | |||
| 47 | static int isa_bus_remove(struct device *dev) | ||
| 48 | { | ||
| 49 | struct isa_driver *isa_driver = dev->platform_data; | ||
| 50 | |||
| 51 | if (isa_driver->remove) | ||
| 52 | return isa_driver->remove(dev, to_isa_dev(dev)->id); | ||
| 53 | |||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | static void isa_bus_shutdown(struct device *dev) | ||
| 58 | { | ||
| 59 | struct isa_driver *isa_driver = dev->platform_data; | ||
| 60 | |||
| 61 | if (isa_driver->shutdown) | ||
| 62 | isa_driver->shutdown(dev, to_isa_dev(dev)->id); | ||
| 63 | } | ||
| 64 | |||
| 65 | static int isa_bus_suspend(struct device *dev, pm_message_t state) | ||
| 66 | { | ||
| 67 | struct isa_driver *isa_driver = dev->platform_data; | ||
| 68 | |||
| 69 | if (isa_driver->suspend) | ||
| 70 | return isa_driver->suspend(dev, to_isa_dev(dev)->id, state); | ||
| 71 | |||
| 72 | return 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | static int isa_bus_resume(struct device *dev) | ||
| 76 | { | ||
| 77 | struct isa_driver *isa_driver = dev->platform_data; | ||
| 78 | |||
| 79 | if (isa_driver->resume) | ||
| 80 | return isa_driver->resume(dev, to_isa_dev(dev)->id); | ||
| 81 | |||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | static struct bus_type isa_bus_type = { | ||
| 86 | .name = "isa", | ||
| 87 | .match = isa_bus_match, | ||
| 88 | .probe = isa_bus_probe, | ||
| 89 | .remove = isa_bus_remove, | ||
| 90 | .shutdown = isa_bus_shutdown, | ||
| 91 | .suspend = isa_bus_suspend, | ||
| 92 | .resume = isa_bus_resume | ||
| 93 | }; | ||
| 94 | |||
| 95 | static void isa_dev_release(struct device *dev) | ||
| 96 | { | ||
| 97 | kfree(to_isa_dev(dev)); | ||
| 98 | } | ||
| 99 | |||
| 100 | void isa_unregister_driver(struct isa_driver *isa_driver) | ||
| 101 | { | ||
| 102 | struct device *dev = isa_driver->devices; | ||
| 103 | |||
| 104 | while (dev) { | ||
| 105 | struct device *tmp = to_isa_dev(dev)->next; | ||
| 106 | device_unregister(dev); | ||
| 107 | dev = tmp; | ||
| 108 | } | ||
| 109 | driver_unregister(&isa_driver->driver); | ||
| 110 | } | ||
| 111 | EXPORT_SYMBOL_GPL(isa_unregister_driver); | ||
| 112 | |||
| 113 | int isa_register_driver(struct isa_driver *isa_driver, unsigned int ndev) | ||
| 114 | { | ||
| 115 | int error; | ||
| 116 | unsigned int id; | ||
| 117 | |||
| 118 | isa_driver->driver.bus = &isa_bus_type; | ||
| 119 | isa_driver->devices = NULL; | ||
| 120 | |||
| 121 | error = driver_register(&isa_driver->driver); | ||
| 122 | if (error) | ||
| 123 | return error; | ||
| 124 | |||
| 125 | for (id = 0; id < ndev; id++) { | ||
| 126 | struct isa_dev *isa_dev; | ||
| 127 | |||
| 128 | isa_dev = kzalloc(sizeof *isa_dev, GFP_KERNEL); | ||
| 129 | if (!isa_dev) { | ||
| 130 | error = -ENOMEM; | ||
| 131 | break; | ||
| 132 | } | ||
| 133 | |||
| 134 | isa_dev->dev.parent = &isa_bus; | ||
| 135 | isa_dev->dev.bus = &isa_bus_type; | ||
| 136 | |||
| 137 | snprintf(isa_dev->dev.bus_id, BUS_ID_SIZE, "%s.%u", | ||
| 138 | isa_driver->driver.name, id); | ||
| 139 | |||
| 140 | isa_dev->dev.platform_data = isa_driver; | ||
| 141 | isa_dev->dev.release = isa_dev_release; | ||
| 142 | isa_dev->id = id; | ||
| 143 | |||
| 144 | error = device_register(&isa_dev->dev); | ||
| 145 | if (error) { | ||
| 146 | put_device(&isa_dev->dev); | ||
| 147 | break; | ||
| 148 | } | ||
| 149 | |||
| 150 | if (isa_dev->dev.platform_data) { | ||
| 151 | isa_dev->next = isa_driver->devices; | ||
| 152 | isa_driver->devices = &isa_dev->dev; | ||
| 153 | } else | ||
| 154 | device_unregister(&isa_dev->dev); | ||
| 155 | } | ||
| 156 | |||
| 157 | if (!error && !isa_driver->devices) | ||
| 158 | error = -ENODEV; | ||
| 159 | |||
| 160 | if (error) | ||
| 161 | isa_unregister_driver(isa_driver); | ||
| 162 | |||
| 163 | return error; | ||
| 164 | } | ||
| 165 | EXPORT_SYMBOL_GPL(isa_register_driver); | ||
| 166 | |||
| 167 | static int __init isa_bus_init(void) | ||
| 168 | { | ||
| 169 | int error; | ||
| 170 | |||
| 171 | error = bus_register(&isa_bus_type); | ||
| 172 | if (!error) { | ||
| 173 | error = device_register(&isa_bus); | ||
| 174 | if (error) | ||
| 175 | bus_unregister(&isa_bus_type); | ||
| 176 | } | ||
| 177 | return error; | ||
| 178 | } | ||
| 179 | |||
| 180 | device_initcall(isa_bus_init); | ||
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 83f5c5984d1a..2b8755db76c6 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
| @@ -275,7 +275,7 @@ int platform_device_add(struct platform_device *pdev) | |||
| 275 | pr_debug("Registering platform device '%s'. Parent at %s\n", | 275 | pr_debug("Registering platform device '%s'. Parent at %s\n", |
| 276 | pdev->dev.bus_id, pdev->dev.parent->bus_id); | 276 | pdev->dev.bus_id, pdev->dev.parent->bus_id); |
| 277 | 277 | ||
| 278 | ret = device_register(&pdev->dev); | 278 | ret = device_add(&pdev->dev); |
| 279 | if (ret == 0) | 279 | if (ret == 0) |
| 280 | return ret; | 280 | return ret; |
| 281 | 281 | ||
| @@ -452,6 +452,37 @@ void platform_driver_unregister(struct platform_driver *drv) | |||
| 452 | EXPORT_SYMBOL_GPL(platform_driver_unregister); | 452 | EXPORT_SYMBOL_GPL(platform_driver_unregister); |
| 453 | 453 | ||
| 454 | 454 | ||
| 455 | /* modalias support enables more hands-off userspace setup: | ||
| 456 | * (a) environment variable lets new-style hotplug events work once system is | ||
| 457 | * fully running: "modprobe $MODALIAS" | ||
| 458 | * (b) sysfs attribute lets new-style coldplug recover from hotplug events | ||
| 459 | * mishandled before system is fully running: "modprobe $(cat modalias)" | ||
| 460 | */ | ||
| 461 | static ssize_t | ||
| 462 | modalias_show(struct device *dev, struct device_attribute *a, char *buf) | ||
| 463 | { | ||
| 464 | struct platform_device *pdev = to_platform_device(dev); | ||
| 465 | int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name); | ||
| 466 | |||
| 467 | return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; | ||
| 468 | } | ||
| 469 | |||
| 470 | static struct device_attribute platform_dev_attrs[] = { | ||
| 471 | __ATTR_RO(modalias), | ||
| 472 | __ATTR_NULL, | ||
| 473 | }; | ||
| 474 | |||
| 475 | static int platform_uevent(struct device *dev, char **envp, int num_envp, | ||
| 476 | char *buffer, int buffer_size) | ||
| 477 | { | ||
| 478 | struct platform_device *pdev = to_platform_device(dev); | ||
| 479 | |||
| 480 | envp[0] = buffer; | ||
| 481 | snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name); | ||
| 482 | return 0; | ||
| 483 | } | ||
| 484 | |||
| 485 | |||
| 455 | /** | 486 | /** |
| 456 | * platform_match - bind platform device to platform driver. | 487 | * platform_match - bind platform device to platform driver. |
| 457 | * @dev: device. | 488 | * @dev: device. |
| @@ -496,7 +527,9 @@ static int platform_resume(struct device * dev) | |||
| 496 | 527 | ||
| 497 | struct bus_type platform_bus_type = { | 528 | struct bus_type platform_bus_type = { |
| 498 | .name = "platform", | 529 | .name = "platform", |
| 530 | .dev_attrs = platform_dev_attrs, | ||
| 499 | .match = platform_match, | 531 | .match = platform_match, |
| 532 | .uevent = platform_uevent, | ||
| 500 | .suspend = platform_suspend, | 533 | .suspend = platform_suspend, |
| 501 | .resume = platform_resume, | 534 | .resume = platform_resume, |
| 502 | }; | 535 | }; |
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index c0219ad94aca..ceeeba2c56c7 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile | |||
| @@ -4,3 +4,6 @@ obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o | |||
| 4 | ifeq ($(CONFIG_DEBUG_DRIVER),y) | 4 | ifeq ($(CONFIG_DEBUG_DRIVER),y) |
| 5 | EXTRA_CFLAGS += -DDEBUG | 5 | EXTRA_CFLAGS += -DDEBUG |
| 6 | endif | 6 | endif |
| 7 | ifeq ($(CONFIG_PM_DEBUG),y) | ||
| 8 | EXTRA_CFLAGS += -DDEBUG | ||
| 9 | endif | ||
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index 2a769cc6f5f9..1a1fe43a3057 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c | |||
| @@ -29,6 +29,15 @@ | |||
| 29 | * lists. This way, the ancestors will be accessed before their descendents. | 29 | * lists. This way, the ancestors will be accessed before their descendents. |
| 30 | */ | 30 | */ |
| 31 | 31 | ||
| 32 | static inline char *suspend_verb(u32 event) | ||
| 33 | { | ||
| 34 | switch (event) { | ||
| 35 | case PM_EVENT_SUSPEND: return "suspend"; | ||
| 36 | case PM_EVENT_FREEZE: return "freeze"; | ||
| 37 | default: return "(unknown suspend event)"; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 32 | 41 | ||
| 33 | /** | 42 | /** |
| 34 | * suspend_device - Save state of one device. | 43 | * suspend_device - Save state of one device. |
| @@ -57,7 +66,13 @@ int suspend_device(struct device * dev, pm_message_t state) | |||
| 57 | dev->power.prev_state = dev->power.power_state; | 66 | dev->power.prev_state = dev->power.power_state; |
| 58 | 67 | ||
| 59 | if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) { | 68 | if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) { |
| 60 | dev_dbg(dev, "suspending\n"); | 69 | dev_dbg(dev, "%s%s\n", |
| 70 | suspend_verb(state.event), | ||
| 71 | ((state.event == PM_EVENT_SUSPEND) | ||
| 72 | && device_may_wakeup(dev)) | ||
| 73 | ? ", may wakeup" | ||
| 74 | : "" | ||
| 75 | ); | ||
| 61 | error = dev->bus->suspend(dev, state); | 76 | error = dev->bus->suspend(dev, state); |
| 62 | suspend_report_result(dev->bus->suspend, error); | 77 | suspend_report_result(dev->bus->suspend, error); |
| 63 | } | 78 | } |
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 6fc23ab127bd..6858178b3aff 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
| @@ -80,10 +80,59 @@ void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a) | |||
| 80 | EXPORT_SYMBOL_GPL(sysdev_create_file); | 80 | EXPORT_SYMBOL_GPL(sysdev_create_file); |
| 81 | EXPORT_SYMBOL_GPL(sysdev_remove_file); | 81 | EXPORT_SYMBOL_GPL(sysdev_remove_file); |
| 82 | 82 | ||
| 83 | #define to_sysdev_class(k) container_of(k, struct sysdev_class, kset.kobj) | ||
| 84 | #define to_sysdev_class_attr(a) container_of(a, \ | ||
| 85 | struct sysdev_class_attribute, attr) | ||
| 86 | |||
| 87 | static ssize_t sysdev_class_show(struct kobject *kobj, struct attribute *attr, | ||
| 88 | char *buffer) | ||
| 89 | { | ||
| 90 | struct sysdev_class * class = to_sysdev_class(kobj); | ||
| 91 | struct sysdev_class_attribute *class_attr = to_sysdev_class_attr(attr); | ||
| 92 | |||
| 93 | if (class_attr->show) | ||
| 94 | return class_attr->show(class, buffer); | ||
| 95 | return -EIO; | ||
| 96 | } | ||
| 97 | |||
| 98 | static ssize_t sysdev_class_store(struct kobject *kobj, struct attribute *attr, | ||
| 99 | const char *buffer, size_t count) | ||
| 100 | { | ||
| 101 | struct sysdev_class * class = to_sysdev_class(kobj); | ||
| 102 | struct sysdev_class_attribute * class_attr = to_sysdev_class_attr(attr); | ||
| 103 | |||
| 104 | if (class_attr->store) | ||
| 105 | return class_attr->store(class, buffer, count); | ||
| 106 | return -EIO; | ||
| 107 | } | ||
| 108 | |||
| 109 | static struct sysfs_ops sysfs_class_ops = { | ||
| 110 | .show = sysdev_class_show, | ||
| 111 | .store = sysdev_class_store, | ||
| 112 | }; | ||
| 113 | |||
| 114 | static struct kobj_type ktype_sysdev_class = { | ||
| 115 | .sysfs_ops = &sysfs_class_ops, | ||
| 116 | }; | ||
| 117 | |||
| 118 | int sysdev_class_create_file(struct sysdev_class *c, | ||
| 119 | struct sysdev_class_attribute *a) | ||
| 120 | { | ||
| 121 | return sysfs_create_file(&c->kset.kobj, &a->attr); | ||
| 122 | } | ||
| 123 | EXPORT_SYMBOL_GPL(sysdev_class_create_file); | ||
| 124 | |||
| 125 | void sysdev_class_remove_file(struct sysdev_class *c, | ||
| 126 | struct sysdev_class_attribute *a) | ||
| 127 | { | ||
| 128 | sysfs_remove_file(&c->kset.kobj, &a->attr); | ||
| 129 | } | ||
| 130 | EXPORT_SYMBOL_GPL(sysdev_class_remove_file); | ||
| 131 | |||
| 83 | /* | 132 | /* |
| 84 | * declare system_subsys | 133 | * declare system_subsys |
| 85 | */ | 134 | */ |
| 86 | static decl_subsys(system, &ktype_sysdev, NULL); | 135 | static decl_subsys(system, &ktype_sysdev_class, NULL); |
| 87 | 136 | ||
| 88 | int sysdev_class_register(struct sysdev_class * cls) | 137 | int sysdev_class_register(struct sysdev_class * cls) |
| 89 | { | 138 | { |
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 1319d8f20640..25c3c4a5da81 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
| @@ -3237,6 +3237,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, | |||
| 3237 | disk->fops = &cciss_fops; | 3237 | disk->fops = &cciss_fops; |
| 3238 | disk->queue = q; | 3238 | disk->queue = q; |
| 3239 | disk->private_data = drv; | 3239 | disk->private_data = drv; |
| 3240 | disk->driverfs_dev = &pdev->dev; | ||
| 3240 | /* we must register the controller even if no disks exist */ | 3241 | /* we must register the controller even if no disks exist */ |
| 3241 | /* this is for the online array utilities */ | 3242 | /* this is for the online array utilities */ |
| 3242 | if(!drv->heads && j) | 3243 | if(!drv->heads && j) |
diff --git a/drivers/block/ub.c b/drivers/block/ub.c index c688c25992e4..60e9a9457c6b 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c | |||
| @@ -10,17 +10,13 @@ | |||
| 10 | * TODO (sorted by decreasing priority) | 10 | * TODO (sorted by decreasing priority) |
| 11 | * -- set readonly flag for CDs, set removable flag for CF readers | 11 | * -- set readonly flag for CDs, set removable flag for CF readers |
| 12 | * -- do inquiry and verify we got a disk and not a tape (for LUN mismatch) | 12 | * -- do inquiry and verify we got a disk and not a tape (for LUN mismatch) |
| 13 | * -- special case some senses, e.g. 3a/0 -> no media present, reduce retries | ||
| 14 | * -- verify the 13 conditions and do bulk resets | 13 | * -- verify the 13 conditions and do bulk resets |
| 15 | * -- kill last_pipe and simply do two-state clearing on both pipes | ||
| 16 | * -- highmem | 14 | * -- highmem |
| 17 | * -- move top_sense and work_bcs into separate allocations (if they survive) | 15 | * -- move top_sense and work_bcs into separate allocations (if they survive) |
| 18 | * for cache purists and esoteric architectures. | 16 | * for cache purists and esoteric architectures. |
| 19 | * -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ? | 17 | * -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ? |
| 20 | * -- prune comments, they are too volumnous | 18 | * -- prune comments, they are too volumnous |
| 21 | * -- Exterminate P3 printks | ||
| 22 | * -- Resove XXX's | 19 | * -- Resove XXX's |
| 23 | * -- Redo "benh's retries", perhaps have spin-up code to handle them. V:D=? | ||
| 24 | * -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring. | 20 | * -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring. |
| 25 | */ | 21 | */ |
| 26 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
| @@ -180,7 +176,6 @@ struct ub_dev; | |||
| 180 | #define UB_DIR_ILLEGAL2 2 | 176 | #define UB_DIR_ILLEGAL2 2 |
| 181 | #define UB_DIR_WRITE 3 | 177 | #define UB_DIR_WRITE 3 |
| 182 | 178 | ||
| 183 | /* P3 */ | ||
| 184 | #define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \ | 179 | #define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \ |
| 185 | (((c)==UB_DIR_READ)? 'r': 'n')) | 180 | (((c)==UB_DIR_READ)? 'r': 'n')) |
| 186 | 181 | ||
| @@ -669,8 +664,9 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) | |||
| 669 | */ | 664 | */ |
| 670 | n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]); | 665 | n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]); |
| 671 | if (n_elem < 0) { | 666 | if (n_elem < 0) { |
| 667 | /* Impossible, because blk_rq_map_sg should not hit ENOMEM. */ | ||
| 672 | printk(KERN_INFO "%s: failed request map (%d)\n", | 668 | printk(KERN_INFO "%s: failed request map (%d)\n", |
| 673 | lun->name, n_elem); /* P3 */ | 669 | lun->name, n_elem); |
| 674 | goto drop; | 670 | goto drop; |
| 675 | } | 671 | } |
| 676 | if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */ | 672 | if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */ |
| @@ -824,7 +820,9 @@ static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, | |||
| 824 | if (urq->current_try >= 3) | 820 | if (urq->current_try >= 3) |
| 825 | return -EIO; | 821 | return -EIO; |
| 826 | urq->current_try++; | 822 | urq->current_try++; |
| 827 | /* P3 */ printk("%s: dir %c len/act %d/%d " | 823 | |
| 824 | /* Remove this if anyone complains of flooding. */ | ||
| 825 | printk(KERN_DEBUG "%s: dir %c len/act %d/%d " | ||
| 828 | "[sense %x %02x %02x] retry %d\n", | 826 | "[sense %x %02x %02x] retry %d\n", |
| 829 | sc->name, UB_DIR_CHAR(cmd->dir), cmd->len, cmd->act_len, | 827 | sc->name, UB_DIR_CHAR(cmd->dir), cmd->len, cmd->act_len, |
| 830 | cmd->key, cmd->asc, cmd->ascq, urq->current_try); | 828 | cmd->key, cmd->asc, cmd->ascq, urq->current_try); |
| @@ -1241,8 +1239,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
| 1241 | * to check. But it's not all right if the device | 1239 | * to check. But it's not all right if the device |
| 1242 | * counts disagree with our counts. | 1240 | * counts disagree with our counts. |
| 1243 | */ | 1241 | */ |
| 1244 | /* P3 */ printk("%s: resid %d len %d act %d\n", | ||
| 1245 | sc->name, len, cmd->len, cmd->act_len); | ||
| 1246 | goto Bad_End; | 1242 | goto Bad_End; |
| 1247 | } | 1243 | } |
| 1248 | 1244 | ||
| @@ -1253,7 +1249,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) | |||
| 1253 | ub_state_sense(sc, cmd); | 1249 | ub_state_sense(sc, cmd); |
| 1254 | return; | 1250 | return; |
| 1255 | case US_BULK_STAT_PHASE: | 1251 | case US_BULK_STAT_PHASE: |
| 1256 | /* P3 */ printk("%s: status PHASE\n", sc->name); | ||
| 1257 | goto Bad_End; | 1252 | goto Bad_End; |
| 1258 | default: | 1253 | default: |
| 1259 | printk(KERN_INFO "%s: unknown CSW status 0x%x\n", | 1254 | printk(KERN_INFO "%s: unknown CSW status 0x%x\n", |
| @@ -1568,16 +1563,14 @@ static void ub_reset_task(void *arg) | |||
| 1568 | } | 1563 | } |
| 1569 | 1564 | ||
| 1570 | if (atomic_read(&sc->poison)) { | 1565 | if (atomic_read(&sc->poison)) { |
| 1571 | printk(KERN_NOTICE "%s: Not resetting disconnected device\n", | 1566 | ; |
| 1572 | sc->name); /* P3 This floods. Remove soon. XXX */ | ||
| 1573 | } else if ((sc->reset & 1) == 0) { | 1567 | } else if ((sc->reset & 1) == 0) { |
| 1574 | ub_sync_reset(sc); | 1568 | ub_sync_reset(sc); |
| 1575 | msleep(700); /* usb-storage sleeps 6s (!) */ | 1569 | msleep(700); /* usb-storage sleeps 6s (!) */ |
| 1576 | ub_probe_clear_stall(sc, sc->recv_bulk_pipe); | 1570 | ub_probe_clear_stall(sc, sc->recv_bulk_pipe); |
| 1577 | ub_probe_clear_stall(sc, sc->send_bulk_pipe); | 1571 | ub_probe_clear_stall(sc, sc->send_bulk_pipe); |
| 1578 | } else if (sc->dev->actconfig->desc.bNumInterfaces != 1) { | 1572 | } else if (sc->dev->actconfig->desc.bNumInterfaces != 1) { |
| 1579 | printk(KERN_NOTICE "%s: Not resetting multi-interface device\n", | 1573 | ; |
| 1580 | sc->name); /* P3 This floods. Remove soon. XXX */ | ||
| 1581 | } else { | 1574 | } else { |
| 1582 | if ((lkr = usb_lock_device_for_reset(sc->dev, sc->intf)) < 0) { | 1575 | if ((lkr = usb_lock_device_for_reset(sc->dev, sc->intf)) < 0) { |
| 1583 | printk(KERN_NOTICE | 1576 | printk(KERN_NOTICE |
| @@ -1651,15 +1644,11 @@ static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun) | |||
| 1651 | static int ub_bd_open(struct inode *inode, struct file *filp) | 1644 | static int ub_bd_open(struct inode *inode, struct file *filp) |
| 1652 | { | 1645 | { |
| 1653 | struct gendisk *disk = inode->i_bdev->bd_disk; | 1646 | struct gendisk *disk = inode->i_bdev->bd_disk; |
| 1654 | struct ub_lun *lun; | 1647 | struct ub_lun *lun = disk->private_data; |
| 1655 | struct ub_dev *sc; | 1648 | struct ub_dev *sc = lun->udev; |
| 1656 | unsigned long flags; | 1649 | unsigned long flags; |
| 1657 | int rc; | 1650 | int rc; |
| 1658 | 1651 | ||
| 1659 | if ((lun = disk->private_data) == NULL) | ||
| 1660 | return -ENXIO; | ||
| 1661 | sc = lun->udev; | ||
| 1662 | |||
| 1663 | spin_lock_irqsave(&ub_lock, flags); | 1652 | spin_lock_irqsave(&ub_lock, flags); |
| 1664 | if (atomic_read(&sc->poison)) { | 1653 | if (atomic_read(&sc->poison)) { |
| 1665 | spin_unlock_irqrestore(&ub_lock, flags); | 1654 | spin_unlock_irqrestore(&ub_lock, flags); |
| @@ -1823,10 +1812,8 @@ static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun) | |||
| 1823 | rc = ub_submit_scsi(sc, cmd); | 1812 | rc = ub_submit_scsi(sc, cmd); |
| 1824 | spin_unlock_irqrestore(sc->lock, flags); | 1813 | spin_unlock_irqrestore(sc->lock, flags); |
| 1825 | 1814 | ||
| 1826 | if (rc != 0) { | 1815 | if (rc != 0) |
| 1827 | printk("ub: testing ready: submit error (%d)\n", rc); /* P3 */ | ||
| 1828 | goto err_submit; | 1816 | goto err_submit; |
| 1829 | } | ||
| 1830 | 1817 | ||
| 1831 | wait_for_completion(&compl); | 1818 | wait_for_completion(&compl); |
| 1832 | 1819 | ||
| @@ -1884,20 +1871,16 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, | |||
| 1884 | rc = ub_submit_scsi(sc, cmd); | 1871 | rc = ub_submit_scsi(sc, cmd); |
| 1885 | spin_unlock_irqrestore(sc->lock, flags); | 1872 | spin_unlock_irqrestore(sc->lock, flags); |
| 1886 | 1873 | ||
| 1887 | if (rc != 0) { | 1874 | if (rc != 0) |
| 1888 | printk("ub: reading capacity: submit error (%d)\n", rc); /* P3 */ | ||
| 1889 | goto err_submit; | 1875 | goto err_submit; |
| 1890 | } | ||
| 1891 | 1876 | ||
| 1892 | wait_for_completion(&compl); | 1877 | wait_for_completion(&compl); |
| 1893 | 1878 | ||
| 1894 | if (cmd->error != 0) { | 1879 | if (cmd->error != 0) { |
| 1895 | printk("ub: reading capacity: error %d\n", cmd->error); /* P3 */ | ||
| 1896 | rc = -EIO; | 1880 | rc = -EIO; |
| 1897 | goto err_read; | 1881 | goto err_read; |
| 1898 | } | 1882 | } |
| 1899 | if (cmd->act_len != 8) { | 1883 | if (cmd->act_len != 8) { |
| 1900 | printk("ub: reading capacity: size %d\n", cmd->act_len); /* P3 */ | ||
| 1901 | rc = -EIO; | 1884 | rc = -EIO; |
| 1902 | goto err_read; | 1885 | goto err_read; |
| 1903 | } | 1886 | } |
| @@ -1911,7 +1894,6 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun, | |||
| 1911 | case 2048: shift = 2; break; | 1894 | case 2048: shift = 2; break; |
| 1912 | case 4096: shift = 3; break; | 1895 | case 4096: shift = 3; break; |
| 1913 | default: | 1896 | default: |
| 1914 | printk("ub: Bad sector size %u\n", bsize); /* P3 */ | ||
| 1915 | rc = -EDOM; | 1897 | rc = -EDOM; |
| 1916 | goto err_inv_bsize; | 1898 | goto err_inv_bsize; |
| 1917 | } | 1899 | } |
| @@ -2023,17 +2005,8 @@ static int ub_sync_getmaxlun(struct ub_dev *sc) | |||
| 2023 | sc->work_urb.error_count = 0; | 2005 | sc->work_urb.error_count = 0; |
| 2024 | sc->work_urb.status = 0; | 2006 | sc->work_urb.status = 0; |
| 2025 | 2007 | ||
| 2026 | if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { | 2008 | if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) |
| 2027 | if (rc == -EPIPE) { | ||
| 2028 | printk("%s: Stall submitting GetMaxLUN, using 1 LUN\n", | ||
| 2029 | sc->name); /* P3 */ | ||
| 2030 | } else { | ||
| 2031 | printk(KERN_NOTICE | ||
| 2032 | "%s: Unable to submit GetMaxLUN (%d)\n", | ||
| 2033 | sc->name, rc); | ||
| 2034 | } | ||
| 2035 | goto err_submit; | 2009 | goto err_submit; |
| 2036 | } | ||
| 2037 | 2010 | ||
| 2038 | init_timer(&timer); | 2011 | init_timer(&timer); |
| 2039 | timer.function = ub_probe_timeout; | 2012 | timer.function = ub_probe_timeout; |
| @@ -2046,21 +2019,10 @@ static int ub_sync_getmaxlun(struct ub_dev *sc) | |||
| 2046 | del_timer_sync(&timer); | 2019 | del_timer_sync(&timer); |
| 2047 | usb_kill_urb(&sc->work_urb); | 2020 | usb_kill_urb(&sc->work_urb); |
| 2048 | 2021 | ||
| 2049 | if ((rc = sc->work_urb.status) < 0) { | 2022 | if ((rc = sc->work_urb.status) < 0) |
| 2050 | if (rc == -EPIPE) { | ||
| 2051 | printk("%s: Stall at GetMaxLUN, using 1 LUN\n", | ||
| 2052 | sc->name); /* P3 */ | ||
| 2053 | } else { | ||
| 2054 | printk(KERN_NOTICE | ||
| 2055 | "%s: Error at GetMaxLUN (%d)\n", | ||
| 2056 | sc->name, rc); | ||
| 2057 | } | ||
| 2058 | goto err_io; | 2023 | goto err_io; |
| 2059 | } | ||
| 2060 | 2024 | ||
| 2061 | if (sc->work_urb.actual_length != 1) { | 2025 | if (sc->work_urb.actual_length != 1) { |
| 2062 | printk("%s: GetMaxLUN returned %d bytes\n", sc->name, | ||
| 2063 | sc->work_urb.actual_length); /* P3 */ | ||
| 2064 | nluns = 0; | 2026 | nluns = 0; |
| 2065 | } else { | 2027 | } else { |
| 2066 | if ((nluns = *p) == 55) { | 2028 | if ((nluns = *p) == 55) { |
| @@ -2071,8 +2033,6 @@ static int ub_sync_getmaxlun(struct ub_dev *sc) | |||
| 2071 | if (nluns > UB_MAX_LUNS) | 2033 | if (nluns > UB_MAX_LUNS) |
| 2072 | nluns = UB_MAX_LUNS; | 2034 | nluns = UB_MAX_LUNS; |
| 2073 | } | 2035 | } |
| 2074 | printk("%s: GetMaxLUN returned %d, using %d LUNs\n", sc->name, | ||
| 2075 | *p, nluns); /* P3 */ | ||
| 2076 | } | 2036 | } |
| 2077 | 2037 | ||
| 2078 | kfree(p); | 2038 | kfree(p); |
| @@ -2270,7 +2230,7 @@ static int ub_probe(struct usb_interface *intf, | |||
| 2270 | * has to succeed, so we clear checks with an additional one here. | 2230 | * has to succeed, so we clear checks with an additional one here. |
| 2271 | * In any case it's not our business how revaliadation is implemented. | 2231 | * In any case it's not our business how revaliadation is implemented. |
| 2272 | */ | 2232 | */ |
| 2273 | for (i = 0; i < 3; i++) { /* Retries for benh's key */ | 2233 | for (i = 0; i < 3; i++) { /* Retries for the schwag key from KS'04 */ |
| 2274 | if ((rc = ub_sync_tur(sc, NULL)) <= 0) break; | 2234 | if ((rc = ub_sync_tur(sc, NULL)) <= 0) break; |
| 2275 | if (rc != 0x6) break; | 2235 | if (rc != 0x6) break; |
| 2276 | msleep(10); | 2236 | msleep(10); |
| @@ -2318,7 +2278,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) | |||
| 2318 | goto err_id; | 2278 | goto err_id; |
| 2319 | 2279 | ||
| 2320 | lun->udev = sc; | 2280 | lun->udev = sc; |
| 2321 | list_add(&lun->link, &sc->luns); | ||
| 2322 | 2281 | ||
| 2323 | snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)", | 2282 | snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)", |
| 2324 | lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num); | 2283 | lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num); |
| @@ -2331,7 +2290,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) | |||
| 2331 | if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL) | 2290 | if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL) |
| 2332 | goto err_diskalloc; | 2291 | goto err_diskalloc; |
| 2333 | 2292 | ||
| 2334 | lun->disk = disk; | ||
| 2335 | sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a'); | 2293 | sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a'); |
| 2336 | sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a'); | 2294 | sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a'); |
| 2337 | disk->major = UB_MAJOR; | 2295 | disk->major = UB_MAJOR; |
| @@ -2353,7 +2311,9 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) | |||
| 2353 | blk_queue_max_sectors(q, UB_MAX_SECTORS); | 2311 | blk_queue_max_sectors(q, UB_MAX_SECTORS); |
| 2354 | blk_queue_hardsect_size(q, lun->capacity.bsize); | 2312 | blk_queue_hardsect_size(q, lun->capacity.bsize); |
| 2355 | 2313 | ||
| 2314 | lun->disk = disk; | ||
| 2356 | q->queuedata = lun; | 2315 | q->queuedata = lun; |
| 2316 | list_add(&lun->link, &sc->luns); | ||
| 2357 | 2317 | ||
| 2358 | set_capacity(disk, lun->capacity.nsec); | 2318 | set_capacity(disk, lun->capacity.nsec); |
| 2359 | if (lun->removable) | 2319 | if (lun->removable) |
| @@ -2366,7 +2326,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) | |||
| 2366 | err_blkqinit: | 2326 | err_blkqinit: |
| 2367 | put_disk(disk); | 2327 | put_disk(disk); |
| 2368 | err_diskalloc: | 2328 | err_diskalloc: |
| 2369 | list_del(&lun->link); | ||
| 2370 | ub_id_put(lun->id); | 2329 | ub_id_put(lun->id); |
| 2371 | err_id: | 2330 | err_id: |
| 2372 | kfree(lun); | 2331 | kfree(lun); |
| @@ -2379,7 +2338,6 @@ static void ub_disconnect(struct usb_interface *intf) | |||
| 2379 | struct ub_dev *sc = usb_get_intfdata(intf); | 2338 | struct ub_dev *sc = usb_get_intfdata(intf); |
| 2380 | struct list_head *p; | 2339 | struct list_head *p; |
| 2381 | struct ub_lun *lun; | 2340 | struct ub_lun *lun; |
| 2382 | struct gendisk *disk; | ||
| 2383 | unsigned long flags; | 2341 | unsigned long flags; |
| 2384 | 2342 | ||
| 2385 | /* | 2343 | /* |
| @@ -2435,9 +2393,7 @@ static void ub_disconnect(struct usb_interface *intf) | |||
| 2435 | */ | 2393 | */ |
| 2436 | list_for_each (p, &sc->luns) { | 2394 | list_for_each (p, &sc->luns) { |
| 2437 | lun = list_entry(p, struct ub_lun, link); | 2395 | lun = list_entry(p, struct ub_lun, link); |
| 2438 | disk = lun->disk; | 2396 | del_gendisk(lun->disk); |
| 2439 | if (disk->flags & GENHD_FL_UP) | ||
| 2440 | del_gendisk(disk); | ||
| 2441 | /* | 2397 | /* |
| 2442 | * I wish I could do: | 2398 | * I wish I could do: |
| 2443 | * set_bit(QUEUE_FLAG_DEAD, &q->queue_flags); | 2399 | * set_bit(QUEUE_FLAG_DEAD, &q->queue_flags); |
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 7c88c060a9e6..46685a540772 100644 --- a/drivers/char/agp/Kconfig +++ b/drivers/char/agp/Kconfig | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | config AGP | 1 | config AGP |
| 2 | tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU | 2 | tristate "/dev/agpgart (AGP Support)" |
| 3 | depends on ALPHA || IA64 || PPC || X86 | 3 | depends on ALPHA || IA64 || PPC || X86 |
| 4 | default y if GART_IOMMU | ||
| 5 | ---help--- | 4 | ---help--- |
| 6 | AGP (Accelerated Graphics Port) is a bus system mainly used to | 5 | AGP (Accelerated Graphics Port) is a bus system mainly used to |
| 7 | connect graphics cards to the rest of the system. | 6 | connect graphics cards to the rest of the system. |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index a88b94a82b14..8b2a59969868 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
| @@ -2961,12 +2961,14 @@ static struct class *tty_class; | |||
| 2961 | * This field is optional, if there is no known struct device for this | 2961 | * This field is optional, if there is no known struct device for this |
| 2962 | * tty device it can be set to NULL safely. | 2962 | * tty device it can be set to NULL safely. |
| 2963 | * | 2963 | * |
| 2964 | * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error). | ||
| 2965 | * | ||
| 2964 | * This call is required to be made to register an individual tty device if | 2966 | * This call is required to be made to register an individual tty device if |
| 2965 | * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set. If that | 2967 | * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set. If that |
| 2966 | * bit is not set, this function should not be called. | 2968 | * bit is not set, this function should not be called. |
| 2967 | */ | 2969 | */ |
| 2968 | void tty_register_device(struct tty_driver *driver, unsigned index, | 2970 | struct class_device *tty_register_device(struct tty_driver *driver, |
| 2969 | struct device *device) | 2971 | unsigned index, struct device *device) |
| 2970 | { | 2972 | { |
| 2971 | char name[64]; | 2973 | char name[64]; |
| 2972 | dev_t dev = MKDEV(driver->major, driver->minor_start) + index; | 2974 | dev_t dev = MKDEV(driver->major, driver->minor_start) + index; |
| @@ -2974,7 +2976,7 @@ void tty_register_device(struct tty_driver *driver, unsigned index, | |||
| 2974 | if (index >= driver->num) { | 2976 | if (index >= driver->num) { |
| 2975 | printk(KERN_ERR "Attempt to register invalid tty line number " | 2977 | printk(KERN_ERR "Attempt to register invalid tty line number " |
| 2976 | " (%d).\n", index); | 2978 | " (%d).\n", index); |
| 2977 | return; | 2979 | return ERR_PTR(-EINVAL); |
| 2978 | } | 2980 | } |
| 2979 | 2981 | ||
| 2980 | devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, | 2982 | devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, |
| @@ -2984,7 +2986,8 @@ void tty_register_device(struct tty_driver *driver, unsigned index, | |||
| 2984 | pty_line_name(driver, index, name); | 2986 | pty_line_name(driver, index, name); |
| 2985 | else | 2987 | else |
| 2986 | tty_line_name(driver, index, name); | 2988 | tty_line_name(driver, index, name); |
| 2987 | class_device_create(tty_class, NULL, dev, device, "%s", name); | 2989 | |
| 2990 | return class_device_create(tty_class, NULL, dev, device, "%s", name); | ||
| 2988 | } | 2991 | } |
| 2989 | 2992 | ||
| 2990 | /** | 2993 | /** |
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index e55767b2ccd3..acb7e2656780 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c | |||
| @@ -460,6 +460,9 @@ void gigaset_freecs(struct cardstate *cs) | |||
| 460 | 460 | ||
| 461 | switch (cs->cs_init) { | 461 | switch (cs->cs_init) { |
| 462 | default: | 462 | default: |
| 463 | /* clear device sysfs */ | ||
| 464 | gigaset_free_dev_sysfs(cs); | ||
| 465 | |||
| 463 | gigaset_if_free(cs); | 466 | gigaset_if_free(cs); |
| 464 | 467 | ||
| 465 | gig_dbg(DEBUG_INIT, "clearing hw"); | 468 | gig_dbg(DEBUG_INIT, "clearing hw"); |
| @@ -699,6 +702,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
| 699 | cs->open_count = 0; | 702 | cs->open_count = 0; |
| 700 | cs->dev = NULL; | 703 | cs->dev = NULL; |
| 701 | cs->tty = NULL; | 704 | cs->tty = NULL; |
| 705 | cs->class = NULL; | ||
| 702 | cs->cidmode = cidmode != 0; | 706 | cs->cidmode = cidmode != 0; |
| 703 | 707 | ||
| 704 | //if(onechannel) { //FIXME | 708 | //if(onechannel) { //FIXME |
| @@ -760,6 +764,9 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
| 760 | 764 | ||
| 761 | gigaset_if_init(cs); | 765 | gigaset_if_init(cs); |
| 762 | 766 | ||
| 767 | /* set up device sysfs */ | ||
| 768 | gigaset_init_dev_sysfs(cs); | ||
| 769 | |||
| 763 | spin_lock_irqsave(&cs->lock, flags); | 770 | spin_lock_irqsave(&cs->lock, flags); |
| 764 | cs->running = 1; | 771 | cs->running = 1; |
| 765 | spin_unlock_irqrestore(&cs->lock, flags); | 772 | spin_unlock_irqrestore(&cs->lock, flags); |
| @@ -902,9 +909,6 @@ int gigaset_start(struct cardstate *cs) | |||
| 902 | 909 | ||
| 903 | wait_event(cs->waitqueue, !cs->waiting); | 910 | wait_event(cs->waitqueue, !cs->waiting); |
| 904 | 911 | ||
| 905 | /* set up device sysfs */ | ||
| 906 | gigaset_init_dev_sysfs(cs); | ||
| 907 | |||
| 908 | mutex_unlock(&cs->mutex); | 912 | mutex_unlock(&cs->mutex); |
| 909 | return 1; | 913 | return 1; |
| 910 | 914 | ||
| @@ -969,9 +973,6 @@ void gigaset_stop(struct cardstate *cs) | |||
| 969 | //FIXME | 973 | //FIXME |
| 970 | } | 974 | } |
| 971 | 975 | ||
| 972 | /* clear device sysfs */ | ||
| 973 | gigaset_free_dev_sysfs(cs); | ||
| 974 | |||
| 975 | cleanup_cs(cs); | 976 | cleanup_cs(cs); |
| 976 | 977 | ||
| 977 | exit: | 978 | exit: |
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 22b9693f7c0a..8d63d822104f 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h | |||
| @@ -445,6 +445,7 @@ struct cardstate { | |||
| 445 | struct gigaset_driver *driver; | 445 | struct gigaset_driver *driver; |
| 446 | unsigned minor_index; | 446 | unsigned minor_index; |
| 447 | struct device *dev; | 447 | struct device *dev; |
| 448 | struct class_device *class; | ||
| 448 | 449 | ||
| 449 | const struct gigaset_ops *ops; | 450 | const struct gigaset_ops *ops; |
| 450 | 451 | ||
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 08e4c4eea14d..74fd234956c8 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c | |||
| @@ -625,7 +625,14 @@ void gigaset_if_init(struct cardstate *cs) | |||
| 625 | return; | 625 | return; |
| 626 | 626 | ||
| 627 | tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs); | 627 | tasklet_init(&cs->if_wake_tasklet, &if_wake, (unsigned long) cs); |
| 628 | tty_register_device(drv->tty, cs->minor_index, NULL); | 628 | cs->class = tty_register_device(drv->tty, cs->minor_index, NULL); |
| 629 | |||
| 630 | if (!IS_ERR(cs->class)) | ||
| 631 | class_set_devdata(cs->class, cs); | ||
| 632 | else { | ||
| 633 | warn("could not register device to the tty subsystem"); | ||
| 634 | cs->class = NULL; | ||
| 635 | } | ||
| 629 | } | 636 | } |
| 630 | 637 | ||
| 631 | void gigaset_if_free(struct cardstate *cs) | 638 | void gigaset_if_free(struct cardstate *cs) |
| @@ -638,6 +645,7 @@ void gigaset_if_free(struct cardstate *cs) | |||
| 638 | 645 | ||
| 639 | tasklet_disable(&cs->if_wake_tasklet); | 646 | tasklet_disable(&cs->if_wake_tasklet); |
| 640 | tasklet_kill(&cs->if_wake_tasklet); | 647 | tasklet_kill(&cs->if_wake_tasklet); |
| 648 | cs->class = NULL; | ||
| 641 | tty_unregister_device(drv->tty, cs->minor_index); | 649 | tty_unregister_device(drv->tty, cs->minor_index); |
| 642 | } | 650 | } |
| 643 | 651 | ||
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c index d267a636b53c..9ae3a7f3e7b3 100644 --- a/drivers/isdn/gigaset/proc.c +++ b/drivers/isdn/gigaset/proc.c | |||
| @@ -16,12 +16,11 @@ | |||
| 16 | #include "gigaset.h" | 16 | #include "gigaset.h" |
| 17 | #include <linux/ctype.h> | 17 | #include <linux/ctype.h> |
| 18 | 18 | ||
| 19 | static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, | 19 | static ssize_t show_cidmode(struct class_device *class, char *buf) |
| 20 | char *buf) | ||
| 21 | { | 20 | { |
| 22 | int ret; | 21 | int ret; |
| 23 | unsigned long flags; | 22 | unsigned long flags; |
| 24 | struct cardstate *cs = dev_get_drvdata(dev); | 23 | struct cardstate *cs = class_get_devdata(class); |
| 25 | 24 | ||
| 26 | spin_lock_irqsave(&cs->lock, flags); | 25 | spin_lock_irqsave(&cs->lock, flags); |
| 27 | ret = sprintf(buf, "%u\n", cs->cidmode); | 26 | ret = sprintf(buf, "%u\n", cs->cidmode); |
| @@ -30,10 +29,10 @@ static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, | |||
| 30 | return ret; | 29 | return ret; |
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, | 32 | static ssize_t set_cidmode(struct class_device *class, |
| 34 | const char *buf, size_t count) | 33 | const char *buf, size_t count) |
| 35 | { | 34 | { |
| 36 | struct cardstate *cs = dev_get_drvdata(dev); | 35 | struct cardstate *cs = class_get_devdata(class); |
| 37 | long int value; | 36 | long int value; |
| 38 | char *end; | 37 | char *end; |
| 39 | 38 | ||
| @@ -65,18 +64,24 @@ static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, | |||
| 65 | return count; | 64 | return count; |
| 66 | } | 65 | } |
| 67 | 66 | ||
| 68 | static DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode); | 67 | static CLASS_DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode); |
| 69 | 68 | ||
| 70 | /* free sysfs for device */ | 69 | /* free sysfs for device */ |
| 71 | void gigaset_free_dev_sysfs(struct cardstate *cs) | 70 | void gigaset_free_dev_sysfs(struct cardstate *cs) |
| 72 | { | 71 | { |
| 72 | if (!cs->class) | ||
| 73 | return; | ||
| 74 | |||
| 73 | gig_dbg(DEBUG_INIT, "removing sysfs entries"); | 75 | gig_dbg(DEBUG_INIT, "removing sysfs entries"); |
| 74 | device_remove_file(cs->dev, &dev_attr_cidmode); | 76 | class_device_remove_file(cs->class, &class_device_attr_cidmode); |
| 75 | } | 77 | } |
| 76 | 78 | ||
| 77 | /* initialize sysfs for device */ | 79 | /* initialize sysfs for device */ |
| 78 | void gigaset_init_dev_sysfs(struct cardstate *cs) | 80 | void gigaset_init_dev_sysfs(struct cardstate *cs) |
| 79 | { | 81 | { |
| 82 | if (!cs->class) | ||
| 83 | return; | ||
| 84 | |||
| 80 | gig_dbg(DEBUG_INIT, "setting up sysfs"); | 85 | gig_dbg(DEBUG_INIT, "setting up sysfs"); |
| 81 | device_create_file(cs->dev, &dev_attr_cidmode); | 86 | class_device_create_file(cs->class, &class_device_attr_cidmode); |
| 82 | } | 87 | } |
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c index c11f5d46b114..6f31ecc88843 100644 --- a/drivers/media/video/usbvideo/konicawc.c +++ b/drivers/media/video/usbvideo/konicawc.c | |||
| @@ -15,8 +15,7 @@ | |||
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
| 18 | #include <linux/input.h> | 18 | #include <linux/usb/input.h> |
| 19 | #include <linux/usb_input.h> | ||
| 20 | 19 | ||
| 21 | #include "usbvideo.h" | 20 | #include "usbvideo.h" |
| 22 | 21 | ||
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index e1feb58bd661..1a2b9785e998 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c | |||
| @@ -2120,7 +2120,7 @@ abort_linearize: | |||
| 2120 | goto drop; | 2120 | goto drop; |
| 2121 | } | 2121 | } |
| 2122 | 2122 | ||
| 2123 | if (skb_linearize(skb, GFP_ATOMIC)) | 2123 | if (skb_linearize(skb)) |
| 2124 | goto drop; | 2124 | goto drop; |
| 2125 | 2125 | ||
| 2126 | mgp->tx_linearized++; | 2126 | mgp->tx_linearized++; |
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 9b7d9769fdcc..c7123bf71c58 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile | |||
| @@ -48,6 +48,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/ | |||
| 48 | obj-$(CONFIG_USB_SERIAL) += serial/ | 48 | obj-$(CONFIG_USB_SERIAL) += serial/ |
| 49 | 49 | ||
| 50 | obj-$(CONFIG_USB_AUERSWALD) += misc/ | 50 | obj-$(CONFIG_USB_AUERSWALD) += misc/ |
| 51 | obj-$(CONFIG_USB_CY7C63) += misc/ | ||
| 51 | obj-$(CONFIG_USB_CYTHERM) += misc/ | 52 | obj-$(CONFIG_USB_CYTHERM) += misc/ |
| 52 | obj-$(CONFIG_USB_EMI26) += misc/ | 53 | obj-$(CONFIG_USB_EMI26) += misc/ |
| 53 | obj-$(CONFIG_USB_EMI62) += misc/ | 54 | obj-$(CONFIG_USB_EMI62) += misc/ |
| @@ -61,6 +62,7 @@ obj-$(CONFIG_USB_TEST) += misc/ | |||
| 61 | obj-$(CONFIG_USB_USS720) += misc/ | 62 | obj-$(CONFIG_USB_USS720) += misc/ |
| 62 | obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ | 63 | obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ |
| 63 | obj-$(CONFIG_USB_SISUSBVGA) += misc/ | 64 | obj-$(CONFIG_USB_SISUSBVGA) += misc/ |
| 65 | obj-$(CONFIG_USB_APPLEDISPLAY) += misc/ | ||
| 64 | 66 | ||
| 65 | obj-$(CONFIG_USB_ATM) += atm/ | 67 | obj-$(CONFIG_USB_ATM) += atm/ |
| 66 | obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ | 68 | obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ |
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 546249843b8e..a38701c742c3 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c | |||
| @@ -1039,7 +1039,7 @@ static void usbatm_tasklet_schedule(unsigned long data) | |||
| 1039 | tasklet_schedule((struct tasklet_struct *) data); | 1039 | tasklet_schedule((struct tasklet_struct *) data); |
| 1040 | } | 1040 | } |
| 1041 | 1041 | ||
| 1042 | static inline void usbatm_init_channel(struct usbatm_channel *channel) | 1042 | static void usbatm_init_channel(struct usbatm_channel *channel) |
| 1043 | { | 1043 | { |
| 1044 | spin_lock_init(&channel->lock); | 1044 | spin_lock_init(&channel->lock); |
| 1045 | INIT_LIST_HEAD(&channel->list); | 1045 | INIT_LIST_HEAD(&channel->list); |
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c index 42d6823b82b3..70125c6d3be4 100644 --- a/drivers/usb/atm/xusbatm.c +++ b/drivers/usb/atm/xusbatm.c | |||
| @@ -20,7 +20,6 @@ | |||
| 20 | ******************************************************************************/ | 20 | ******************************************************************************/ |
| 21 | 21 | ||
| 22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 23 | #include <linux/netdevice.h> /* FIXME: required by linux/etherdevice.h */ | ||
| 24 | #include <linux/etherdevice.h> /* for random_ether_addr() */ | 23 | #include <linux/etherdevice.h> /* for random_ether_addr() */ |
| 25 | 24 | ||
| 26 | #include "usbatm.h" | 25 | #include "usbatm.h" |
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 6dd339f4c0fc..d41dc67ba4cc 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -63,7 +63,7 @@ | |||
| 63 | #include <linux/mutex.h> | 63 | #include <linux/mutex.h> |
| 64 | #include <asm/uaccess.h> | 64 | #include <asm/uaccess.h> |
| 65 | #include <linux/usb.h> | 65 | #include <linux/usb.h> |
| 66 | #include <linux/usb_cdc.h> | 66 | #include <linux/usb/cdc.h> |
| 67 | #include <asm/byteorder.h> | 67 | #include <asm/byteorder.h> |
| 68 | #include <asm/unaligned.h> | 68 | #include <asm/unaligned.h> |
| 69 | #include <linux/list.h> | 69 | #include <linux/list.h> |
| @@ -127,8 +127,8 @@ static int acm_wb_alloc(struct acm *acm) | |||
| 127 | wb->use = 1; | 127 | wb->use = 1; |
| 128 | return wbn; | 128 | return wbn; |
| 129 | } | 129 | } |
| 130 | wbn = (wbn + 1) % ACM_NWB; | 130 | wbn = (wbn + 1) % ACM_NW; |
| 131 | if (++i >= ACM_NWB) | 131 | if (++i >= ACM_NW) |
| 132 | return -1; | 132 | return -1; |
| 133 | } | 133 | } |
| 134 | } | 134 | } |
| @@ -142,10 +142,9 @@ static int acm_wb_is_avail(struct acm *acm) | |||
| 142 | { | 142 | { |
| 143 | int i, n; | 143 | int i, n; |
| 144 | 144 | ||
| 145 | n = 0; | 145 | n = ACM_NW; |
| 146 | for (i = 0; i < ACM_NWB; i++) { | 146 | for (i = 0; i < ACM_NW; i++) { |
| 147 | if (!acm->wb[i].use) | 147 | n -= acm->wb[i].use; |
| 148 | n++; | ||
| 149 | } | 148 | } |
| 150 | return n; | 149 | return n; |
| 151 | } | 150 | } |
| @@ -167,7 +166,7 @@ static void acm_write_done(struct acm *acm) | |||
| 167 | acm->write_ready = 1; | 166 | acm->write_ready = 1; |
| 168 | wbn = acm->write_current; | 167 | wbn = acm->write_current; |
| 169 | acm_wb_free(acm, wbn); | 168 | acm_wb_free(acm, wbn); |
| 170 | acm->write_current = (wbn + 1) % ACM_NWB; | 169 | acm->write_current = (wbn + 1) % ACM_NW; |
| 171 | spin_unlock_irqrestore(&acm->write_lock, flags); | 170 | spin_unlock_irqrestore(&acm->write_lock, flags); |
| 172 | } | 171 | } |
| 173 | 172 | ||
| @@ -291,22 +290,32 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs) | |||
| 291 | struct acm_rb *buf; | 290 | struct acm_rb *buf; |
| 292 | struct acm_ru *rcv = urb->context; | 291 | struct acm_ru *rcv = urb->context; |
| 293 | struct acm *acm = rcv->instance; | 292 | struct acm *acm = rcv->instance; |
| 293 | int status = urb->status; | ||
| 294 | dbg("Entering acm_read_bulk with status %d\n", urb->status); | 294 | dbg("Entering acm_read_bulk with status %d\n", urb->status); |
| 295 | 295 | ||
| 296 | if (!ACM_READY(acm)) | 296 | if (!ACM_READY(acm)) |
| 297 | return; | 297 | return; |
| 298 | 298 | ||
| 299 | if (urb->status) | 299 | if (status) |
| 300 | dev_dbg(&acm->data->dev, "bulk rx status %d\n", urb->status); | 300 | dev_dbg(&acm->data->dev, "bulk rx status %d\n", status); |
| 301 | 301 | ||
| 302 | buf = rcv->buffer; | 302 | buf = rcv->buffer; |
| 303 | buf->size = urb->actual_length; | 303 | buf->size = urb->actual_length; |
| 304 | 304 | ||
| 305 | spin_lock(&acm->read_lock); | 305 | if (likely(status == 0)) { |
| 306 | list_add_tail(&rcv->list, &acm->spare_read_urbs); | 306 | spin_lock(&acm->read_lock); |
| 307 | list_add_tail(&buf->list, &acm->filled_read_bufs); | 307 | list_add_tail(&rcv->list, &acm->spare_read_urbs); |
| 308 | spin_unlock(&acm->read_lock); | 308 | list_add_tail(&buf->list, &acm->filled_read_bufs); |
| 309 | 309 | spin_unlock(&acm->read_lock); | |
| 310 | } else { | ||
| 311 | /* we drop the buffer due to an error */ | ||
| 312 | spin_lock(&acm->read_lock); | ||
| 313 | list_add_tail(&rcv->list, &acm->spare_read_urbs); | ||
| 314 | list_add(&buf->list, &acm->spare_read_bufs); | ||
| 315 | spin_unlock(&acm->read_lock); | ||
| 316 | /* nevertheless the tasklet must be kicked unconditionally | ||
| 317 | so the queue cannot dry up */ | ||
| 318 | } | ||
| 310 | tasklet_schedule(&acm->urb_task); | 319 | tasklet_schedule(&acm->urb_task); |
| 311 | } | 320 | } |
| 312 | 321 | ||
| @@ -464,10 +473,10 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) | |||
| 464 | INIT_LIST_HEAD(&acm->spare_read_urbs); | 473 | INIT_LIST_HEAD(&acm->spare_read_urbs); |
| 465 | INIT_LIST_HEAD(&acm->spare_read_bufs); | 474 | INIT_LIST_HEAD(&acm->spare_read_bufs); |
| 466 | INIT_LIST_HEAD(&acm->filled_read_bufs); | 475 | INIT_LIST_HEAD(&acm->filled_read_bufs); |
| 467 | for (i = 0; i < ACM_NRU; i++) { | 476 | for (i = 0; i < acm->rx_buflimit; i++) { |
| 468 | list_add(&(acm->ru[i].list), &acm->spare_read_urbs); | 477 | list_add(&(acm->ru[i].list), &acm->spare_read_urbs); |
| 469 | } | 478 | } |
| 470 | for (i = 0; i < ACM_NRB; i++) { | 479 | for (i = 0; i < acm->rx_buflimit; i++) { |
| 471 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); | 480 | list_add(&(acm->rb[i].list), &acm->spare_read_bufs); |
| 472 | } | 481 | } |
| 473 | 482 | ||
| @@ -488,14 +497,15 @@ bail_out: | |||
| 488 | 497 | ||
| 489 | static void acm_tty_unregister(struct acm *acm) | 498 | static void acm_tty_unregister(struct acm *acm) |
| 490 | { | 499 | { |
| 491 | int i; | 500 | int i,nr; |
| 492 | 501 | ||
| 502 | nr = acm->rx_buflimit; | ||
| 493 | tty_unregister_device(acm_tty_driver, acm->minor); | 503 | tty_unregister_device(acm_tty_driver, acm->minor); |
| 494 | usb_put_intf(acm->control); | 504 | usb_put_intf(acm->control); |
| 495 | acm_table[acm->minor] = NULL; | 505 | acm_table[acm->minor] = NULL; |
| 496 | usb_free_urb(acm->ctrlurb); | 506 | usb_free_urb(acm->ctrlurb); |
| 497 | usb_free_urb(acm->writeurb); | 507 | usb_free_urb(acm->writeurb); |
| 498 | for (i = 0; i < ACM_NRU; i++) | 508 | for (i = 0; i < nr; i++) |
| 499 | usb_free_urb(acm->ru[i].urb); | 509 | usb_free_urb(acm->ru[i].urb); |
| 500 | kfree(acm); | 510 | kfree(acm); |
| 501 | } | 511 | } |
| @@ -503,18 +513,19 @@ static void acm_tty_unregister(struct acm *acm) | |||
| 503 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) | 513 | static void acm_tty_close(struct tty_struct *tty, struct file *filp) |
| 504 | { | 514 | { |
| 505 | struct acm *acm = tty->driver_data; | 515 | struct acm *acm = tty->driver_data; |
| 506 | int i; | 516 | int i,nr; |
| 507 | 517 | ||
| 508 | if (!acm || !acm->used) | 518 | if (!acm || !acm->used) |
| 509 | return; | 519 | return; |
| 510 | 520 | ||
| 521 | nr = acm->rx_buflimit; | ||
| 511 | mutex_lock(&open_mutex); | 522 | mutex_lock(&open_mutex); |
| 512 | if (!--acm->used) { | 523 | if (!--acm->used) { |
| 513 | if (acm->dev) { | 524 | if (acm->dev) { |
| 514 | acm_set_control(acm, acm->ctrlout = 0); | 525 | acm_set_control(acm, acm->ctrlout = 0); |
| 515 | usb_kill_urb(acm->ctrlurb); | 526 | usb_kill_urb(acm->ctrlurb); |
| 516 | usb_kill_urb(acm->writeurb); | 527 | usb_kill_urb(acm->writeurb); |
| 517 | for (i = 0; i < ACM_NRU; i++) | 528 | for (i = 0; i < nr; i++) |
| 518 | usb_kill_urb(acm->ru[i].urb); | 529 | usb_kill_urb(acm->ru[i].urb); |
| 519 | } else | 530 | } else |
| 520 | acm_tty_unregister(acm); | 531 | acm_tty_unregister(acm); |
| @@ -576,7 +587,7 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty) | |||
| 576 | /* | 587 | /* |
| 577 | * This is inaccurate (overcounts), but it works. | 588 | * This is inaccurate (overcounts), but it works. |
| 578 | */ | 589 | */ |
| 579 | return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize; | 590 | return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize; |
| 580 | } | 591 | } |
| 581 | 592 | ||
| 582 | static void acm_tty_throttle(struct tty_struct *tty) | 593 | static void acm_tty_throttle(struct tty_struct *tty) |
| @@ -712,7 +723,7 @@ static void acm_write_buffers_free(struct acm *acm) | |||
| 712 | int i; | 723 | int i; |
| 713 | struct acm_wb *wb; | 724 | struct acm_wb *wb; |
| 714 | 725 | ||
| 715 | for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) { | 726 | for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { |
| 716 | usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah); | 727 | usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah); |
| 717 | } | 728 | } |
| 718 | } | 729 | } |
| @@ -723,7 +734,7 @@ static int acm_write_buffers_alloc(struct acm *acm) | |||
| 723 | int i; | 734 | int i; |
| 724 | struct acm_wb *wb; | 735 | struct acm_wb *wb; |
| 725 | 736 | ||
| 726 | for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) { | 737 | for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { |
| 727 | wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL, | 738 | wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL, |
| 728 | &wb->dmah); | 739 | &wb->dmah); |
| 729 | if (!wb->buf) { | 740 | if (!wb->buf) { |
| @@ -760,10 +771,14 @@ static int acm_probe (struct usb_interface *intf, | |||
| 760 | int call_interface_num = -1; | 771 | int call_interface_num = -1; |
| 761 | int data_interface_num; | 772 | int data_interface_num; |
| 762 | unsigned long quirks; | 773 | unsigned long quirks; |
| 774 | int num_rx_buf; | ||
| 763 | int i; | 775 | int i; |
| 764 | 776 | ||
| 765 | /* handle quirks deadly to normal probing*/ | 777 | /* normal quirks */ |
| 766 | quirks = (unsigned long)id->driver_info; | 778 | quirks = (unsigned long)id->driver_info; |
| 779 | num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; | ||
| 780 | |||
| 781 | /* handle quirks deadly to normal probing*/ | ||
| 767 | if (quirks == NO_UNION_NORMAL) { | 782 | if (quirks == NO_UNION_NORMAL) { |
| 768 | data_interface = usb_ifnum_to_if(usb_dev, 1); | 783 | data_interface = usb_ifnum_to_if(usb_dev, 1); |
| 769 | control_interface = usb_ifnum_to_if(usb_dev, 0); | 784 | control_interface = usb_ifnum_to_if(usb_dev, 0); |
| @@ -900,7 +915,7 @@ skip_normal_probe: | |||
| 900 | } | 915 | } |
| 901 | 916 | ||
| 902 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); | 917 | ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize); |
| 903 | readsize = le16_to_cpu(epread->wMaxPacketSize)*2; | 918 | readsize = le16_to_cpu(epread->wMaxPacketSize)* ( quirks == SINGLE_RX_URB ? 1 : 2); |
| 904 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); | 919 | acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize); |
| 905 | acm->control = control_interface; | 920 | acm->control = control_interface; |
| 906 | acm->data = data_interface; | 921 | acm->data = data_interface; |
| @@ -909,6 +924,7 @@ skip_normal_probe: | |||
| 909 | acm->ctrl_caps = ac_management_function; | 924 | acm->ctrl_caps = ac_management_function; |
| 910 | acm->ctrlsize = ctrlsize; | 925 | acm->ctrlsize = ctrlsize; |
| 911 | acm->readsize = readsize; | 926 | acm->readsize = readsize; |
| 927 | acm->rx_buflimit = num_rx_buf; | ||
| 912 | acm->urb_task.func = acm_rx_tasklet; | 928 | acm->urb_task.func = acm_rx_tasklet; |
| 913 | acm->urb_task.data = (unsigned long) acm; | 929 | acm->urb_task.data = (unsigned long) acm; |
| 914 | INIT_WORK(&acm->work, acm_softint, acm); | 930 | INIT_WORK(&acm->work, acm_softint, acm); |
| @@ -935,7 +951,7 @@ skip_normal_probe: | |||
| 935 | dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); | 951 | dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); |
| 936 | goto alloc_fail5; | 952 | goto alloc_fail5; |
| 937 | } | 953 | } |
| 938 | for (i = 0; i < ACM_NRU; i++) { | 954 | for (i = 0; i < num_rx_buf; i++) { |
| 939 | struct acm_ru *rcv = &(acm->ru[i]); | 955 | struct acm_ru *rcv = &(acm->ru[i]); |
| 940 | 956 | ||
| 941 | if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { | 957 | if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) { |
| @@ -946,10 +962,9 @@ skip_normal_probe: | |||
| 946 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 962 | rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
| 947 | rcv->instance = acm; | 963 | rcv->instance = acm; |
| 948 | } | 964 | } |
| 949 | for (i = 0; i < ACM_NRB; i++) { | 965 | for (i = 0; i < num_rx_buf; i++) { |
| 950 | struct acm_rb *buf = &(acm->rb[i]); | 966 | struct acm_rb *buf = &(acm->rb[i]); |
| 951 | 967 | ||
| 952 | // Using usb_buffer_alloc instead of kmalloc as Oliver suggested | ||
| 953 | if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) { | 968 | if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) { |
| 954 | dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); | 969 | dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n"); |
| 955 | goto alloc_fail7; | 970 | goto alloc_fail7; |
| @@ -988,9 +1003,9 @@ skip_normal_probe: | |||
| 988 | return 0; | 1003 | return 0; |
| 989 | 1004 | ||
| 990 | alloc_fail7: | 1005 | alloc_fail7: |
| 991 | for (i = 0; i < ACM_NRB; i++) | 1006 | for (i = 0; i < num_rx_buf; i++) |
| 992 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | 1007 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); |
| 993 | for (i = 0; i < ACM_NRU; i++) | 1008 | for (i = 0; i < num_rx_buf; i++) |
| 994 | usb_free_urb(acm->ru[i].urb); | 1009 | usb_free_urb(acm->ru[i].urb); |
| 995 | usb_free_urb(acm->ctrlurb); | 1010 | usb_free_urb(acm->ctrlurb); |
| 996 | alloc_fail5: | 1011 | alloc_fail5: |
| @@ -1027,7 +1042,7 @@ static void acm_disconnect(struct usb_interface *intf) | |||
| 1027 | 1042 | ||
| 1028 | usb_kill_urb(acm->ctrlurb); | 1043 | usb_kill_urb(acm->ctrlurb); |
| 1029 | usb_kill_urb(acm->writeurb); | 1044 | usb_kill_urb(acm->writeurb); |
| 1030 | for (i = 0; i < ACM_NRU; i++) | 1045 | for (i = 0; i < acm->rx_buflimit; i++) |
| 1031 | usb_kill_urb(acm->ru[i].urb); | 1046 | usb_kill_urb(acm->ru[i].urb); |
| 1032 | 1047 | ||
| 1033 | INIT_LIST_HEAD(&acm->filled_read_bufs); | 1048 | INIT_LIST_HEAD(&acm->filled_read_bufs); |
| @@ -1039,7 +1054,7 @@ static void acm_disconnect(struct usb_interface *intf) | |||
| 1039 | 1054 | ||
| 1040 | acm_write_buffers_free(acm); | 1055 | acm_write_buffers_free(acm); |
| 1041 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); | 1056 | usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); |
| 1042 | for (i = 0; i < ACM_NRB; i++) | 1057 | for (i = 0; i < acm->rx_buflimit; i++) |
| 1043 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); | 1058 | usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma); |
| 1044 | 1059 | ||
| 1045 | usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf); | 1060 | usb_driver_release_interface(&acm_driver, intf == acm->control ? acm->data : intf); |
| @@ -1068,6 +1083,9 @@ static struct usb_device_id acm_ids[] = { | |||
| 1068 | { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ | 1083 | { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ |
| 1069 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ | 1084 | .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ |
| 1070 | }, | 1085 | }, |
| 1086 | { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ | ||
| 1087 | .driver_info = SINGLE_RX_URB, /* firmware bug */ | ||
| 1088 | }, | ||
| 1071 | /* control interfaces with various AT-command sets */ | 1089 | /* control interfaces with various AT-command sets */ |
| 1072 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, | 1090 | { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, |
| 1073 | USB_CDC_ACM_PROTO_AT_V25TER) }, | 1091 | USB_CDC_ACM_PROTO_AT_V25TER) }, |
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index fd2aaccdcbac..1bcaea32cfc1 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h | |||
| @@ -56,11 +56,11 @@ | |||
| 56 | * in line disciplines. They ask for empty space amount, receive our URB size, | 56 | * in line disciplines. They ask for empty space amount, receive our URB size, |
| 57 | * and proceed to issue several 1-character writes, assuming they will fit. | 57 | * and proceed to issue several 1-character writes, assuming they will fit. |
| 58 | * The very first write takes a complete URB. Fortunately, this only happens | 58 | * The very first write takes a complete URB. Fortunately, this only happens |
| 59 | * when processing onlcr, so we only need 2 buffers. | 59 | * when processing onlcr, so we only need 2 buffers. These values must be |
| 60 | * powers of 2. | ||
| 60 | */ | 61 | */ |
| 61 | #define ACM_NWB 2 | 62 | #define ACM_NW 2 |
| 62 | #define ACM_NRU 16 | 63 | #define ACM_NR 16 |
| 63 | #define ACM_NRB 16 | ||
| 64 | 64 | ||
| 65 | struct acm_wb { | 65 | struct acm_wb { |
| 66 | unsigned char *buf; | 66 | unsigned char *buf; |
| @@ -91,9 +91,10 @@ struct acm { | |||
| 91 | struct urb *ctrlurb, *writeurb; /* urbs */ | 91 | struct urb *ctrlurb, *writeurb; /* urbs */ |
| 92 | u8 *ctrl_buffer; /* buffers of urbs */ | 92 | u8 *ctrl_buffer; /* buffers of urbs */ |
| 93 | dma_addr_t ctrl_dma; /* dma handles of buffers */ | 93 | dma_addr_t ctrl_dma; /* dma handles of buffers */ |
| 94 | struct acm_wb wb[ACM_NWB]; | 94 | struct acm_wb wb[ACM_NW]; |
| 95 | struct acm_ru ru[ACM_NRU]; | 95 | struct acm_ru ru[ACM_NR]; |
| 96 | struct acm_rb rb[ACM_NRB]; | 96 | struct acm_rb rb[ACM_NR]; |
| 97 | int rx_buflimit; | ||
| 97 | int rx_endpoint; | 98 | int rx_endpoint; |
| 98 | spinlock_t read_lock; | 99 | spinlock_t read_lock; |
| 99 | struct list_head spare_read_urbs; | 100 | struct list_head spare_read_urbs; |
| @@ -122,3 +123,4 @@ struct acm { | |||
| 122 | 123 | ||
| 123 | /* constants describing various quirks and errors */ | 124 | /* constants describing various quirks and errors */ |
| 124 | #define NO_UNION_NORMAL 1 | 125 | #define NO_UNION_NORMAL 1 |
| 126 | #define SINGLE_RX_URB 2 | ||
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 28329ddf187c..ec510922af63 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile | |||
| @@ -3,7 +3,8 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \ | 5 | usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \ |
| 6 | config.o file.o buffer.o sysfs.o devio.o notify.o | 6 | config.o file.o buffer.o sysfs.o endpoint.o \ |
| 7 | devio.o notify.o | ||
| 7 | 8 | ||
| 8 | ifeq ($(CONFIG_PCI),y) | 9 | ifeq ($(CONFIG_PCI),y) |
| 9 | usbcore-objs += hcd-pci.o | 10 | usbcore-objs += hcd-pci.o |
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 545da37afca7..3f8e06279c92 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
| @@ -515,19 +515,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig | |||
| 515 | 515 | ||
| 516 | static struct usb_device *usbdev_lookup_minor(int minor) | 516 | static struct usb_device *usbdev_lookup_minor(int minor) |
| 517 | { | 517 | { |
| 518 | struct class_device *class_dev; | 518 | struct device *device; |
| 519 | struct usb_device *dev = NULL; | 519 | struct usb_device *udev = NULL; |
| 520 | 520 | ||
| 521 | down(&usb_device_class->sem); | 521 | down(&usb_device_class->sem); |
| 522 | list_for_each_entry(class_dev, &usb_device_class->children, node) { | 522 | list_for_each_entry(device, &usb_device_class->devices, node) { |
| 523 | if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { | 523 | if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { |
| 524 | dev = class_dev->class_data; | 524 | udev = device->platform_data; |
| 525 | break; | 525 | break; |
| 526 | } | 526 | } |
| 527 | } | 527 | } |
| 528 | up(&usb_device_class->sem); | 528 | up(&usb_device_class->sem); |
| 529 | 529 | ||
| 530 | return dev; | 530 | return udev; |
| 531 | }; | 531 | }; |
| 532 | 532 | ||
| 533 | /* | 533 | /* |
| @@ -823,8 +823,7 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg) | |||
| 823 | 823 | ||
| 824 | static int proc_resetdevice(struct dev_state *ps) | 824 | static int proc_resetdevice(struct dev_state *ps) |
| 825 | { | 825 | { |
| 826 | return usb_reset_device(ps->dev); | 826 | return usb_reset_composite_device(ps->dev, NULL); |
| 827 | |||
| 828 | } | 827 | } |
| 829 | 828 | ||
| 830 | static int proc_setintf(struct dev_state *ps, void __user *arg) | 829 | static int proc_setintf(struct dev_state *ps, void __user *arg) |
| @@ -923,8 +922,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 923 | if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) | 922 | if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) |
| 924 | != USB_ENDPOINT_XFER_CONTROL) | 923 | != USB_ENDPOINT_XFER_CONTROL) |
| 925 | return -EINVAL; | 924 | return -EINVAL; |
| 926 | /* min 8 byte setup packet, max arbitrary */ | 925 | /* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */ |
| 927 | if (uurb->buffer_length < 8 || uurb->buffer_length > PAGE_SIZE) | 926 | if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE)) |
| 928 | return -EINVAL; | 927 | return -EINVAL; |
| 929 | if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) | 928 | if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) |
| 930 | return -ENOMEM; | 929 | return -ENOMEM; |
| @@ -982,7 +981,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
| 982 | return -EFAULT; | 981 | return -EFAULT; |
| 983 | } | 982 | } |
| 984 | for (totlen = u = 0; u < uurb->number_of_packets; u++) { | 983 | for (totlen = u = 0; u < uurb->number_of_packets; u++) { |
| 985 | if (isopkt[u].length > 1023) { | 984 | /* arbitrary limit, sufficient for USB 2.0 high-bandwidth iso */ |
| 985 | if (isopkt[u].length > 8192) { | ||
| 986 | kfree(isopkt); | 986 | kfree(isopkt); |
| 987 | return -EINVAL; | 987 | return -EINVAL; |
| 988 | } | 988 | } |
| @@ -1078,7 +1078,9 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) | |||
| 1078 | if (copy_from_user(&uurb, arg, sizeof(uurb))) | 1078 | if (copy_from_user(&uurb, arg, sizeof(uurb))) |
| 1079 | return -EFAULT; | 1079 | return -EFAULT; |
| 1080 | 1080 | ||
| 1081 | return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg); | 1081 | return proc_do_submiturb(ps, &uurb, |
| 1082 | (struct usbdevfs_iso_packet_desc __user *)uurb.iso_frame_desc, | ||
| 1083 | arg); | ||
| 1082 | } | 1084 | } |
| 1083 | 1085 | ||
| 1084 | static int proc_unlinkurb(struct dev_state *ps, void __user *arg) | 1086 | static int proc_unlinkurb(struct dev_state *ps, void __user *arg) |
| @@ -1203,7 +1205,9 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) | |||
| 1203 | if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg)) | 1205 | if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg)) |
| 1204 | return -EFAULT; | 1206 | return -EFAULT; |
| 1205 | 1207 | ||
| 1206 | return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg); | 1208 | return proc_do_submiturb(ps, &uurb, |
| 1209 | (struct usbdevfs_iso_packet_desc __user *)uurb.iso_frame_desc, | ||
| 1210 | arg); | ||
| 1207 | } | 1211 | } |
| 1208 | 1212 | ||
| 1209 | static int processcompl_compat(struct async *as, void __user * __user *arg) | 1213 | static int processcompl_compat(struct async *as, void __user * __user *arg) |
| @@ -1576,16 +1580,16 @@ static void usbdev_add(struct usb_device *dev) | |||
| 1576 | { | 1580 | { |
| 1577 | int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); | 1581 | int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); |
| 1578 | 1582 | ||
| 1579 | dev->class_dev = class_device_create(usb_device_class, NULL, | 1583 | dev->usbfs_dev = device_create(usb_device_class, &dev->dev, |
| 1580 | MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, | 1584 | MKDEV(USB_DEVICE_MAJOR, minor), |
| 1581 | "usbdev%d.%d", dev->bus->busnum, dev->devnum); | 1585 | "usbdev%d.%d", dev->bus->busnum, dev->devnum); |
| 1582 | 1586 | ||
| 1583 | dev->class_dev->class_data = dev; | 1587 | dev->usbfs_dev->platform_data = dev; |
| 1584 | } | 1588 | } |
| 1585 | 1589 | ||
| 1586 | static void usbdev_remove(struct usb_device *dev) | 1590 | static void usbdev_remove(struct usb_device *dev) |
| 1587 | { | 1591 | { |
| 1588 | class_device_unregister(dev->class_dev); | 1592 | device_unregister(dev->usbfs_dev); |
| 1589 | } | 1593 | } |
| 1590 | 1594 | ||
| 1591 | static int usbdev_notify(struct notifier_block *self, unsigned long action, | 1595 | static int usbdev_notify(struct notifier_block *self, unsigned long action, |
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c new file mode 100644 index 000000000000..247b5a4913a8 --- /dev/null +++ b/drivers/usb/core/endpoint.c | |||
| @@ -0,0 +1,275 @@ | |||
| 1 | /* | ||
| 2 | * drivers/usb/core/endpoint.c | ||
| 3 | * | ||
| 4 | * (C) Copyright 2002,2004,2006 Greg Kroah-Hartman | ||
| 5 | * (C) Copyright 2002,2004 IBM Corp. | ||
| 6 | * (C) Copyright 2006 Novell Inc. | ||
| 7 | * | ||
| 8 | * Endpoint sysfs stuff | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/usb.h> | ||
| 14 | #include "usb.h" | ||
| 15 | |||
| 16 | /* endpoint stuff */ | ||
| 17 | |||
| 18 | struct ep_device { | ||
| 19 | struct usb_endpoint_descriptor *desc; | ||
| 20 | struct usb_device *udev; | ||
| 21 | struct device dev; | ||
| 22 | }; | ||
| 23 | #define to_ep_device(_dev) \ | ||
| 24 | container_of(_dev, struct ep_device, dev) | ||
| 25 | |||
| 26 | struct ep_attribute { | ||
| 27 | struct attribute attr; | ||
| 28 | ssize_t (*show)(struct usb_device *, | ||
| 29 | struct usb_endpoint_descriptor *, char *); | ||
| 30 | }; | ||
| 31 | #define to_ep_attribute(_attr) \ | ||
| 32 | container_of(_attr, struct ep_attribute, attr) | ||
| 33 | |||
| 34 | #define usb_ep_attr(field, format_string) \ | ||
| 35 | static ssize_t show_ep_##field(struct device *dev, \ | ||
| 36 | struct device_attribute *attr, \ | ||
| 37 | char *buf) \ | ||
| 38 | { \ | ||
| 39 | struct ep_device *ep = to_ep_device(dev); \ | ||
| 40 | return sprintf(buf, format_string, ep->desc->field); \ | ||
| 41 | } \ | ||
| 42 | static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL); | ||
| 43 | |||
| 44 | usb_ep_attr(bLength, "%02x\n") | ||
| 45 | usb_ep_attr(bEndpointAddress, "%02x\n") | ||
| 46 | usb_ep_attr(bmAttributes, "%02x\n") | ||
| 47 | usb_ep_attr(bInterval, "%02x\n") | ||
| 48 | |||
| 49 | static ssize_t show_ep_wMaxPacketSize(struct device *dev, | ||
| 50 | struct device_attribute *attr, char *buf) | ||
| 51 | { | ||
| 52 | struct ep_device *ep = to_ep_device(dev); | ||
| 53 | return sprintf(buf, "%04x\n", | ||
| 54 | le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff); | ||
| 55 | } | ||
| 56 | static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL); | ||
| 57 | |||
| 58 | static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, | ||
| 59 | char *buf) | ||
| 60 | { | ||
| 61 | struct ep_device *ep = to_ep_device(dev); | ||
| 62 | char *type = "unknown"; | ||
| 63 | |||
| 64 | switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
| 65 | case USB_ENDPOINT_XFER_CONTROL: | ||
| 66 | type = "Control"; | ||
| 67 | break; | ||
| 68 | case USB_ENDPOINT_XFER_ISOC: | ||
| 69 | type = "Isoc"; | ||
| 70 | break; | ||
| 71 | case USB_ENDPOINT_XFER_BULK: | ||
| 72 | type = "Bulk"; | ||
| 73 | break; | ||
| 74 | case USB_ENDPOINT_XFER_INT: | ||
| 75 | type = "Interrupt"; | ||
| 76 | break; | ||
| 77 | } | ||
| 78 | return sprintf(buf, "%s\n", type); | ||
| 79 | } | ||
| 80 | static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL); | ||
| 81 | |||
| 82 | static ssize_t show_ep_interval(struct device *dev, | ||
| 83 | struct device_attribute *attr, char *buf) | ||
| 84 | { | ||
| 85 | struct ep_device *ep = to_ep_device(dev); | ||
| 86 | char unit; | ||
| 87 | unsigned interval = 0; | ||
| 88 | unsigned in; | ||
| 89 | |||
| 90 | in = (ep->desc->bEndpointAddress & USB_DIR_IN); | ||
| 91 | |||
| 92 | switch (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
| 93 | case USB_ENDPOINT_XFER_CONTROL: | ||
| 94 | if (ep->udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ | ||
| 95 | interval = ep->desc->bInterval; | ||
| 96 | break; | ||
| 97 | case USB_ENDPOINT_XFER_ISOC: | ||
| 98 | interval = 1 << (ep->desc->bInterval - 1); | ||
| 99 | break; | ||
| 100 | case USB_ENDPOINT_XFER_BULK: | ||
| 101 | if (ep->udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ | ||
| 102 | interval = ep->desc->bInterval; | ||
| 103 | break; | ||
| 104 | case USB_ENDPOINT_XFER_INT: | ||
| 105 | if (ep->udev->speed == USB_SPEED_HIGH) | ||
| 106 | interval = 1 << (ep->desc->bInterval - 1); | ||
| 107 | else | ||
| 108 | interval = ep->desc->bInterval; | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000; | ||
| 112 | if (interval % 1000) | ||
| 113 | unit = 'u'; | ||
| 114 | else { | ||
| 115 | unit = 'm'; | ||
| 116 | interval /= 1000; | ||
| 117 | } | ||
| 118 | |||
| 119 | return sprintf(buf, "%d%cs\n", interval, unit); | ||
| 120 | } | ||
| 121 | static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL); | ||
| 122 | |||
| 123 | static ssize_t show_ep_direction(struct device *dev, | ||
| 124 | struct device_attribute *attr, char *buf) | ||
| 125 | { | ||
| 126 | struct ep_device *ep = to_ep_device(dev); | ||
| 127 | char *direction; | ||
| 128 | |||
| 129 | if ((ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | ||
| 130 | USB_ENDPOINT_XFER_CONTROL) | ||
| 131 | direction = "both"; | ||
| 132 | else if (ep->desc->bEndpointAddress & USB_DIR_IN) | ||
| 133 | direction = "in"; | ||
| 134 | else | ||
| 135 | direction = "out"; | ||
| 136 | return sprintf(buf, "%s\n", direction); | ||
| 137 | } | ||
| 138 | static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL); | ||
| 139 | |||
| 140 | static struct attribute *ep_dev_attrs[] = { | ||
| 141 | &dev_attr_bLength.attr, | ||
| 142 | &dev_attr_bEndpointAddress.attr, | ||
| 143 | &dev_attr_bmAttributes.attr, | ||
| 144 | &dev_attr_bInterval.attr, | ||
| 145 | &dev_attr_wMaxPacketSize.attr, | ||
| 146 | &dev_attr_interval.attr, | ||
| 147 | &dev_attr_type.attr, | ||
| 148 | &dev_attr_direction.attr, | ||
| 149 | NULL, | ||
| 150 | }; | ||
| 151 | static struct attribute_group ep_dev_attr_grp = { | ||
| 152 | .attrs = ep_dev_attrs, | ||
| 153 | }; | ||
| 154 | |||
| 155 | static struct endpoint_class { | ||
| 156 | struct kref kref; | ||
| 157 | struct class *class; | ||
| 158 | } *ep_class; | ||
| 159 | |||
| 160 | static int init_endpoint_class(void) | ||
| 161 | { | ||
| 162 | int result = 0; | ||
| 163 | |||
| 164 | if (ep_class != NULL) { | ||
| 165 | kref_get(&ep_class->kref); | ||
| 166 | goto exit; | ||
| 167 | } | ||
| 168 | |||
| 169 | ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL); | ||
| 170 | if (!ep_class) { | ||
| 171 | result = -ENOMEM; | ||
| 172 | goto exit; | ||
| 173 | } | ||
| 174 | |||
| 175 | kref_init(&ep_class->kref); | ||
| 176 | ep_class->class = class_create(THIS_MODULE, "usb_endpoint"); | ||
| 177 | if (IS_ERR(ep_class->class)) { | ||
| 178 | result = IS_ERR(ep_class->class); | ||
| 179 | kfree(ep_class); | ||
| 180 | ep_class = NULL; | ||
| 181 | goto exit; | ||
| 182 | } | ||
| 183 | |||
| 184 | exit: | ||
| 185 | return result; | ||
| 186 | } | ||
| 187 | |||
| 188 | static void release_endpoint_class(struct kref *kref) | ||
| 189 | { | ||
| 190 | /* Ok, we cheat as we know we only have one ep_class */ | ||
| 191 | class_destroy(ep_class->class); | ||
| 192 | kfree(ep_class); | ||
| 193 | ep_class = NULL; | ||
| 194 | } | ||
| 195 | |||
| 196 | static void destroy_endpoint_class(void) | ||
| 197 | { | ||
| 198 | if (ep_class) | ||
| 199 | kref_put(&ep_class->kref, release_endpoint_class); | ||
| 200 | } | ||
| 201 | |||
| 202 | static void ep_device_release(struct device *dev) | ||
| 203 | { | ||
| 204 | struct ep_device *ep_dev = to_ep_device(dev); | ||
| 205 | |||
| 206 | dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id); | ||
| 207 | kfree(ep_dev); | ||
| 208 | } | ||
| 209 | |||
| 210 | void usb_create_ep_files(struct device *parent, | ||
| 211 | struct usb_host_endpoint *endpoint, | ||
| 212 | struct usb_device *udev) | ||
| 213 | { | ||
| 214 | char name[8]; | ||
| 215 | struct ep_device *ep_dev; | ||
| 216 | int minor; | ||
| 217 | int retval; | ||
| 218 | |||
| 219 | retval = init_endpoint_class(); | ||
| 220 | if (retval) | ||
| 221 | goto exit; | ||
| 222 | |||
| 223 | ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); | ||
| 224 | if (!ep_dev) { | ||
| 225 | retval = -ENOMEM; | ||
| 226 | goto exit; | ||
| 227 | } | ||
| 228 | |||
| 229 | /* fun calculation to determine the minor of this endpoint */ | ||
| 230 | minor = (((udev->bus->busnum - 1) * 128) * 16) + (udev->devnum - 1); | ||
| 231 | |||
| 232 | ep_dev->desc = &endpoint->desc; | ||
| 233 | ep_dev->udev = udev; | ||
| 234 | ep_dev->dev.devt = MKDEV(442, minor); // FIXME fake number... | ||
| 235 | ep_dev->dev.class = ep_class->class; | ||
| 236 | ep_dev->dev.parent = parent; | ||
| 237 | ep_dev->dev.release = ep_device_release; | ||
| 238 | snprintf(ep_dev->dev.bus_id, BUS_ID_SIZE, "usbdev%d.%d_ep%02x", | ||
| 239 | udev->bus->busnum, udev->devnum, | ||
| 240 | endpoint->desc.bEndpointAddress); | ||
| 241 | |||
| 242 | retval = device_register(&ep_dev->dev); | ||
| 243 | if (retval) | ||
| 244 | goto error; | ||
| 245 | sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); | ||
| 246 | |||
| 247 | endpoint->ep_dev = ep_dev; | ||
| 248 | |||
| 249 | /* create the symlink to the old-style "ep_XX" directory */ | ||
| 250 | sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); | ||
| 251 | sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name); | ||
| 252 | |||
| 253 | exit: | ||
| 254 | return; | ||
| 255 | error: | ||
| 256 | kfree(ep_dev); | ||
| 257 | return; | ||
| 258 | } | ||
| 259 | |||
| 260 | void usb_remove_ep_files(struct usb_host_endpoint *endpoint) | ||
| 261 | { | ||
| 262 | |||
| 263 | if (endpoint->ep_dev) { | ||
| 264 | char name[8]; | ||
| 265 | |||
| 266 | sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); | ||
| 267 | sysfs_remove_link(&endpoint->ep_dev->dev.parent->kobj, name); | ||
| 268 | sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp); | ||
| 269 | device_unregister(&endpoint->ep_dev->dev); | ||
| 270 | endpoint->ep_dev = NULL; | ||
| 271 | } | ||
| 272 | destroy_endpoint_class(); | ||
| 273 | } | ||
| 274 | |||
| 275 | |||
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index b263a54a13c0..f65b193cde3d 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c | |||
| @@ -61,33 +61,66 @@ static struct file_operations usb_fops = { | |||
| 61 | .open = usb_open, | 61 | .open = usb_open, |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | static struct class *usb_class; | 64 | static struct usb_class { |
| 65 | struct kref kref; | ||
| 66 | struct class *class; | ||
| 67 | } *usb_class; | ||
| 65 | 68 | ||
| 66 | int usb_major_init(void) | 69 | static int init_usb_class(void) |
| 67 | { | 70 | { |
| 68 | int error; | 71 | int result = 0; |
| 69 | 72 | ||
| 70 | error = register_chrdev(USB_MAJOR, "usb", &usb_fops); | 73 | if (usb_class != NULL) { |
| 71 | if (error) { | 74 | kref_get(&usb_class->kref); |
| 72 | err("unable to get major %d for usb devices", USB_MAJOR); | 75 | goto exit; |
| 73 | goto out; | 76 | } |
| 77 | |||
| 78 | usb_class = kmalloc(sizeof(*usb_class), GFP_KERNEL); | ||
| 79 | if (!usb_class) { | ||
| 80 | result = -ENOMEM; | ||
| 81 | goto exit; | ||
| 74 | } | 82 | } |
| 75 | 83 | ||
| 76 | usb_class = class_create(THIS_MODULE, "usb"); | 84 | kref_init(&usb_class->kref); |
| 77 | if (IS_ERR(usb_class)) { | 85 | usb_class->class = class_create(THIS_MODULE, "usb"); |
| 78 | error = PTR_ERR(usb_class); | 86 | if (IS_ERR(usb_class->class)) { |
| 87 | result = IS_ERR(usb_class->class); | ||
| 79 | err("class_create failed for usb devices"); | 88 | err("class_create failed for usb devices"); |
| 80 | unregister_chrdev(USB_MAJOR, "usb"); | 89 | kfree(usb_class); |
| 81 | goto out; | 90 | usb_class = NULL; |
| 82 | } | 91 | } |
| 83 | 92 | ||
| 84 | out: | 93 | exit: |
| 94 | return result; | ||
| 95 | } | ||
| 96 | |||
| 97 | static void release_usb_class(struct kref *kref) | ||
| 98 | { | ||
| 99 | /* Ok, we cheat as we know we only have one usb_class */ | ||
| 100 | class_destroy(usb_class->class); | ||
| 101 | kfree(usb_class); | ||
| 102 | usb_class = NULL; | ||
| 103 | } | ||
| 104 | |||
| 105 | static void destroy_usb_class(void) | ||
| 106 | { | ||
| 107 | if (usb_class) | ||
| 108 | kref_put(&usb_class->kref, release_usb_class); | ||
| 109 | } | ||
| 110 | |||
| 111 | int usb_major_init(void) | ||
| 112 | { | ||
| 113 | int error; | ||
| 114 | |||
| 115 | error = register_chrdev(USB_MAJOR, "usb", &usb_fops); | ||
| 116 | if (error) | ||
| 117 | err("unable to get major %d for usb devices", USB_MAJOR); | ||
| 118 | |||
| 85 | return error; | 119 | return error; |
| 86 | } | 120 | } |
| 87 | 121 | ||
| 88 | void usb_major_cleanup(void) | 122 | void usb_major_cleanup(void) |
| 89 | { | 123 | { |
| 90 | class_destroy(usb_class); | ||
| 91 | unregister_chrdev(USB_MAJOR, "usb"); | 124 | unregister_chrdev(USB_MAJOR, "usb"); |
| 92 | } | 125 | } |
| 93 | 126 | ||
| @@ -149,6 +182,10 @@ int usb_register_dev(struct usb_interface *intf, | |||
| 149 | if (retval) | 182 | if (retval) |
| 150 | goto exit; | 183 | goto exit; |
| 151 | 184 | ||
| 185 | retval = init_usb_class(); | ||
| 186 | if (retval) | ||
| 187 | goto exit; | ||
| 188 | |||
| 152 | intf->minor = minor; | 189 | intf->minor = minor; |
| 153 | 190 | ||
| 154 | /* create a usb class device for this usb interface */ | 191 | /* create a usb class device for this usb interface */ |
| @@ -158,14 +195,13 @@ int usb_register_dev(struct usb_interface *intf, | |||
| 158 | ++temp; | 195 | ++temp; |
| 159 | else | 196 | else |
| 160 | temp = name; | 197 | temp = name; |
| 161 | intf->class_dev = class_device_create(usb_class, NULL, | 198 | intf->usb_dev = device_create(usb_class->class, &intf->dev, |
| 162 | MKDEV(USB_MAJOR, minor), | 199 | MKDEV(USB_MAJOR, minor), "%s", temp); |
| 163 | &intf->dev, "%s", temp); | 200 | if (IS_ERR(intf->usb_dev)) { |
| 164 | if (IS_ERR(intf->class_dev)) { | ||
| 165 | spin_lock (&minor_lock); | 201 | spin_lock (&minor_lock); |
| 166 | usb_minors[intf->minor] = NULL; | 202 | usb_minors[intf->minor] = NULL; |
| 167 | spin_unlock (&minor_lock); | 203 | spin_unlock (&minor_lock); |
| 168 | retval = PTR_ERR(intf->class_dev); | 204 | retval = PTR_ERR(intf->usb_dev); |
| 169 | } | 205 | } |
| 170 | exit: | 206 | exit: |
| 171 | return retval; | 207 | return retval; |
| @@ -206,9 +242,10 @@ void usb_deregister_dev(struct usb_interface *intf, | |||
| 206 | spin_unlock (&minor_lock); | 242 | spin_unlock (&minor_lock); |
| 207 | 243 | ||
| 208 | snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); | 244 | snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); |
| 209 | class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor)); | 245 | device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); |
| 210 | intf->class_dev = NULL; | 246 | intf->usb_dev = NULL; |
| 211 | intf->minor = -1; | 247 | intf->minor = -1; |
| 248 | destroy_usb_class(); | ||
| 212 | } | 249 | } |
| 213 | EXPORT_SYMBOL(usb_deregister_dev); | 250 | EXPORT_SYMBOL(usb_deregister_dev); |
| 214 | 251 | ||
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 90b8d43c6b33..e1731ff8af4d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
| @@ -432,15 +432,22 @@ static void hub_power_on(struct usb_hub *hub) | |||
| 432 | { | 432 | { |
| 433 | int port1; | 433 | int port1; |
| 434 | unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; | 434 | unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; |
| 435 | u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); | 435 | u16 wHubCharacteristics = |
| 436 | 436 | le16_to_cpu(hub->descriptor->wHubCharacteristics); | |
| 437 | /* if hub supports power switching, enable power on each port */ | 437 | |
| 438 | if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) { | 438 | /* Enable power on each port. Some hubs have reserved values |
| 439 | * of LPSM (> 2) in their descriptors, even though they are | ||
| 440 | * USB 2.0 hubs. Some hubs do not implement port-power switching | ||
| 441 | * but only emulate it. In all cases, the ports won't work | ||
| 442 | * unless we send these messages to the hub. | ||
| 443 | */ | ||
| 444 | if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) | ||
| 439 | dev_dbg(hub->intfdev, "enabling power on all ports\n"); | 445 | dev_dbg(hub->intfdev, "enabling power on all ports\n"); |
| 440 | for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) | 446 | else |
| 441 | set_port_feature(hub->hdev, port1, | 447 | dev_dbg(hub->intfdev, "trying to enable port power on " |
| 442 | USB_PORT_FEAT_POWER); | 448 | "non-switchable hub\n"); |
| 443 | } | 449 | for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) |
| 450 | set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); | ||
| 444 | 451 | ||
| 445 | /* Wait at least 100 msec for power to become stable */ | 452 | /* Wait at least 100 msec for power to become stable */ |
| 446 | msleep(max(pgood_delay, (unsigned) 100)); | 453 | msleep(max(pgood_delay, (unsigned) 100)); |
| @@ -518,15 +525,16 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) | |||
| 518 | 525 | ||
| 519 | 526 | ||
| 520 | /* caller has locked the hub device */ | 527 | /* caller has locked the hub device */ |
| 521 | static void hub_pre_reset(struct usb_hub *hub, int disable_ports) | 528 | static void hub_pre_reset(struct usb_interface *intf) |
| 522 | { | 529 | { |
| 530 | struct usb_hub *hub = usb_get_intfdata(intf); | ||
| 523 | struct usb_device *hdev = hub->hdev; | 531 | struct usb_device *hdev = hub->hdev; |
| 524 | int port1; | 532 | int port1; |
| 525 | 533 | ||
| 526 | for (port1 = 1; port1 <= hdev->maxchild; ++port1) { | 534 | for (port1 = 1; port1 <= hdev->maxchild; ++port1) { |
| 527 | if (hdev->children[port1 - 1]) { | 535 | if (hdev->children[port1 - 1]) { |
| 528 | usb_disconnect(&hdev->children[port1 - 1]); | 536 | usb_disconnect(&hdev->children[port1 - 1]); |
| 529 | if (disable_ports) | 537 | if (hub->error == 0) |
| 530 | hub_port_disable(hub, port1, 0); | 538 | hub_port_disable(hub, port1, 0); |
| 531 | } | 539 | } |
| 532 | } | 540 | } |
| @@ -534,8 +542,10 @@ static void hub_pre_reset(struct usb_hub *hub, int disable_ports) | |||
| 534 | } | 542 | } |
| 535 | 543 | ||
| 536 | /* caller has locked the hub device */ | 544 | /* caller has locked the hub device */ |
| 537 | static void hub_post_reset(struct usb_hub *hub) | 545 | static void hub_post_reset(struct usb_interface *intf) |
| 538 | { | 546 | { |
| 547 | struct usb_hub *hub = usb_get_intfdata(intf); | ||
| 548 | |||
| 539 | hub_activate(hub); | 549 | hub_activate(hub); |
| 540 | hub_power_on(hub); | 550 | hub_power_on(hub); |
| 541 | } | 551 | } |
| @@ -795,15 +805,16 @@ static void hub_disconnect(struct usb_interface *intf) | |||
| 795 | struct usb_hub *hub = usb_get_intfdata (intf); | 805 | struct usb_hub *hub = usb_get_intfdata (intf); |
| 796 | struct usb_device *hdev; | 806 | struct usb_device *hdev; |
| 797 | 807 | ||
| 808 | /* Disconnect all children and quiesce the hub */ | ||
| 809 | hub->error = 0; | ||
| 810 | hub_pre_reset(intf); | ||
| 811 | |||
| 798 | usb_set_intfdata (intf, NULL); | 812 | usb_set_intfdata (intf, NULL); |
| 799 | hdev = hub->hdev; | 813 | hdev = hub->hdev; |
| 800 | 814 | ||
| 801 | if (hdev->speed == USB_SPEED_HIGH) | 815 | if (hdev->speed == USB_SPEED_HIGH) |
| 802 | highspeed_hubs--; | 816 | highspeed_hubs--; |
| 803 | 817 | ||
| 804 | /* Disconnect all children and quiesce the hub */ | ||
| 805 | hub_pre_reset(hub, 1); | ||
| 806 | |||
| 807 | usb_free_urb(hub->urb); | 818 | usb_free_urb(hub->urb); |
| 808 | hub->urb = NULL; | 819 | hub->urb = NULL; |
| 809 | 820 | ||
| @@ -1169,6 +1180,7 @@ static int choose_configuration(struct usb_device *udev) | |||
| 1169 | { | 1180 | { |
| 1170 | int i; | 1181 | int i; |
| 1171 | int num_configs; | 1182 | int num_configs; |
| 1183 | int insufficient_power = 0; | ||
| 1172 | struct usb_host_config *c, *best; | 1184 | struct usb_host_config *c, *best; |
| 1173 | 1185 | ||
| 1174 | best = NULL; | 1186 | best = NULL; |
| @@ -1221,8 +1233,10 @@ static int choose_configuration(struct usb_device *udev) | |||
| 1221 | */ | 1233 | */ |
| 1222 | 1234 | ||
| 1223 | /* Rule out configs that draw too much bus current */ | 1235 | /* Rule out configs that draw too much bus current */ |
| 1224 | if (c->desc.bMaxPower * 2 > udev->bus_mA) | 1236 | if (c->desc.bMaxPower * 2 > udev->bus_mA) { |
| 1237 | insufficient_power++; | ||
| 1225 | continue; | 1238 | continue; |
| 1239 | } | ||
| 1226 | 1240 | ||
| 1227 | /* If the first config's first interface is COMM/2/0xff | 1241 | /* If the first config's first interface is COMM/2/0xff |
| 1228 | * (MSFT RNDIS), rule it out unless Linux has host-side | 1242 | * (MSFT RNDIS), rule it out unless Linux has host-side |
| @@ -1231,7 +1245,7 @@ static int choose_configuration(struct usb_device *udev) | |||
| 1231 | && desc->bInterfaceClass == USB_CLASS_COMM | 1245 | && desc->bInterfaceClass == USB_CLASS_COMM |
| 1232 | && desc->bInterfaceSubClass == 2 | 1246 | && desc->bInterfaceSubClass == 2 |
| 1233 | && desc->bInterfaceProtocol == 0xff) { | 1247 | && desc->bInterfaceProtocol == 0xff) { |
| 1234 | #ifndef CONFIG_USB_NET_RNDIS | 1248 | #ifndef CONFIG_USB_NET_RNDIS_HOST |
| 1235 | continue; | 1249 | continue; |
| 1236 | #else | 1250 | #else |
| 1237 | best = c; | 1251 | best = c; |
| @@ -1256,6 +1270,11 @@ static int choose_configuration(struct usb_device *udev) | |||
| 1256 | best = c; | 1270 | best = c; |
| 1257 | } | 1271 | } |
| 1258 | 1272 | ||
| 1273 | if (insufficient_power > 0) | ||
| 1274 | dev_info(&udev->dev, "rejected %d configuration%s " | ||
| 1275 | "due to insufficient available bus power\n", | ||
| 1276 | insufficient_power, plural(insufficient_power)); | ||
| 1277 | |||
| 1259 | if (best) { | 1278 | if (best) { |
| 1260 | i = best->desc.bConfigurationValue; | 1279 | i = best->desc.bConfigurationValue; |
| 1261 | dev_info(&udev->dev, | 1280 | dev_info(&udev->dev, |
| @@ -2732,7 +2751,8 @@ static void hub_events(void) | |||
| 2732 | 2751 | ||
| 2733 | /* If the hub has died, clean up after it */ | 2752 | /* If the hub has died, clean up after it */ |
| 2734 | if (hdev->state == USB_STATE_NOTATTACHED) { | 2753 | if (hdev->state == USB_STATE_NOTATTACHED) { |
| 2735 | hub_pre_reset(hub, 0); | 2754 | hub->error = -ENODEV; |
| 2755 | hub_pre_reset(intf); | ||
| 2736 | goto loop; | 2756 | goto loop; |
| 2737 | } | 2757 | } |
| 2738 | 2758 | ||
| @@ -2744,7 +2764,7 @@ static void hub_events(void) | |||
| 2744 | dev_dbg (hub_dev, "resetting for error %d\n", | 2764 | dev_dbg (hub_dev, "resetting for error %d\n", |
| 2745 | hub->error); | 2765 | hub->error); |
| 2746 | 2766 | ||
| 2747 | ret = usb_reset_device(hdev); | 2767 | ret = usb_reset_composite_device(hdev, intf); |
| 2748 | if (ret) { | 2768 | if (ret) { |
| 2749 | dev_dbg (hub_dev, | 2769 | dev_dbg (hub_dev, |
| 2750 | "error resetting hub: %d\n", ret); | 2770 | "error resetting hub: %d\n", ret); |
| @@ -2913,6 +2933,8 @@ static struct usb_driver hub_driver = { | |||
| 2913 | .disconnect = hub_disconnect, | 2933 | .disconnect = hub_disconnect, |
| 2914 | .suspend = hub_suspend, | 2934 | .suspend = hub_suspend, |
| 2915 | .resume = hub_resume, | 2935 | .resume = hub_resume, |
| 2936 | .pre_reset = hub_pre_reset, | ||
| 2937 | .post_reset = hub_post_reset, | ||
| 2916 | .ioctl = hub_ioctl, | 2938 | .ioctl = hub_ioctl, |
| 2917 | .id_table = hub_id_table, | 2939 | .id_table = hub_id_table, |
| 2918 | }; | 2940 | }; |
| @@ -2992,9 +3014,9 @@ static int config_descriptors_changed(struct usb_device *udev) | |||
| 2992 | * usb_reset_device - perform a USB port reset to reinitialize a device | 3014 | * usb_reset_device - perform a USB port reset to reinitialize a device |
| 2993 | * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) | 3015 | * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) |
| 2994 | * | 3016 | * |
| 2995 | * WARNING - don't reset any device unless drivers for all of its | 3017 | * WARNING - don't use this routine to reset a composite device |
| 2996 | * interfaces are expecting that reset! Maybe some driver->reset() | 3018 | * (one with multiple interfaces owned by separate drivers)! |
| 2997 | * method should eventually help ensure sufficient cooperation. | 3019 | * Use usb_reset_composite_device() instead. |
| 2998 | * | 3020 | * |
| 2999 | * Do a port reset, reassign the device's address, and establish its | 3021 | * Do a port reset, reassign the device's address, and establish its |
| 3000 | * former operating configuration. If the reset fails, or the device's | 3022 | * former operating configuration. If the reset fails, or the device's |
| @@ -3018,7 +3040,6 @@ int usb_reset_device(struct usb_device *udev) | |||
| 3018 | struct usb_device *parent_hdev = udev->parent; | 3040 | struct usb_device *parent_hdev = udev->parent; |
| 3019 | struct usb_hub *parent_hub; | 3041 | struct usb_hub *parent_hub; |
| 3020 | struct usb_device_descriptor descriptor = udev->descriptor; | 3042 | struct usb_device_descriptor descriptor = udev->descriptor; |
| 3021 | struct usb_hub *hub = NULL; | ||
| 3022 | int i, ret = 0; | 3043 | int i, ret = 0; |
| 3023 | int port1 = udev->portnum; | 3044 | int port1 = udev->portnum; |
| 3024 | 3045 | ||
| @@ -3036,14 +3057,6 @@ int usb_reset_device(struct usb_device *udev) | |||
| 3036 | } | 3057 | } |
| 3037 | parent_hub = hdev_to_hub(parent_hdev); | 3058 | parent_hub = hdev_to_hub(parent_hdev); |
| 3038 | 3059 | ||
| 3039 | /* If we're resetting an active hub, take some special actions */ | ||
| 3040 | if (udev->actconfig && udev->actconfig->desc.bNumInterfaces > 0 && | ||
| 3041 | udev->actconfig->interface[0]->dev.driver == | ||
| 3042 | &hub_driver.driver && | ||
| 3043 | (hub = hdev_to_hub(udev)) != NULL) { | ||
| 3044 | hub_pre_reset(hub, 0); | ||
| 3045 | } | ||
| 3046 | |||
| 3047 | set_bit(port1, parent_hub->busy_bits); | 3060 | set_bit(port1, parent_hub->busy_bits); |
| 3048 | for (i = 0; i < SET_CONFIG_TRIES; ++i) { | 3061 | for (i = 0; i < SET_CONFIG_TRIES; ++i) { |
| 3049 | 3062 | ||
| @@ -3102,11 +3115,87 @@ int usb_reset_device(struct usb_device *udev) | |||
| 3102 | } | 3115 | } |
| 3103 | 3116 | ||
| 3104 | done: | 3117 | done: |
| 3105 | if (hub) | ||
| 3106 | hub_post_reset(hub); | ||
| 3107 | return 0; | 3118 | return 0; |
| 3108 | 3119 | ||
| 3109 | re_enumerate: | 3120 | re_enumerate: |
| 3110 | hub_port_logical_disconnect(parent_hub, port1); | 3121 | hub_port_logical_disconnect(parent_hub, port1); |
| 3111 | return -ENODEV; | 3122 | return -ENODEV; |
| 3112 | } | 3123 | } |
| 3124 | |||
| 3125 | /** | ||
| 3126 | * usb_reset_composite_device - warn interface drivers and perform a USB port reset | ||
| 3127 | * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) | ||
| 3128 | * @iface: interface bound to the driver making the request (optional) | ||
| 3129 | * | ||
| 3130 | * Warns all drivers bound to registered interfaces (using their pre_reset | ||
| 3131 | * method), performs the port reset, and then lets the drivers know that | ||
| 3132 | * the reset is over (using their post_reset method). | ||
| 3133 | * | ||
| 3134 | * Return value is the same as for usb_reset_device(). | ||
| 3135 | * | ||
| 3136 | * The caller must own the device lock. For example, it's safe to use | ||
| 3137 | * this from a driver probe() routine after downloading new firmware. | ||
| 3138 | * For calls that might not occur during probe(), drivers should lock | ||
| 3139 | * the device using usb_lock_device_for_reset(). | ||
| 3140 | * | ||
| 3141 | * The interface locks are acquired during the pre_reset stage and released | ||
| 3142 | * during the post_reset stage. However if iface is not NULL and is | ||
| 3143 | * currently being probed, we assume that the caller already owns its | ||
| 3144 | * lock. | ||
| 3145 | */ | ||
| 3146 | int usb_reset_composite_device(struct usb_device *udev, | ||
| 3147 | struct usb_interface *iface) | ||
| 3148 | { | ||
| 3149 | int ret; | ||
| 3150 | struct usb_host_config *config = udev->actconfig; | ||
| 3151 | |||
| 3152 | if (udev->state == USB_STATE_NOTATTACHED || | ||
| 3153 | udev->state == USB_STATE_SUSPENDED) { | ||
| 3154 | dev_dbg(&udev->dev, "device reset not allowed in state %d\n", | ||
| 3155 | udev->state); | ||
| 3156 | return -EINVAL; | ||
| 3157 | } | ||
| 3158 | |||
| 3159 | if (iface && iface->condition != USB_INTERFACE_BINDING) | ||
| 3160 | iface = NULL; | ||
| 3161 | |||
| 3162 | if (config) { | ||
| 3163 | int i; | ||
| 3164 | struct usb_interface *cintf; | ||
| 3165 | struct usb_driver *drv; | ||
| 3166 | |||
| 3167 | for (i = 0; i < config->desc.bNumInterfaces; ++i) { | ||
| 3168 | cintf = config->interface[i]; | ||
| 3169 | if (cintf != iface) | ||
| 3170 | down(&cintf->dev.sem); | ||
| 3171 | if (device_is_registered(&cintf->dev) && | ||
| 3172 | cintf->dev.driver) { | ||
| 3173 | drv = to_usb_driver(cintf->dev.driver); | ||
| 3174 | if (drv->pre_reset) | ||
| 3175 | (drv->pre_reset)(cintf); | ||
| 3176 | } | ||
| 3177 | } | ||
| 3178 | } | ||
| 3179 | |||
| 3180 | ret = usb_reset_device(udev); | ||
| 3181 | |||
| 3182 | if (config) { | ||
| 3183 | int i; | ||
| 3184 | struct usb_interface *cintf; | ||
| 3185 | struct usb_driver *drv; | ||
| 3186 | |||
| 3187 | for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { | ||
| 3188 | cintf = config->interface[i]; | ||
| 3189 | if (device_is_registered(&cintf->dev) && | ||
| 3190 | cintf->dev.driver) { | ||
| 3191 | drv = to_usb_driver(cintf->dev.driver); | ||
| 3192 | if (drv->post_reset) | ||
| 3193 | (drv->post_reset)(cintf); | ||
| 3194 | } | ||
| 3195 | if (cintf != iface) | ||
| 3196 | up(&cintf->dev.sem); | ||
| 3197 | } | ||
| 3198 | } | ||
| 3199 | |||
| 3200 | return ret; | ||
| 3201 | } | ||
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 08fb20f06f3e..8569600f3130 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
| @@ -158,6 +158,37 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u | |||
| 158 | 158 | ||
| 159 | 159 | ||
| 160 | /** | 160 | /** |
| 161 | * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion | ||
| 162 | * @usb_dev: pointer to the usb device to send the message to | ||
| 163 | * @pipe: endpoint "pipe" to send the message to | ||
| 164 | * @data: pointer to the data to send | ||
| 165 | * @len: length in bytes of the data to send | ||
| 166 | * @actual_length: pointer to a location to put the actual length transferred in bytes | ||
| 167 | * @timeout: time in msecs to wait for the message to complete before | ||
| 168 | * timing out (if 0 the wait is forever) | ||
| 169 | * Context: !in_interrupt () | ||
| 170 | * | ||
| 171 | * This function sends a simple interrupt message to a specified endpoint and | ||
| 172 | * waits for the message to complete, or timeout. | ||
| 173 | * | ||
| 174 | * If successful, it returns 0, otherwise a negative error number. The number | ||
| 175 | * of actual bytes transferred will be stored in the actual_length paramater. | ||
| 176 | * | ||
| 177 | * Don't use this function from within an interrupt context, like a bottom half | ||
| 178 | * handler. If you need an asynchronous message, or need to send a message | ||
| 179 | * from within interrupt context, use usb_submit_urb() If a thread in your | ||
| 180 | * driver uses this call, make sure your disconnect() method can wait for it to | ||
| 181 | * complete. Since you don't have a handle on the URB used, you can't cancel | ||
| 182 | * the request. | ||
| 183 | */ | ||
| 184 | int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, | ||
| 185 | void *data, int len, int *actual_length, int timeout) | ||
| 186 | { | ||
| 187 | return usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout); | ||
| 188 | } | ||
| 189 | EXPORT_SYMBOL_GPL(usb_interrupt_msg); | ||
| 190 | |||
| 191 | /** | ||
| 161 | * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion | 192 | * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion |
| 162 | * @usb_dev: pointer to the usb device to send the message to | 193 | * @usb_dev: pointer to the usb device to send the message to |
| 163 | * @pipe: endpoint "pipe" to send the message to | 194 | * @pipe: endpoint "pipe" to send the message to |
| @@ -1380,15 +1411,7 @@ free_interfaces: | |||
| 1380 | return ret; | 1411 | return ret; |
| 1381 | } | 1412 | } |
| 1382 | } | 1413 | } |
| 1383 | } | ||
| 1384 | |||
| 1385 | /* if it's already configured, clear out old state first. | ||
| 1386 | * getting rid of old interfaces means unbinding their drivers. | ||
| 1387 | */ | ||
| 1388 | if (dev->state != USB_STATE_ADDRESS) | ||
| 1389 | usb_disable_device (dev, 1); // Skip ep0 | ||
| 1390 | 1414 | ||
| 1391 | if (cp) { | ||
| 1392 | i = dev->bus_mA - cp->desc.bMaxPower * 2; | 1415 | i = dev->bus_mA - cp->desc.bMaxPower * 2; |
| 1393 | if (i < 0) | 1416 | if (i < 0) |
| 1394 | dev_warn(&dev->dev, "new config #%d exceeds power " | 1417 | dev_warn(&dev->dev, "new config #%d exceeds power " |
| @@ -1396,84 +1419,91 @@ free_interfaces: | |||
| 1396 | configuration, -i); | 1419 | configuration, -i); |
| 1397 | } | 1420 | } |
| 1398 | 1421 | ||
| 1422 | /* if it's already configured, clear out old state first. | ||
| 1423 | * getting rid of old interfaces means unbinding their drivers. | ||
| 1424 | */ | ||
| 1425 | if (dev->state != USB_STATE_ADDRESS) | ||
| 1426 | usb_disable_device (dev, 1); // Skip ep0 | ||
| 1427 | |||
| 1399 | if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | 1428 | if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), |
| 1400 | USB_REQ_SET_CONFIGURATION, 0, configuration, 0, | 1429 | USB_REQ_SET_CONFIGURATION, 0, configuration, 0, |
| 1401 | NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) | 1430 | NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) { |
| 1402 | goto free_interfaces; | 1431 | |
| 1432 | /* All the old state is gone, so what else can we do? | ||
| 1433 | * The device is probably useless now anyway. | ||
| 1434 | */ | ||
| 1435 | cp = NULL; | ||
| 1436 | } | ||
| 1403 | 1437 | ||
| 1404 | dev->actconfig = cp; | 1438 | dev->actconfig = cp; |
| 1405 | if (!cp) | 1439 | if (!cp) { |
| 1406 | usb_set_device_state(dev, USB_STATE_ADDRESS); | 1440 | usb_set_device_state(dev, USB_STATE_ADDRESS); |
| 1407 | else { | 1441 | goto free_interfaces; |
| 1408 | usb_set_device_state(dev, USB_STATE_CONFIGURED); | 1442 | } |
| 1443 | usb_set_device_state(dev, USB_STATE_CONFIGURED); | ||
| 1409 | 1444 | ||
| 1410 | /* Initialize the new interface structures and the | 1445 | /* Initialize the new interface structures and the |
| 1411 | * hc/hcd/usbcore interface/endpoint state. | 1446 | * hc/hcd/usbcore interface/endpoint state. |
| 1412 | */ | 1447 | */ |
| 1413 | for (i = 0; i < nintf; ++i) { | 1448 | for (i = 0; i < nintf; ++i) { |
| 1414 | struct usb_interface_cache *intfc; | 1449 | struct usb_interface_cache *intfc; |
| 1415 | struct usb_interface *intf; | 1450 | struct usb_interface *intf; |
| 1416 | struct usb_host_interface *alt; | 1451 | struct usb_host_interface *alt; |
| 1417 | 1452 | ||
| 1418 | cp->interface[i] = intf = new_interfaces[i]; | 1453 | cp->interface[i] = intf = new_interfaces[i]; |
| 1419 | intfc = cp->intf_cache[i]; | 1454 | intfc = cp->intf_cache[i]; |
| 1420 | intf->altsetting = intfc->altsetting; | 1455 | intf->altsetting = intfc->altsetting; |
| 1421 | intf->num_altsetting = intfc->num_altsetting; | 1456 | intf->num_altsetting = intfc->num_altsetting; |
| 1422 | kref_get(&intfc->ref); | 1457 | kref_get(&intfc->ref); |
| 1423 | |||
| 1424 | alt = usb_altnum_to_altsetting(intf, 0); | ||
| 1425 | |||
| 1426 | /* No altsetting 0? We'll assume the first altsetting. | ||
| 1427 | * We could use a GetInterface call, but if a device is | ||
| 1428 | * so non-compliant that it doesn't have altsetting 0 | ||
| 1429 | * then I wouldn't trust its reply anyway. | ||
| 1430 | */ | ||
| 1431 | if (!alt) | ||
| 1432 | alt = &intf->altsetting[0]; | ||
| 1433 | |||
| 1434 | intf->cur_altsetting = alt; | ||
| 1435 | usb_enable_interface(dev, intf); | ||
| 1436 | intf->dev.parent = &dev->dev; | ||
| 1437 | intf->dev.driver = NULL; | ||
| 1438 | intf->dev.bus = &usb_bus_type; | ||
| 1439 | intf->dev.dma_mask = dev->dev.dma_mask; | ||
| 1440 | intf->dev.release = release_interface; | ||
| 1441 | device_initialize (&intf->dev); | ||
| 1442 | mark_quiesced(intf); | ||
| 1443 | sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", | ||
| 1444 | dev->bus->busnum, dev->devpath, | ||
| 1445 | configuration, | ||
| 1446 | alt->desc.bInterfaceNumber); | ||
| 1447 | } | ||
| 1448 | kfree(new_interfaces); | ||
| 1449 | 1458 | ||
| 1450 | if (cp->string == NULL) | 1459 | alt = usb_altnum_to_altsetting(intf, 0); |
| 1451 | cp->string = usb_cache_string(dev, | ||
| 1452 | cp->desc.iConfiguration); | ||
| 1453 | 1460 | ||
| 1454 | /* Now that all the interfaces are set up, register them | 1461 | /* No altsetting 0? We'll assume the first altsetting. |
| 1455 | * to trigger binding of drivers to interfaces. probe() | 1462 | * We could use a GetInterface call, but if a device is |
| 1456 | * routines may install different altsettings and may | 1463 | * so non-compliant that it doesn't have altsetting 0 |
| 1457 | * claim() any interfaces not yet bound. Many class drivers | 1464 | * then I wouldn't trust its reply anyway. |
| 1458 | * need that: CDC, audio, video, etc. | ||
| 1459 | */ | 1465 | */ |
| 1460 | for (i = 0; i < nintf; ++i) { | 1466 | if (!alt) |
| 1461 | struct usb_interface *intf = cp->interface[i]; | 1467 | alt = &intf->altsetting[0]; |
| 1462 | 1468 | ||
| 1463 | dev_dbg (&dev->dev, | 1469 | intf->cur_altsetting = alt; |
| 1464 | "adding %s (config #%d, interface %d)\n", | 1470 | usb_enable_interface(dev, intf); |
| 1465 | intf->dev.bus_id, configuration, | 1471 | intf->dev.parent = &dev->dev; |
| 1466 | intf->cur_altsetting->desc.bInterfaceNumber); | 1472 | intf->dev.driver = NULL; |
| 1467 | ret = device_add (&intf->dev); | 1473 | intf->dev.bus = &usb_bus_type; |
| 1468 | if (ret != 0) { | 1474 | intf->dev.dma_mask = dev->dev.dma_mask; |
| 1469 | dev_err(&dev->dev, | 1475 | intf->dev.release = release_interface; |
| 1470 | "device_add(%s) --> %d\n", | 1476 | device_initialize (&intf->dev); |
| 1471 | intf->dev.bus_id, | 1477 | mark_quiesced(intf); |
| 1472 | ret); | 1478 | sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", |
| 1473 | continue; | 1479 | dev->bus->busnum, dev->devpath, |
| 1474 | } | 1480 | configuration, alt->desc.bInterfaceNumber); |
| 1475 | usb_create_sysfs_intf_files (intf); | 1481 | } |
| 1482 | kfree(new_interfaces); | ||
| 1483 | |||
| 1484 | if (cp->string == NULL) | ||
| 1485 | cp->string = usb_cache_string(dev, cp->desc.iConfiguration); | ||
| 1486 | |||
| 1487 | /* Now that all the interfaces are set up, register them | ||
| 1488 | * to trigger binding of drivers to interfaces. probe() | ||
| 1489 | * routines may install different altsettings and may | ||
| 1490 | * claim() any interfaces not yet bound. Many class drivers | ||
| 1491 | * need that: CDC, audio, video, etc. | ||
| 1492 | */ | ||
| 1493 | for (i = 0; i < nintf; ++i) { | ||
| 1494 | struct usb_interface *intf = cp->interface[i]; | ||
| 1495 | |||
| 1496 | dev_dbg (&dev->dev, | ||
| 1497 | "adding %s (config #%d, interface %d)\n", | ||
| 1498 | intf->dev.bus_id, configuration, | ||
| 1499 | intf->cur_altsetting->desc.bInterfaceNumber); | ||
| 1500 | ret = device_add (&intf->dev); | ||
| 1501 | if (ret != 0) { | ||
| 1502 | dev_err(&dev->dev, "device_add(%s) --> %d\n", | ||
| 1503 | intf->dev.bus_id, ret); | ||
| 1504 | continue; | ||
| 1476 | } | 1505 | } |
| 1506 | usb_create_sysfs_intf_files (intf); | ||
| 1477 | } | 1507 | } |
| 1478 | 1508 | ||
| 1479 | return 0; | 1509 | return 0; |
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 71d881327e88..3f49bf51cff7 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c | |||
| @@ -15,203 +15,6 @@ | |||
| 15 | #include <linux/usb.h> | 15 | #include <linux/usb.h> |
| 16 | #include "usb.h" | 16 | #include "usb.h" |
| 17 | 17 | ||
| 18 | /* endpoint stuff */ | ||
| 19 | struct ep_object { | ||
| 20 | struct usb_endpoint_descriptor *desc; | ||
| 21 | struct usb_device *udev; | ||
| 22 | struct kobject kobj; | ||
| 23 | }; | ||
| 24 | #define to_ep_object(_kobj) \ | ||
| 25 | container_of(_kobj, struct ep_object, kobj) | ||
| 26 | |||
| 27 | struct ep_attribute { | ||
| 28 | struct attribute attr; | ||
| 29 | ssize_t (*show)(struct usb_device *, | ||
| 30 | struct usb_endpoint_descriptor *, char *); | ||
| 31 | }; | ||
| 32 | #define to_ep_attribute(_attr) \ | ||
| 33 | container_of(_attr, struct ep_attribute, attr) | ||
| 34 | |||
| 35 | #define EP_ATTR(_name) \ | ||
| 36 | struct ep_attribute ep_##_name = { \ | ||
| 37 | .attr = {.name = #_name, .owner = THIS_MODULE, \ | ||
| 38 | .mode = S_IRUGO}, \ | ||
| 39 | .show = show_ep_##_name} | ||
| 40 | |||
| 41 | #define usb_ep_attr(field, format_string) \ | ||
| 42 | static ssize_t show_ep_##field(struct usb_device *udev, \ | ||
| 43 | struct usb_endpoint_descriptor *desc, \ | ||
| 44 | char *buf) \ | ||
| 45 | { \ | ||
| 46 | return sprintf(buf, format_string, desc->field); \ | ||
| 47 | } \ | ||
| 48 | static EP_ATTR(field); | ||
| 49 | |||
| 50 | usb_ep_attr(bLength, "%02x\n") | ||
| 51 | usb_ep_attr(bEndpointAddress, "%02x\n") | ||
| 52 | usb_ep_attr(bmAttributes, "%02x\n") | ||
| 53 | usb_ep_attr(bInterval, "%02x\n") | ||
| 54 | |||
| 55 | static ssize_t show_ep_wMaxPacketSize(struct usb_device *udev, | ||
| 56 | struct usb_endpoint_descriptor *desc, char *buf) | ||
| 57 | { | ||
| 58 | return sprintf(buf, "%04x\n", | ||
| 59 | le16_to_cpu(desc->wMaxPacketSize) & 0x07ff); | ||
| 60 | } | ||
| 61 | static EP_ATTR(wMaxPacketSize); | ||
| 62 | |||
| 63 | static ssize_t show_ep_type(struct usb_device *udev, | ||
| 64 | struct usb_endpoint_descriptor *desc, char *buf) | ||
| 65 | { | ||
| 66 | char *type = "unknown"; | ||
| 67 | |||
| 68 | switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
| 69 | case USB_ENDPOINT_XFER_CONTROL: | ||
| 70 | type = "Control"; | ||
| 71 | break; | ||
| 72 | case USB_ENDPOINT_XFER_ISOC: | ||
| 73 | type = "Isoc"; | ||
| 74 | break; | ||
| 75 | case USB_ENDPOINT_XFER_BULK: | ||
| 76 | type = "Bulk"; | ||
| 77 | break; | ||
| 78 | case USB_ENDPOINT_XFER_INT: | ||
| 79 | type = "Interrupt"; | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | return sprintf(buf, "%s\n", type); | ||
| 83 | } | ||
| 84 | static EP_ATTR(type); | ||
| 85 | |||
| 86 | static ssize_t show_ep_interval(struct usb_device *udev, | ||
| 87 | struct usb_endpoint_descriptor *desc, char *buf) | ||
| 88 | { | ||
| 89 | char unit; | ||
| 90 | unsigned interval = 0; | ||
| 91 | unsigned in; | ||
| 92 | |||
| 93 | in = (desc->bEndpointAddress & USB_DIR_IN); | ||
| 94 | |||
| 95 | switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { | ||
| 96 | case USB_ENDPOINT_XFER_CONTROL: | ||
| 97 | if (udev->speed == USB_SPEED_HIGH) /* uframes per NAK */ | ||
| 98 | interval = desc->bInterval; | ||
| 99 | break; | ||
| 100 | case USB_ENDPOINT_XFER_ISOC: | ||
| 101 | interval = 1 << (desc->bInterval - 1); | ||
| 102 | break; | ||
| 103 | case USB_ENDPOINT_XFER_BULK: | ||
| 104 | if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ | ||
| 105 | interval = desc->bInterval; | ||
| 106 | break; | ||
| 107 | case USB_ENDPOINT_XFER_INT: | ||
| 108 | if (udev->speed == USB_SPEED_HIGH) | ||
| 109 | interval = 1 << (desc->bInterval - 1); | ||
| 110 | else | ||
| 111 | interval = desc->bInterval; | ||
| 112 | break; | ||
| 113 | } | ||
| 114 | interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000; | ||
| 115 | if (interval % 1000) | ||
| 116 | unit = 'u'; | ||
| 117 | else { | ||
| 118 | unit = 'm'; | ||
| 119 | interval /= 1000; | ||
| 120 | } | ||
| 121 | |||
| 122 | return sprintf(buf, "%d%cs\n", interval, unit); | ||
| 123 | } | ||
| 124 | static EP_ATTR(interval); | ||
| 125 | |||
| 126 | static ssize_t show_ep_direction(struct usb_device *udev, | ||
| 127 | struct usb_endpoint_descriptor *desc, char *buf) | ||
| 128 | { | ||
| 129 | char *direction; | ||
| 130 | |||
| 131 | if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | ||
| 132 | USB_ENDPOINT_XFER_CONTROL) | ||
| 133 | direction = "both"; | ||
| 134 | else if (desc->bEndpointAddress & USB_DIR_IN) | ||
| 135 | direction = "in"; | ||
| 136 | else | ||
| 137 | direction = "out"; | ||
| 138 | return sprintf(buf, "%s\n", direction); | ||
| 139 | } | ||
| 140 | static EP_ATTR(direction); | ||
| 141 | |||
| 142 | static struct attribute *ep_attrs[] = { | ||
| 143 | &ep_bLength.attr, | ||
| 144 | &ep_bEndpointAddress.attr, | ||
| 145 | &ep_bmAttributes.attr, | ||
| 146 | &ep_bInterval.attr, | ||
| 147 | &ep_wMaxPacketSize.attr, | ||
| 148 | &ep_type.attr, | ||
| 149 | &ep_interval.attr, | ||
| 150 | &ep_direction.attr, | ||
| 151 | NULL, | ||
| 152 | }; | ||
| 153 | |||
| 154 | static void ep_object_release(struct kobject *kobj) | ||
| 155 | { | ||
| 156 | kfree(to_ep_object(kobj)); | ||
| 157 | } | ||
| 158 | |||
| 159 | static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr, | ||
| 160 | char *buf) | ||
| 161 | { | ||
| 162 | struct ep_object *ep_obj = to_ep_object(kobj); | ||
| 163 | struct ep_attribute *ep_attr = to_ep_attribute(attr); | ||
| 164 | |||
| 165 | return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf); | ||
| 166 | } | ||
| 167 | |||
| 168 | static struct sysfs_ops ep_object_sysfs_ops = { | ||
| 169 | .show = ep_object_show, | ||
| 170 | }; | ||
| 171 | |||
| 172 | static struct kobj_type ep_object_ktype = { | ||
| 173 | .release = ep_object_release, | ||
| 174 | .sysfs_ops = &ep_object_sysfs_ops, | ||
| 175 | .default_attrs = ep_attrs, | ||
| 176 | }; | ||
| 177 | |||
| 178 | static void usb_create_ep_files(struct kobject *parent, | ||
| 179 | struct usb_host_endpoint *endpoint, | ||
| 180 | struct usb_device *udev) | ||
| 181 | { | ||
| 182 | struct ep_object *ep_obj; | ||
| 183 | struct kobject *kobj; | ||
| 184 | |||
| 185 | ep_obj = kzalloc(sizeof(struct ep_object), GFP_KERNEL); | ||
| 186 | if (!ep_obj) | ||
| 187 | return; | ||
| 188 | |||
| 189 | ep_obj->desc = &endpoint->desc; | ||
| 190 | ep_obj->udev = udev; | ||
| 191 | |||
| 192 | kobj = &ep_obj->kobj; | ||
| 193 | kobject_set_name(kobj, "ep_%02x", endpoint->desc.bEndpointAddress); | ||
| 194 | kobj->parent = parent; | ||
| 195 | kobj->ktype = &ep_object_ktype; | ||
| 196 | |||
| 197 | /* Don't use kobject_register, because it generates a hotplug event */ | ||
| 198 | kobject_init(kobj); | ||
| 199 | if (kobject_add(kobj) == 0) | ||
| 200 | endpoint->kobj = kobj; | ||
| 201 | else | ||
| 202 | kobject_put(kobj); | ||
| 203 | } | ||
| 204 | |||
| 205 | static void usb_remove_ep_files(struct usb_host_endpoint *endpoint) | ||
| 206 | { | ||
| 207 | |||
| 208 | if (endpoint->kobj) { | ||
| 209 | kobject_del(endpoint->kobj); | ||
| 210 | kobject_put(endpoint->kobj); | ||
| 211 | endpoint->kobj = NULL; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | /* Active configuration fields */ | 18 | /* Active configuration fields */ |
| 216 | #define usb_actconfig_show(field, multiplier, format_string) \ | 19 | #define usb_actconfig_show(field, multiplier, format_string) \ |
| 217 | static ssize_t show_##field (struct device *dev, \ | 20 | static ssize_t show_##field (struct device *dev, \ |
| @@ -420,7 +223,7 @@ void usb_create_sysfs_dev_files (struct usb_device *udev) | |||
| 420 | if (udev->serial) | 223 | if (udev->serial) |
| 421 | device_create_file (dev, &dev_attr_serial); | 224 | device_create_file (dev, &dev_attr_serial); |
| 422 | device_create_file (dev, &dev_attr_configuration); | 225 | device_create_file (dev, &dev_attr_configuration); |
| 423 | usb_create_ep_files(&dev->kobj, &udev->ep0, udev); | 226 | usb_create_ep_files(dev, &udev->ep0, udev); |
| 424 | } | 227 | } |
| 425 | 228 | ||
| 426 | void usb_remove_sysfs_dev_files (struct usb_device *udev) | 229 | void usb_remove_sysfs_dev_files (struct usb_device *udev) |
| @@ -524,7 +327,7 @@ static inline void usb_create_intf_ep_files(struct usb_interface *intf, | |||
| 524 | 327 | ||
| 525 | iface_desc = intf->cur_altsetting; | 328 | iface_desc = intf->cur_altsetting; |
| 526 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) | 329 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) |
| 527 | usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i], | 330 | usb_create_ep_files(&intf->dev, &iface_desc->endpoint[i], |
| 528 | udev); | 331 | udev); |
| 529 | } | 332 | } |
| 530 | 333 | ||
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index b7fdc1cd134a..515310751303 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c | |||
| @@ -1207,6 +1207,7 @@ EXPORT_SYMBOL(usb_ifnum_to_if); | |||
| 1207 | EXPORT_SYMBOL(usb_altnum_to_altsetting); | 1207 | EXPORT_SYMBOL(usb_altnum_to_altsetting); |
| 1208 | 1208 | ||
| 1209 | EXPORT_SYMBOL(usb_reset_device); | 1209 | EXPORT_SYMBOL(usb_reset_device); |
| 1210 | EXPORT_SYMBOL(usb_reset_composite_device); | ||
| 1210 | 1211 | ||
| 1211 | EXPORT_SYMBOL(__usb_get_extra_descriptor); | 1212 | EXPORT_SYMBOL(__usb_get_extra_descriptor); |
| 1212 | 1213 | ||
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 4647e1ebc68d..7a650c763a62 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h | |||
| @@ -4,6 +4,9 @@ extern void usb_create_sysfs_dev_files (struct usb_device *dev); | |||
| 4 | extern void usb_remove_sysfs_dev_files (struct usb_device *dev); | 4 | extern void usb_remove_sysfs_dev_files (struct usb_device *dev); |
| 5 | extern void usb_create_sysfs_intf_files (struct usb_interface *intf); | 5 | extern void usb_create_sysfs_intf_files (struct usb_interface *intf); |
| 6 | extern void usb_remove_sysfs_intf_files (struct usb_interface *intf); | 6 | extern void usb_remove_sysfs_intf_files (struct usb_interface *intf); |
| 7 | extern void usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint, | ||
| 8 | struct usb_device *udev); | ||
| 9 | extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint); | ||
| 7 | 10 | ||
| 8 | extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); | 11 | extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr); |
| 9 | extern void usb_disable_interface (struct usb_device *dev, | 12 | extern void usb_disable_interface (struct usb_device *dev, |
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 9c4422ac9de4..078daa026718 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c | |||
| @@ -49,7 +49,7 @@ | |||
| 49 | #include <asm/unaligned.h> | 49 | #include <asm/unaligned.h> |
| 50 | 50 | ||
| 51 | #include <linux/usb_ch9.h> | 51 | #include <linux/usb_ch9.h> |
| 52 | #include <linux/usb_cdc.h> | 52 | #include <linux/usb/cdc.h> |
| 53 | #include <linux/usb_gadget.h> | 53 | #include <linux/usb_gadget.h> |
| 54 | 54 | ||
| 55 | #include <linux/random.h> | 55 | #include <linux/random.h> |
| @@ -101,9 +101,9 @@ static const char driver_desc [] = DRIVER_DESC; | |||
| 101 | 101 | ||
| 102 | /* CDC and RNDIS support the same host-chosen outgoing packet filters. */ | 102 | /* CDC and RNDIS support the same host-chosen outgoing packet filters. */ |
| 103 | #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ | 103 | #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ |
| 104 | |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ | 104 | |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ |
| 105 | |USB_CDC_PACKET_TYPE_PROMISCUOUS \ | 105 | |USB_CDC_PACKET_TYPE_PROMISCUOUS \ |
| 106 | |USB_CDC_PACKET_TYPE_DIRECTED) | 106 | |USB_CDC_PACKET_TYPE_DIRECTED) |
| 107 | 107 | ||
| 108 | 108 | ||
| 109 | /*-------------------------------------------------------------------------*/ | 109 | /*-------------------------------------------------------------------------*/ |
| @@ -318,7 +318,7 @@ static inline int rndis_active(struct eth_dev *dev) | |||
| 318 | #define DEFAULT_QLEN 2 /* double buffering by default */ | 318 | #define DEFAULT_QLEN 2 /* double buffering by default */ |
| 319 | 319 | ||
| 320 | /* peak bulk transfer bits-per-second */ | 320 | /* peak bulk transfer bits-per-second */ |
| 321 | #define HS_BPS (13 * 512 * 8 * 1000 * 8) | 321 | #define HS_BPS (13 * 512 * 8 * 1000 * 8) |
| 322 | #define FS_BPS (19 * 64 * 1 * 1000 * 8) | 322 | #define FS_BPS (19 * 64 * 1 * 1000 * 8) |
| 323 | 323 | ||
| 324 | #ifdef CONFIG_USB_GADGET_DUALSPEED | 324 | #ifdef CONFIG_USB_GADGET_DUALSPEED |
| @@ -466,7 +466,7 @@ eth_config = { | |||
| 466 | }; | 466 | }; |
| 467 | 467 | ||
| 468 | #ifdef CONFIG_USB_ETH_RNDIS | 468 | #ifdef CONFIG_USB_ETH_RNDIS |
| 469 | static struct usb_config_descriptor | 469 | static struct usb_config_descriptor |
| 470 | rndis_config = { | 470 | rndis_config = { |
| 471 | .bLength = sizeof rndis_config, | 471 | .bLength = sizeof rndis_config, |
| 472 | .bDescriptorType = USB_DT_CONFIG, | 472 | .bDescriptorType = USB_DT_CONFIG, |
| @@ -511,7 +511,7 @@ static const struct usb_interface_descriptor | |||
| 511 | rndis_control_intf = { | 511 | rndis_control_intf = { |
| 512 | .bLength = sizeof rndis_control_intf, | 512 | .bLength = sizeof rndis_control_intf, |
| 513 | .bDescriptorType = USB_DT_INTERFACE, | 513 | .bDescriptorType = USB_DT_INTERFACE, |
| 514 | 514 | ||
| 515 | .bInterfaceNumber = 0, | 515 | .bInterfaceNumber = 0, |
| 516 | .bNumEndpoints = 1, | 516 | .bNumEndpoints = 1, |
| 517 | .bInterfaceClass = USB_CLASS_COMM, | 517 | .bInterfaceClass = USB_CLASS_COMM, |
| @@ -545,20 +545,20 @@ static const struct usb_cdc_union_desc union_desc = { | |||
| 545 | #ifdef CONFIG_USB_ETH_RNDIS | 545 | #ifdef CONFIG_USB_ETH_RNDIS |
| 546 | 546 | ||
| 547 | static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { | 547 | static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { |
| 548 | .bLength = sizeof call_mgmt_descriptor, | 548 | .bLength = sizeof call_mgmt_descriptor, |
| 549 | .bDescriptorType = USB_DT_CS_INTERFACE, | 549 | .bDescriptorType = USB_DT_CS_INTERFACE, |
| 550 | .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, | 550 | .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, |
| 551 | 551 | ||
| 552 | .bmCapabilities = 0x00, | 552 | .bmCapabilities = 0x00, |
| 553 | .bDataInterface = 0x01, | 553 | .bDataInterface = 0x01, |
| 554 | }; | 554 | }; |
| 555 | 555 | ||
| 556 | static const struct usb_cdc_acm_descriptor acm_descriptor = { | 556 | static const struct usb_cdc_acm_descriptor acm_descriptor = { |
| 557 | .bLength = sizeof acm_descriptor, | 557 | .bLength = sizeof acm_descriptor, |
| 558 | .bDescriptorType = USB_DT_CS_INTERFACE, | 558 | .bDescriptorType = USB_DT_CS_INTERFACE, |
| 559 | .bDescriptorSubType = USB_CDC_ACM_TYPE, | 559 | .bDescriptorSubType = USB_CDC_ACM_TYPE, |
| 560 | 560 | ||
| 561 | .bmCapabilities = 0x00, | 561 | .bmCapabilities = 0x00, |
| 562 | }; | 562 | }; |
| 563 | 563 | ||
| 564 | #endif | 564 | #endif |
| @@ -595,7 +595,7 @@ static const struct usb_cdc_ether_desc ether_desc = { | |||
| 595 | * RNDIS requires the status endpoint, since it uses that encapsulation | 595 | * RNDIS requires the status endpoint, since it uses that encapsulation |
| 596 | * mechanism for its funky RPC scheme. | 596 | * mechanism for its funky RPC scheme. |
| 597 | */ | 597 | */ |
| 598 | 598 | ||
| 599 | #define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ | 599 | #define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ |
| 600 | #define STATUS_BYTECOUNT 16 /* 8 byte header + data */ | 600 | #define STATUS_BYTECOUNT 16 /* 8 byte header + data */ |
| 601 | 601 | ||
| @@ -978,7 +978,7 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags) | |||
| 978 | 978 | ||
| 979 | result = usb_ep_enable (dev->status_ep, dev->status); | 979 | result = usb_ep_enable (dev->status_ep, dev->status); |
| 980 | if (result != 0) { | 980 | if (result != 0) { |
| 981 | DEBUG (dev, "enable %s --> %d\n", | 981 | DEBUG (dev, "enable %s --> %d\n", |
| 982 | dev->status_ep->name, result); | 982 | dev->status_ep->name, result); |
| 983 | goto done; | 983 | goto done; |
| 984 | } | 984 | } |
| @@ -1002,15 +1002,15 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags) | |||
| 1002 | if (!cdc_active(dev)) { | 1002 | if (!cdc_active(dev)) { |
| 1003 | result = usb_ep_enable (dev->in_ep, dev->in); | 1003 | result = usb_ep_enable (dev->in_ep, dev->in); |
| 1004 | if (result != 0) { | 1004 | if (result != 0) { |
| 1005 | DEBUG(dev, "enable %s --> %d\n", | 1005 | DEBUG(dev, "enable %s --> %d\n", |
| 1006 | dev->in_ep->name, result); | 1006 | dev->in_ep->name, result); |
| 1007 | goto done; | 1007 | goto done; |
| 1008 | } | 1008 | } |
| 1009 | 1009 | ||
| 1010 | result = usb_ep_enable (dev->out_ep, dev->out); | 1010 | result = usb_ep_enable (dev->out_ep, dev->out); |
| 1011 | if (result != 0) { | 1011 | if (result != 0) { |
| 1012 | DEBUG (dev, "enable %s --> %d\n", | 1012 | DEBUG (dev, "enable %s --> %d\n", |
| 1013 | dev->in_ep->name, result); | 1013 | dev->out_ep->name, result); |
| 1014 | goto done; | 1014 | goto done; |
| 1015 | } | 1015 | } |
| 1016 | } | 1016 | } |
| @@ -1144,7 +1144,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags) | |||
| 1144 | #ifdef CONFIG_USB_GADGET_DUALSPEED | 1144 | #ifdef CONFIG_USB_GADGET_DUALSPEED |
| 1145 | case USB_SPEED_HIGH: speed = "high"; break; | 1145 | case USB_SPEED_HIGH: speed = "high"; break; |
| 1146 | #endif | 1146 | #endif |
| 1147 | default: speed = "?"; break; | 1147 | default: speed = "?"; break; |
| 1148 | } | 1148 | } |
| 1149 | 1149 | ||
| 1150 | dev->config = number; | 1150 | dev->config = number; |
| @@ -1206,7 +1206,7 @@ static void issue_start_status (struct eth_dev *dev) | |||
| 1206 | struct usb_request *req = dev->stat_req; | 1206 | struct usb_request *req = dev->stat_req; |
| 1207 | struct usb_cdc_notification *event; | 1207 | struct usb_cdc_notification *event; |
| 1208 | int value; | 1208 | int value; |
| 1209 | 1209 | ||
| 1210 | DEBUG (dev, "%s, flush old status first\n", __FUNCTION__); | 1210 | DEBUG (dev, "%s, flush old status first\n", __FUNCTION__); |
| 1211 | 1211 | ||
| 1212 | /* flush old status | 1212 | /* flush old status |
| @@ -1268,7 +1268,7 @@ static void rndis_command_complete (struct usb_ep *ep, struct usb_request *req) | |||
| 1268 | { | 1268 | { |
| 1269 | struct eth_dev *dev = ep->driver_data; | 1269 | struct eth_dev *dev = ep->driver_data; |
| 1270 | int status; | 1270 | int status; |
| 1271 | 1271 | ||
| 1272 | /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ | 1272 | /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ |
| 1273 | spin_lock(&dev->lock); | 1273 | spin_lock(&dev->lock); |
| 1274 | status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf); | 1274 | status = rndis_msg_parser (dev->rndis_config, (u8 *) req->buf); |
| @@ -1472,7 +1472,7 @@ done_set_intf: | |||
| 1472 | 1472 | ||
| 1473 | #endif /* DEV_CONFIG_CDC */ | 1473 | #endif /* DEV_CONFIG_CDC */ |
| 1474 | 1474 | ||
| 1475 | #ifdef CONFIG_USB_ETH_RNDIS | 1475 | #ifdef CONFIG_USB_ETH_RNDIS |
| 1476 | /* RNDIS uses the CDC command encapsulation mechanism to implement | 1476 | /* RNDIS uses the CDC command encapsulation mechanism to implement |
| 1477 | * an RPC scheme, with much getting/setting of attributes by OID. | 1477 | * an RPC scheme, with much getting/setting of attributes by OID. |
| 1478 | */ | 1478 | */ |
| @@ -1489,7 +1489,7 @@ done_set_intf: | |||
| 1489 | req->complete = rndis_command_complete; | 1489 | req->complete = rndis_command_complete; |
| 1490 | /* later, rndis_control_ack () sends a notification */ | 1490 | /* later, rndis_control_ack () sends a notification */ |
| 1491 | break; | 1491 | break; |
| 1492 | 1492 | ||
| 1493 | case USB_CDC_GET_ENCAPSULATED_RESPONSE: | 1493 | case USB_CDC_GET_ENCAPSULATED_RESPONSE: |
| 1494 | if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE) | 1494 | if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE) |
| 1495 | == ctrl->bRequestType | 1495 | == ctrl->bRequestType |
| @@ -1641,7 +1641,7 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) | |||
| 1641 | DEBUG (dev, "no rx skb\n"); | 1641 | DEBUG (dev, "no rx skb\n"); |
| 1642 | goto enomem; | 1642 | goto enomem; |
| 1643 | } | 1643 | } |
| 1644 | 1644 | ||
| 1645 | /* Some platforms perform better when IP packets are aligned, | 1645 | /* Some platforms perform better when IP packets are aligned, |
| 1646 | * but on at least one, checksumming fails otherwise. Note: | 1646 | * but on at least one, checksumming fails otherwise. Note: |
| 1647 | * RNDIS headers involve variable numbers of LE32 values. | 1647 | * RNDIS headers involve variable numbers of LE32 values. |
| @@ -1720,7 +1720,7 @@ quiesce: | |||
| 1720 | case -EOVERFLOW: | 1720 | case -EOVERFLOW: |
| 1721 | dev->stats.rx_over_errors++; | 1721 | dev->stats.rx_over_errors++; |
| 1722 | // FALLTHROUGH | 1722 | // FALLTHROUGH |
| 1723 | 1723 | ||
| 1724 | default: | 1724 | default: |
| 1725 | dev->stats.rx_errors++; | 1725 | dev->stats.rx_errors++; |
| 1726 | DEBUG (dev, "rx status %d\n", status); | 1726 | DEBUG (dev, "rx status %d\n", status); |
| @@ -1915,7 +1915,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) | |||
| 1915 | sizeof (struct rndis_packet_msg_type)); | 1915 | sizeof (struct rndis_packet_msg_type)); |
| 1916 | if (!skb_rndis) | 1916 | if (!skb_rndis) |
| 1917 | goto drop; | 1917 | goto drop; |
| 1918 | 1918 | ||
| 1919 | dev_kfree_skb_any (skb); | 1919 | dev_kfree_skb_any (skb); |
| 1920 | skb = skb_rndis; | 1920 | skb = skb_rndis; |
| 1921 | rndis_add_hdr (skb); | 1921 | rndis_add_hdr (skb); |
| @@ -2001,7 +2001,7 @@ static int rndis_control_ack (struct net_device *net) | |||
| 2001 | struct eth_dev *dev = netdev_priv(net); | 2001 | struct eth_dev *dev = netdev_priv(net); |
| 2002 | u32 length; | 2002 | u32 length; |
| 2003 | struct usb_request *resp = dev->stat_req; | 2003 | struct usb_request *resp = dev->stat_req; |
| 2004 | 2004 | ||
| 2005 | /* in case RNDIS calls this after disconnect */ | 2005 | /* in case RNDIS calls this after disconnect */ |
| 2006 | if (!dev->status) { | 2006 | if (!dev->status) { |
| 2007 | DEBUG (dev, "status ENODEV\n"); | 2007 | DEBUG (dev, "status ENODEV\n"); |
| @@ -2021,16 +2021,16 @@ static int rndis_control_ack (struct net_device *net) | |||
| 2021 | resp->length = 8; | 2021 | resp->length = 8; |
| 2022 | resp->complete = rndis_control_ack_complete; | 2022 | resp->complete = rndis_control_ack_complete; |
| 2023 | resp->context = dev; | 2023 | resp->context = dev; |
| 2024 | 2024 | ||
| 2025 | *((__le32 *) resp->buf) = __constant_cpu_to_le32 (1); | 2025 | *((__le32 *) resp->buf) = __constant_cpu_to_le32 (1); |
| 2026 | *((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0); | 2026 | *((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0); |
| 2027 | 2027 | ||
| 2028 | length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC); | 2028 | length = usb_ep_queue (dev->status_ep, resp, GFP_ATOMIC); |
| 2029 | if (length < 0) { | 2029 | if (length < 0) { |
| 2030 | resp->status = 0; | 2030 | resp->status = 0; |
| 2031 | rndis_control_ack_complete (dev->status_ep, resp); | 2031 | rndis_control_ack_complete (dev->status_ep, resp); |
| 2032 | } | 2032 | } |
| 2033 | 2033 | ||
| 2034 | return 0; | 2034 | return 0; |
| 2035 | } | 2035 | } |
| 2036 | 2036 | ||
| @@ -2047,7 +2047,7 @@ static void eth_start (struct eth_dev *dev, gfp_t gfp_flags) | |||
| 2047 | /* fill the rx queue */ | 2047 | /* fill the rx queue */ |
| 2048 | rx_fill (dev, gfp_flags); | 2048 | rx_fill (dev, gfp_flags); |
| 2049 | 2049 | ||
| 2050 | /* and open the tx floodgates */ | 2050 | /* and open the tx floodgates */ |
| 2051 | atomic_set (&dev->tx_qlen, 0); | 2051 | atomic_set (&dev->tx_qlen, 0); |
| 2052 | netif_wake_queue (dev->net); | 2052 | netif_wake_queue (dev->net); |
| 2053 | if (rndis_active(dev)) { | 2053 | if (rndis_active(dev)) { |
| @@ -2076,7 +2076,7 @@ static int eth_stop (struct net_device *net) | |||
| 2076 | netif_stop_queue (net); | 2076 | netif_stop_queue (net); |
| 2077 | 2077 | ||
| 2078 | DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", | 2078 | DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", |
| 2079 | dev->stats.rx_packets, dev->stats.tx_packets, | 2079 | dev->stats.rx_packets, dev->stats.tx_packets, |
| 2080 | dev->stats.rx_errors, dev->stats.tx_errors | 2080 | dev->stats.rx_errors, dev->stats.tx_errors |
| 2081 | ); | 2081 | ); |
| 2082 | 2082 | ||
| @@ -2095,7 +2095,7 @@ static int eth_stop (struct net_device *net) | |||
| 2095 | usb_ep_enable (dev->status_ep, dev->status); | 2095 | usb_ep_enable (dev->status_ep, dev->status); |
| 2096 | } | 2096 | } |
| 2097 | } | 2097 | } |
| 2098 | 2098 | ||
| 2099 | if (rndis_active(dev)) { | 2099 | if (rndis_active(dev)) { |
| 2100 | rndis_set_param_medium (dev->rndis_config, | 2100 | rndis_set_param_medium (dev->rndis_config, |
| 2101 | NDIS_MEDIUM_802_3, 0); | 2101 | NDIS_MEDIUM_802_3, 0); |
| @@ -2301,7 +2301,7 @@ autoconf_fail: | |||
| 2301 | return -ENODEV; | 2301 | return -ENODEV; |
| 2302 | } | 2302 | } |
| 2303 | in_ep->driver_data = in_ep; /* claim */ | 2303 | in_ep->driver_data = in_ep; /* claim */ |
| 2304 | 2304 | ||
| 2305 | out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc); | 2305 | out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc); |
| 2306 | if (!out_ep) | 2306 | if (!out_ep) |
| 2307 | goto autoconf_fail; | 2307 | goto autoconf_fail; |
| @@ -2374,8 +2374,8 @@ autoconf_fail: | |||
| 2374 | #endif | 2374 | #endif |
| 2375 | } | 2375 | } |
| 2376 | 2376 | ||
| 2377 | net = alloc_etherdev (sizeof *dev); | 2377 | net = alloc_etherdev (sizeof *dev); |
| 2378 | if (!net) | 2378 | if (!net) |
| 2379 | return status; | 2379 | return status; |
| 2380 | dev = netdev_priv(net); | 2380 | dev = netdev_priv(net); |
| 2381 | spin_lock_init (&dev->lock); | 2381 | spin_lock_init (&dev->lock); |
| @@ -2454,7 +2454,7 @@ autoconf_fail: | |||
| 2454 | dev->gadget = gadget; | 2454 | dev->gadget = gadget; |
| 2455 | set_gadget_data (gadget, dev); | 2455 | set_gadget_data (gadget, dev); |
| 2456 | gadget->ep0->driver_data = dev; | 2456 | gadget->ep0->driver_data = dev; |
| 2457 | 2457 | ||
| 2458 | /* two kinds of host-initiated state changes: | 2458 | /* two kinds of host-initiated state changes: |
| 2459 | * - iff DATA transfer is active, carrier is "on" | 2459 | * - iff DATA transfer is active, carrier is "on" |
| 2460 | * - tx queueing enabled if open *and* carrier is "on" | 2460 | * - tx queueing enabled if open *and* carrier is "on" |
| @@ -2462,8 +2462,8 @@ autoconf_fail: | |||
| 2462 | netif_stop_queue (dev->net); | 2462 | netif_stop_queue (dev->net); |
| 2463 | netif_carrier_off (dev->net); | 2463 | netif_carrier_off (dev->net); |
| 2464 | 2464 | ||
| 2465 | SET_NETDEV_DEV (dev->net, &gadget->dev); | 2465 | SET_NETDEV_DEV (dev->net, &gadget->dev); |
| 2466 | status = register_netdev (dev->net); | 2466 | status = register_netdev (dev->net); |
| 2467 | if (status < 0) | 2467 | if (status < 0) |
| 2468 | goto fail1; | 2468 | goto fail1; |
| 2469 | 2469 | ||
| @@ -2488,7 +2488,7 @@ autoconf_fail: | |||
| 2488 | u32 vendorID = 0; | 2488 | u32 vendorID = 0; |
| 2489 | 2489 | ||
| 2490 | /* FIXME RNDIS vendor id == "vendor NIC code" == ? */ | 2490 | /* FIXME RNDIS vendor id == "vendor NIC code" == ? */ |
| 2491 | 2491 | ||
| 2492 | dev->rndis_config = rndis_register (rndis_control_ack); | 2492 | dev->rndis_config = rndis_register (rndis_control_ack); |
| 2493 | if (dev->rndis_config < 0) { | 2493 | if (dev->rndis_config < 0) { |
| 2494 | fail0: | 2494 | fail0: |
| @@ -2496,7 +2496,7 @@ fail0: | |||
| 2496 | status = -ENODEV; | 2496 | status = -ENODEV; |
| 2497 | goto fail; | 2497 | goto fail; |
| 2498 | } | 2498 | } |
| 2499 | 2499 | ||
| 2500 | /* these set up a lot of the OIDs that RNDIS needs */ | 2500 | /* these set up a lot of the OIDs that RNDIS needs */ |
| 2501 | rndis_set_host_mac (dev->rndis_config, dev->host_mac); | 2501 | rndis_set_host_mac (dev->rndis_config, dev->host_mac); |
| 2502 | if (rndis_set_param_dev (dev->rndis_config, dev->net, | 2502 | if (rndis_set_param_dev (dev->rndis_config, dev->net, |
| @@ -2556,7 +2556,7 @@ static struct usb_gadget_driver eth_driver = { | |||
| 2556 | .suspend = eth_suspend, | 2556 | .suspend = eth_suspend, |
| 2557 | .resume = eth_resume, | 2557 | .resume = eth_resume, |
| 2558 | 2558 | ||
| 2559 | .driver = { | 2559 | .driver = { |
| 2560 | .name = (char *) shortname, | 2560 | .name = (char *) shortname, |
| 2561 | .owner = THIS_MODULE, | 2561 | .owner = THIS_MODULE, |
| 2562 | }, | 2562 | }, |
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 0eb010a3f5bc..aef0722b8f17 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c | |||
| @@ -528,7 +528,7 @@ struct kiocb_priv { | |||
| 528 | struct usb_request *req; | 528 | struct usb_request *req; |
| 529 | struct ep_data *epdata; | 529 | struct ep_data *epdata; |
| 530 | void *buf; | 530 | void *buf; |
| 531 | char __user *ubuf; | 531 | char __user *ubuf; /* NULL for writes */ |
| 532 | unsigned actual; | 532 | unsigned actual; |
| 533 | }; | 533 | }; |
| 534 | 534 | ||
| @@ -566,7 +566,6 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) | |||
| 566 | status = priv->actual; | 566 | status = priv->actual; |
| 567 | kfree(priv->buf); | 567 | kfree(priv->buf); |
| 568 | kfree(priv); | 568 | kfree(priv); |
| 569 | aio_put_req(iocb); | ||
| 570 | return status; | 569 | return status; |
| 571 | } | 570 | } |
| 572 | 571 | ||
| @@ -580,8 +579,8 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) | |||
| 580 | spin_lock(&epdata->dev->lock); | 579 | spin_lock(&epdata->dev->lock); |
| 581 | priv->req = NULL; | 580 | priv->req = NULL; |
| 582 | priv->epdata = NULL; | 581 | priv->epdata = NULL; |
| 583 | if (NULL == iocb->ki_retry | 582 | if (priv->ubuf == NULL |
| 584 | || unlikely(0 == req->actual) | 583 | || unlikely(req->actual == 0) |
| 585 | || unlikely(kiocbIsCancelled(iocb))) { | 584 | || unlikely(kiocbIsCancelled(iocb))) { |
| 586 | kfree(req->buf); | 585 | kfree(req->buf); |
| 587 | kfree(priv); | 586 | kfree(priv); |
| @@ -618,7 +617,7 @@ ep_aio_rwtail( | |||
| 618 | char __user *ubuf | 617 | char __user *ubuf |
| 619 | ) | 618 | ) |
| 620 | { | 619 | { |
| 621 | struct kiocb_priv *priv = (void *) &iocb->private; | 620 | struct kiocb_priv *priv; |
| 622 | struct usb_request *req; | 621 | struct usb_request *req; |
| 623 | ssize_t value; | 622 | ssize_t value; |
| 624 | 623 | ||
| @@ -670,7 +669,7 @@ fail: | |||
| 670 | kfree(priv); | 669 | kfree(priv); |
| 671 | put_ep(epdata); | 670 | put_ep(epdata); |
| 672 | } else | 671 | } else |
| 673 | value = -EIOCBQUEUED; | 672 | value = (ubuf ? -EIOCBRETRY : -EIOCBQUEUED); |
| 674 | return value; | 673 | return value; |
| 675 | } | 674 | } |
| 676 | 675 | ||
| @@ -1039,7 +1038,7 @@ scan: | |||
| 1039 | /* ep0 can't deliver events when STATE_SETUP */ | 1038 | /* ep0 can't deliver events when STATE_SETUP */ |
| 1040 | for (i = 0; i < n; i++) { | 1039 | for (i = 0; i < n; i++) { |
| 1041 | if (dev->event [i].type == GADGETFS_SETUP) { | 1040 | if (dev->event [i].type == GADGETFS_SETUP) { |
| 1042 | len = n = i + 1; | 1041 | len = i + 1; |
| 1043 | len *= sizeof (struct usb_gadgetfs_event); | 1042 | len *= sizeof (struct usb_gadgetfs_event); |
| 1044 | n = 0; | 1043 | n = 0; |
| 1045 | break; | 1044 | break; |
| @@ -1587,13 +1586,13 @@ gadgetfs_create_file (struct super_block *sb, char const *name, | |||
| 1587 | static int activate_ep_files (struct dev_data *dev) | 1586 | static int activate_ep_files (struct dev_data *dev) |
| 1588 | { | 1587 | { |
| 1589 | struct usb_ep *ep; | 1588 | struct usb_ep *ep; |
| 1589 | struct ep_data *data; | ||
| 1590 | 1590 | ||
| 1591 | gadget_for_each_ep (ep, dev->gadget) { | 1591 | gadget_for_each_ep (ep, dev->gadget) { |
| 1592 | struct ep_data *data; | ||
| 1593 | 1592 | ||
| 1594 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 1593 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
| 1595 | if (!data) | 1594 | if (!data) |
| 1596 | goto enomem; | 1595 | goto enomem0; |
| 1597 | data->state = STATE_EP_DISABLED; | 1596 | data->state = STATE_EP_DISABLED; |
| 1598 | init_MUTEX (&data->lock); | 1597 | init_MUTEX (&data->lock); |
| 1599 | init_waitqueue_head (&data->wait); | 1598 | init_waitqueue_head (&data->wait); |
| @@ -1608,21 +1607,23 @@ static int activate_ep_files (struct dev_data *dev) | |||
| 1608 | 1607 | ||
| 1609 | data->req = usb_ep_alloc_request (ep, GFP_KERNEL); | 1608 | data->req = usb_ep_alloc_request (ep, GFP_KERNEL); |
| 1610 | if (!data->req) | 1609 | if (!data->req) |
| 1611 | goto enomem; | 1610 | goto enomem1; |
| 1612 | 1611 | ||
| 1613 | data->inode = gadgetfs_create_file (dev->sb, data->name, | 1612 | data->inode = gadgetfs_create_file (dev->sb, data->name, |
| 1614 | data, &ep_config_operations, | 1613 | data, &ep_config_operations, |
| 1615 | &data->dentry); | 1614 | &data->dentry); |
| 1616 | if (!data->inode) { | 1615 | if (!data->inode) |
| 1617 | usb_ep_free_request(ep, data->req); | 1616 | goto enomem2; |
| 1618 | kfree (data); | ||
| 1619 | goto enomem; | ||
| 1620 | } | ||
| 1621 | list_add_tail (&data->epfiles, &dev->epfiles); | 1617 | list_add_tail (&data->epfiles, &dev->epfiles); |
| 1622 | } | 1618 | } |
| 1623 | return 0; | 1619 | return 0; |
| 1624 | 1620 | ||
| 1625 | enomem: | 1621 | enomem2: |
| 1622 | usb_ep_free_request (ep, data->req); | ||
| 1623 | enomem1: | ||
| 1624 | put_dev (dev); | ||
| 1625 | kfree (data); | ||
| 1626 | enomem0: | ||
| 1626 | DBG (dev, "%s enomem\n", __FUNCTION__); | 1627 | DBG (dev, "%s enomem\n", __FUNCTION__); |
| 1627 | destroy_ep_files (dev); | 1628 | destroy_ep_files (dev); |
| 1628 | return -ENOMEM; | 1629 | return -ENOMEM; |
| @@ -1793,7 +1794,7 @@ static struct usb_gadget_driver probe_driver = { | |||
| 1793 | * | 1794 | * |
| 1794 | * After initialization, the device stays active for as long as that | 1795 | * After initialization, the device stays active for as long as that |
| 1795 | * $CHIP file is open. Events may then be read from that descriptor, | 1796 | * $CHIP file is open. Events may then be read from that descriptor, |
| 1796 | * such configuration notifications. More complex drivers will handle | 1797 | * such as configuration notifications. More complex drivers will handle |
| 1797 | * some control requests in user space. | 1798 | * some control requests in user space. |
| 1798 | */ | 1799 | */ |
| 1799 | 1800 | ||
| @@ -2033,12 +2034,10 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) | |||
| 2033 | NULL, &simple_dir_operations, | 2034 | NULL, &simple_dir_operations, |
| 2034 | S_IFDIR | S_IRUGO | S_IXUGO); | 2035 | S_IFDIR | S_IRUGO | S_IXUGO); |
| 2035 | if (!inode) | 2036 | if (!inode) |
| 2036 | return -ENOMEM; | 2037 | goto enomem0; |
| 2037 | inode->i_op = &simple_dir_inode_operations; | 2038 | inode->i_op = &simple_dir_inode_operations; |
| 2038 | if (!(d = d_alloc_root (inode))) { | 2039 | if (!(d = d_alloc_root (inode))) |
| 2039 | iput (inode); | 2040 | goto enomem1; |
| 2040 | return -ENOMEM; | ||
| 2041 | } | ||
| 2042 | sb->s_root = d; | 2041 | sb->s_root = d; |
| 2043 | 2042 | ||
| 2044 | /* the ep0 file is named after the controller we expect; | 2043 | /* the ep0 file is named after the controller we expect; |
| @@ -2046,21 +2045,28 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) | |||
| 2046 | */ | 2045 | */ |
| 2047 | dev = dev_new (); | 2046 | dev = dev_new (); |
| 2048 | if (!dev) | 2047 | if (!dev) |
| 2049 | return -ENOMEM; | 2048 | goto enomem2; |
| 2050 | 2049 | ||
| 2051 | dev->sb = sb; | 2050 | dev->sb = sb; |
| 2052 | if (!(inode = gadgetfs_create_file (sb, CHIP, | 2051 | if (!gadgetfs_create_file (sb, CHIP, |
| 2053 | dev, &dev_init_operations, | 2052 | dev, &dev_init_operations, |
| 2054 | &dev->dentry))) { | 2053 | &dev->dentry)) |
| 2055 | put_dev(dev); | 2054 | goto enomem3; |
| 2056 | return -ENOMEM; | ||
| 2057 | } | ||
| 2058 | 2055 | ||
| 2059 | /* other endpoint files are available after hardware setup, | 2056 | /* other endpoint files are available after hardware setup, |
| 2060 | * from binding to a controller. | 2057 | * from binding to a controller. |
| 2061 | */ | 2058 | */ |
| 2062 | the_device = dev; | 2059 | the_device = dev; |
| 2063 | return 0; | 2060 | return 0; |
| 2061 | |||
| 2062 | enomem3: | ||
| 2063 | put_dev (dev); | ||
| 2064 | enomem2: | ||
| 2065 | dput (d); | ||
| 2066 | enomem1: | ||
| 2067 | iput (inode); | ||
| 2068 | enomem0: | ||
| 2069 | return -ENOMEM; | ||
| 2064 | } | 2070 | } |
| 2065 | 2071 | ||
| 2066 | /* "mount -t gadgetfs path /dev/gadget" ends up here */ | 2072 | /* "mount -t gadgetfs path /dev/gadget" ends up here */ |
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 020d3c42b1af..1facdea56a8a 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c | |||
| @@ -2966,6 +2966,22 @@ done: | |||
| 2966 | return retval; | 2966 | return retval; |
| 2967 | } | 2967 | } |
| 2968 | 2968 | ||
| 2969 | /* make sure the board is quiescent; otherwise it will continue | ||
| 2970 | * generating IRQs across the upcoming reboot. | ||
| 2971 | */ | ||
| 2972 | |||
| 2973 | static void net2280_shutdown (struct pci_dev *pdev) | ||
| 2974 | { | ||
| 2975 | struct net2280 *dev = pci_get_drvdata (pdev); | ||
| 2976 | |||
| 2977 | /* disable IRQs */ | ||
| 2978 | writel (0, &dev->regs->pciirqenb0); | ||
| 2979 | writel (0, &dev->regs->pciirqenb1); | ||
| 2980 | |||
| 2981 | /* disable the pullup so the host will think we're gone */ | ||
| 2982 | writel (0, &dev->usb->usbctl); | ||
| 2983 | } | ||
| 2984 | |||
| 2969 | 2985 | ||
| 2970 | /*-------------------------------------------------------------------------*/ | 2986 | /*-------------------------------------------------------------------------*/ |
| 2971 | 2987 | ||
| @@ -2995,6 +3011,7 @@ static struct pci_driver net2280_pci_driver = { | |||
| 2995 | 3011 | ||
| 2996 | .probe = net2280_probe, | 3012 | .probe = net2280_probe, |
| 2997 | .remove = net2280_remove, | 3013 | .remove = net2280_remove, |
| 3014 | .shutdown = net2280_shutdown, | ||
| 2998 | 3015 | ||
| 2999 | /* FIXME add power management support */ | 3016 | /* FIXME add power management support */ |
| 3000 | }; | 3017 | }; |
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 680f7fc5b171..269ce7f4ad66 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c | |||
| @@ -53,12 +53,14 @@ | |||
| 53 | #include <asm/mach-types.h> | 53 | #include <asm/mach-types.h> |
| 54 | #include <asm/unaligned.h> | 54 | #include <asm/unaligned.h> |
| 55 | #include <asm/hardware.h> | 55 | #include <asm/hardware.h> |
| 56 | #ifdef CONFIG_ARCH_PXA | ||
| 56 | #include <asm/arch/pxa-regs.h> | 57 | #include <asm/arch/pxa-regs.h> |
| 58 | #endif | ||
| 57 | 59 | ||
| 58 | #include <linux/usb_ch9.h> | 60 | #include <linux/usb_ch9.h> |
| 59 | #include <linux/usb_gadget.h> | 61 | #include <linux/usb_gadget.h> |
| 60 | 62 | ||
| 61 | #include <asm/arch/udc.h> | 63 | #include <asm/arch/hardware/intel_udc.h> |
| 62 | 64 | ||
| 63 | 65 | ||
| 64 | /* | 66 | /* |
| @@ -545,6 +547,7 @@ write_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req) | |||
| 545 | count = req->req.length; | 547 | count = req->req.length; |
| 546 | done (ep, req, 0); | 548 | done (ep, req, 0); |
| 547 | ep0_idle(ep->dev); | 549 | ep0_idle(ep->dev); |
| 550 | #ifndef CONFIG_ARCH_IXP4XX | ||
| 548 | #if 1 | 551 | #if 1 |
| 549 | /* This seems to get rid of lost status irqs in some cases: | 552 | /* This seems to get rid of lost status irqs in some cases: |
| 550 | * host responds quickly, or next request involves config | 553 | * host responds quickly, or next request involves config |
| @@ -565,6 +568,7 @@ write_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req) | |||
| 565 | } while (count); | 568 | } while (count); |
| 566 | } | 569 | } |
| 567 | #endif | 570 | #endif |
| 571 | #endif | ||
| 568 | } else if (ep->dev->req_pending) | 572 | } else if (ep->dev->req_pending) |
| 569 | ep0start(ep->dev, 0, "IN"); | 573 | ep0start(ep->dev, 0, "IN"); |
| 570 | return is_short; | 574 | return is_short; |
| @@ -1585,7 +1589,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) | |||
| 1585 | int retval; | 1589 | int retval; |
| 1586 | 1590 | ||
| 1587 | if (!driver | 1591 | if (!driver |
| 1588 | || driver->speed != USB_SPEED_FULL | 1592 | || driver->speed < USB_SPEED_FULL |
| 1589 | || !driver->bind | 1593 | || !driver->bind |
| 1590 | || !driver->unbind | 1594 | || !driver->unbind |
| 1591 | || !driver->disconnect | 1595 | || !driver->disconnect |
| @@ -2427,6 +2431,7 @@ static struct pxa2xx_udc memory = { | |||
| 2427 | #define PXA210_B1 0x00000123 | 2431 | #define PXA210_B1 0x00000123 |
| 2428 | #define PXA210_B0 0x00000122 | 2432 | #define PXA210_B0 0x00000122 |
| 2429 | #define IXP425_A0 0x000001c1 | 2433 | #define IXP425_A0 0x000001c1 |
| 2434 | #define IXP465_AD 0x00000200 | ||
| 2430 | 2435 | ||
| 2431 | /* | 2436 | /* |
| 2432 | * probe - binds to the platform device | 2437 | * probe - binds to the platform device |
| @@ -2463,6 +2468,8 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) | |||
| 2463 | break; | 2468 | break; |
| 2464 | #elif defined(CONFIG_ARCH_IXP4XX) | 2469 | #elif defined(CONFIG_ARCH_IXP4XX) |
| 2465 | case IXP425_A0: | 2470 | case IXP425_A0: |
| 2471 | case IXP465_AD: | ||
| 2472 | dev->has_cfr = 1; | ||
| 2466 | out_dma = 0; | 2473 | out_dma = 0; |
| 2467 | break; | 2474 | break; |
| 2468 | #endif | 2475 | #endif |
| @@ -2575,10 +2582,12 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev) | |||
| 2575 | free_irq(IRQ_USB, dev); | 2582 | free_irq(IRQ_USB, dev); |
| 2576 | dev->got_irq = 0; | 2583 | dev->got_irq = 0; |
| 2577 | } | 2584 | } |
| 2585 | #ifdef CONFIG_ARCH_LUBBOCK | ||
| 2578 | if (machine_is_lubbock()) { | 2586 | if (machine_is_lubbock()) { |
| 2579 | free_irq(LUBBOCK_USB_DISC_IRQ, dev); | 2587 | free_irq(LUBBOCK_USB_DISC_IRQ, dev); |
| 2580 | free_irq(LUBBOCK_USB_IRQ, dev); | 2588 | free_irq(LUBBOCK_USB_IRQ, dev); |
| 2581 | } | 2589 | } |
| 2590 | #endif | ||
| 2582 | platform_set_drvdata(pdev, NULL); | 2591 | platform_set_drvdata(pdev, NULL); |
| 2583 | the_controller = NULL; | 2592 | the_controller = NULL; |
| 2584 | return 0; | 2593 | return 0; |
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 6d6eaad73968..3ff6db7828a0 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c | |||
| @@ -1,23 +1,23 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * RNDIS MSG parser | 2 | * RNDIS MSG parser |
| 3 | * | 3 | * |
| 4 | * Version: $Id: rndis.c,v 1.19 2004/03/25 21:33:46 robert Exp $ | 4 | * Version: $Id: rndis.c,v 1.19 2004/03/25 21:33:46 robert Exp $ |
| 5 | * | 5 | * |
| 6 | * Authors: Benedikt Spranger, Pengutronix | 6 | * Authors: Benedikt Spranger, Pengutronix |
| 7 | * Robert Schwebel, Pengutronix | 7 | * Robert Schwebel, Pengutronix |
| 8 | * | 8 | * |
| 9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
| 11 | * version 2, as published by the Free Software Foundation. | 11 | * version 2, as published by the Free Software Foundation. |
| 12 | * | 12 | * |
| 13 | * This software was originally developed in conformance with | 13 | * This software was originally developed in conformance with |
| 14 | * Microsoft's Remote NDIS Specification License Agreement. | 14 | * Microsoft's Remote NDIS Specification License Agreement. |
| 15 | * | 15 | * |
| 16 | * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de> | 16 | * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de> |
| 17 | * Fixed message length bug in init_response | 17 | * Fixed message length bug in init_response |
| 18 | * | 18 | * |
| 19 | * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de> | 19 | * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de> |
| 20 | * Fixed rndis_rm_hdr length bug. | 20 | * Fixed rndis_rm_hdr length bug. |
| 21 | * | 21 | * |
| 22 | * Copyright (C) 2004 by David Brownell | 22 | * Copyright (C) 2004 by David Brownell |
| 23 | * updates to merge with Linux 2.6, better match RNDIS spec | 23 | * updates to merge with Linux 2.6, better match RNDIS spec |
| @@ -82,7 +82,7 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length); | |||
| 82 | 82 | ||
| 83 | 83 | ||
| 84 | /* supported OIDs */ | 84 | /* supported OIDs */ |
| 85 | static const u32 oid_supported_list [] = | 85 | static const u32 oid_supported_list [] = |
| 86 | { | 86 | { |
| 87 | /* the general stuff */ | 87 | /* the general stuff */ |
| 88 | OID_GEN_SUPPORTED_LIST, | 88 | OID_GEN_SUPPORTED_LIST, |
| @@ -103,7 +103,7 @@ static const u32 oid_supported_list [] = | |||
| 103 | #if 0 | 103 | #if 0 |
| 104 | OID_GEN_RNDIS_CONFIG_PARAMETER, | 104 | OID_GEN_RNDIS_CONFIG_PARAMETER, |
| 105 | #endif | 105 | #endif |
| 106 | 106 | ||
| 107 | /* the statistical stuff */ | 107 | /* the statistical stuff */ |
| 108 | OID_GEN_XMIT_OK, | 108 | OID_GEN_XMIT_OK, |
| 109 | OID_GEN_RCV_OK, | 109 | OID_GEN_RCV_OK, |
| @@ -127,14 +127,14 @@ static const u32 oid_supported_list [] = | |||
| 127 | OID_GEN_TRANSMIT_QUEUE_LENGTH, | 127 | OID_GEN_TRANSMIT_QUEUE_LENGTH, |
| 128 | #endif /* RNDIS_OPTIONAL_STATS */ | 128 | #endif /* RNDIS_OPTIONAL_STATS */ |
| 129 | 129 | ||
| 130 | /* mandatory 802.3 */ | 130 | /* mandatory 802.3 */ |
| 131 | /* the general stuff */ | 131 | /* the general stuff */ |
| 132 | OID_802_3_PERMANENT_ADDRESS, | 132 | OID_802_3_PERMANENT_ADDRESS, |
| 133 | OID_802_3_CURRENT_ADDRESS, | 133 | OID_802_3_CURRENT_ADDRESS, |
| 134 | OID_802_3_MULTICAST_LIST, | 134 | OID_802_3_MULTICAST_LIST, |
| 135 | OID_802_3_MAC_OPTIONS, | 135 | OID_802_3_MAC_OPTIONS, |
| 136 | OID_802_3_MAXIMUM_LIST_SIZE, | 136 | OID_802_3_MAXIMUM_LIST_SIZE, |
| 137 | 137 | ||
| 138 | /* the statistical stuff */ | 138 | /* the statistical stuff */ |
| 139 | OID_802_3_RCV_ERROR_ALIGNMENT, | 139 | OID_802_3_RCV_ERROR_ALIGNMENT, |
| 140 | OID_802_3_XMIT_ONE_COLLISION, | 140 | OID_802_3_XMIT_ONE_COLLISION, |
| @@ -172,8 +172,8 @@ static int | |||
| 172 | gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | 172 | gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, |
| 173 | rndis_resp_t *r) | 173 | rndis_resp_t *r) |
| 174 | { | 174 | { |
| 175 | int retval = -ENOTSUPP; | 175 | int retval = -ENOTSUPP; |
| 176 | u32 length = 4; /* usually */ | 176 | u32 length = 4; /* usually */ |
| 177 | __le32 *outbuf; | 177 | __le32 *outbuf; |
| 178 | int i, count; | 178 | int i, count; |
| 179 | rndis_query_cmplt_type *resp; | 179 | rndis_query_cmplt_type *resp; |
| @@ -211,27 +211,27 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 211 | outbuf[i] = cpu_to_le32 (oid_supported_list[i]); | 211 | outbuf[i] = cpu_to_le32 (oid_supported_list[i]); |
| 212 | retval = 0; | 212 | retval = 0; |
| 213 | break; | 213 | break; |
| 214 | 214 | ||
| 215 | /* mandatory */ | 215 | /* mandatory */ |
| 216 | case OID_GEN_HARDWARE_STATUS: | 216 | case OID_GEN_HARDWARE_STATUS: |
| 217 | DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__); | 217 | DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__); |
| 218 | /* Bogus question! | 218 | /* Bogus question! |
| 219 | * Hardware must be ready to receive high level protocols. | 219 | * Hardware must be ready to receive high level protocols. |
| 220 | * BTW: | 220 | * BTW: |
| 221 | * reddite ergo quae sunt Caesaris Caesari | 221 | * reddite ergo quae sunt Caesaris Caesari |
| 222 | * et quae sunt Dei Deo! | 222 | * et quae sunt Dei Deo! |
| 223 | */ | 223 | */ |
| 224 | *outbuf = __constant_cpu_to_le32 (0); | 224 | *outbuf = __constant_cpu_to_le32 (0); |
| 225 | retval = 0; | 225 | retval = 0; |
| 226 | break; | 226 | break; |
| 227 | 227 | ||
| 228 | /* mandatory */ | 228 | /* mandatory */ |
| 229 | case OID_GEN_MEDIA_SUPPORTED: | 229 | case OID_GEN_MEDIA_SUPPORTED: |
| 230 | DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__); | 230 | DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__); |
| 231 | *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); | 231 | *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); |
| 232 | retval = 0; | 232 | retval = 0; |
| 233 | break; | 233 | break; |
| 234 | 234 | ||
| 235 | /* mandatory */ | 235 | /* mandatory */ |
| 236 | case OID_GEN_MEDIA_IN_USE: | 236 | case OID_GEN_MEDIA_IN_USE: |
| 237 | DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__); | 237 | DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__); |
| @@ -239,7 +239,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 239 | *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); | 239 | *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium); |
| 240 | retval = 0; | 240 | retval = 0; |
| 241 | break; | 241 | break; |
| 242 | 242 | ||
| 243 | /* mandatory */ | 243 | /* mandatory */ |
| 244 | case OID_GEN_MAXIMUM_FRAME_SIZE: | 244 | case OID_GEN_MAXIMUM_FRAME_SIZE: |
| 245 | DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__); | 245 | DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__); |
| @@ -249,7 +249,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 249 | retval = 0; | 249 | retval = 0; |
| 250 | } | 250 | } |
| 251 | break; | 251 | break; |
| 252 | 252 | ||
| 253 | /* mandatory */ | 253 | /* mandatory */ |
| 254 | case OID_GEN_LINK_SPEED: | 254 | case OID_GEN_LINK_SPEED: |
| 255 | if (rndis_debug > 1) | 255 | if (rndis_debug > 1) |
| @@ -272,7 +272,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 272 | retval = 0; | 272 | retval = 0; |
| 273 | } | 273 | } |
| 274 | break; | 274 | break; |
| 275 | 275 | ||
| 276 | /* mandatory */ | 276 | /* mandatory */ |
| 277 | case OID_GEN_RECEIVE_BLOCK_SIZE: | 277 | case OID_GEN_RECEIVE_BLOCK_SIZE: |
| 278 | DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__); | 278 | DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__); |
| @@ -282,7 +282,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 282 | retval = 0; | 282 | retval = 0; |
| 283 | } | 283 | } |
| 284 | break; | 284 | break; |
| 285 | 285 | ||
| 286 | /* mandatory */ | 286 | /* mandatory */ |
| 287 | case OID_GEN_VENDOR_ID: | 287 | case OID_GEN_VENDOR_ID: |
| 288 | DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__); | 288 | DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__); |
| @@ -290,7 +290,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 290 | rndis_per_dev_params [configNr].vendorID); | 290 | rndis_per_dev_params [configNr].vendorID); |
| 291 | retval = 0; | 291 | retval = 0; |
| 292 | break; | 292 | break; |
| 293 | 293 | ||
| 294 | /* mandatory */ | 294 | /* mandatory */ |
| 295 | case OID_GEN_VENDOR_DESCRIPTION: | 295 | case OID_GEN_VENDOR_DESCRIPTION: |
| 296 | DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__); | 296 | DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__); |
| @@ -356,7 +356,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 356 | DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); | 356 | DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__); |
| 357 | if (rndis_per_dev_params [configNr].stats) { | 357 | if (rndis_per_dev_params [configNr].stats) { |
| 358 | *outbuf = cpu_to_le32 ( | 358 | *outbuf = cpu_to_le32 ( |
| 359 | rndis_per_dev_params [configNr].stats->tx_packets - | 359 | rndis_per_dev_params [configNr].stats->tx_packets - |
| 360 | rndis_per_dev_params [configNr].stats->tx_errors - | 360 | rndis_per_dev_params [configNr].stats->tx_errors - |
| 361 | rndis_per_dev_params [configNr].stats->tx_dropped); | 361 | rndis_per_dev_params [configNr].stats->tx_dropped); |
| 362 | retval = 0; | 362 | retval = 0; |
| @@ -369,13 +369,13 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 369 | DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); | 369 | DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__); |
| 370 | if (rndis_per_dev_params [configNr].stats) { | 370 | if (rndis_per_dev_params [configNr].stats) { |
| 371 | *outbuf = cpu_to_le32 ( | 371 | *outbuf = cpu_to_le32 ( |
| 372 | rndis_per_dev_params [configNr].stats->rx_packets - | 372 | rndis_per_dev_params [configNr].stats->rx_packets - |
| 373 | rndis_per_dev_params [configNr].stats->rx_errors - | 373 | rndis_per_dev_params [configNr].stats->rx_errors - |
| 374 | rndis_per_dev_params [configNr].stats->rx_dropped); | 374 | rndis_per_dev_params [configNr].stats->rx_dropped); |
| 375 | retval = 0; | 375 | retval = 0; |
| 376 | } | 376 | } |
| 377 | break; | 377 | break; |
| 378 | 378 | ||
| 379 | /* mandatory */ | 379 | /* mandatory */ |
| 380 | case OID_GEN_XMIT_ERROR: | 380 | case OID_GEN_XMIT_ERROR: |
| 381 | if (rndis_debug > 1) | 381 | if (rndis_debug > 1) |
| @@ -386,7 +386,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 386 | retval = 0; | 386 | retval = 0; |
| 387 | } | 387 | } |
| 388 | break; | 388 | break; |
| 389 | 389 | ||
| 390 | /* mandatory */ | 390 | /* mandatory */ |
| 391 | case OID_GEN_RCV_ERROR: | 391 | case OID_GEN_RCV_ERROR: |
| 392 | if (rndis_debug > 1) | 392 | if (rndis_debug > 1) |
| @@ -397,7 +397,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 397 | retval = 0; | 397 | retval = 0; |
| 398 | } | 398 | } |
| 399 | break; | 399 | break; |
| 400 | 400 | ||
| 401 | /* mandatory */ | 401 | /* mandatory */ |
| 402 | case OID_GEN_RCV_NO_BUFFER: | 402 | case OID_GEN_RCV_NO_BUFFER: |
| 403 | DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__); | 403 | DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__); |
| @@ -411,7 +411,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 411 | #ifdef RNDIS_OPTIONAL_STATS | 411 | #ifdef RNDIS_OPTIONAL_STATS |
| 412 | case OID_GEN_DIRECTED_BYTES_XMIT: | 412 | case OID_GEN_DIRECTED_BYTES_XMIT: |
| 413 | DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__); | 413 | DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__); |
| 414 | /* | 414 | /* |
| 415 | * Aunt Tilly's size of shoes | 415 | * Aunt Tilly's size of shoes |
| 416 | * minus antarctica count of penguins | 416 | * minus antarctica count of penguins |
| 417 | * divided by weight of Alpha Centauri | 417 | * divided by weight of Alpha Centauri |
| @@ -419,7 +419,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 419 | if (rndis_per_dev_params [configNr].stats) { | 419 | if (rndis_per_dev_params [configNr].stats) { |
| 420 | *outbuf = cpu_to_le32 ( | 420 | *outbuf = cpu_to_le32 ( |
| 421 | (rndis_per_dev_params [configNr] | 421 | (rndis_per_dev_params [configNr] |
| 422 | .stats->tx_packets - | 422 | .stats->tx_packets - |
| 423 | rndis_per_dev_params [configNr] | 423 | rndis_per_dev_params [configNr] |
| 424 | .stats->tx_errors - | 424 | .stats->tx_errors - |
| 425 | rndis_per_dev_params [configNr] | 425 | rndis_per_dev_params [configNr] |
| @@ -428,14 +428,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 428 | retval = 0; | 428 | retval = 0; |
| 429 | } | 429 | } |
| 430 | break; | 430 | break; |
| 431 | 431 | ||
| 432 | case OID_GEN_DIRECTED_FRAMES_XMIT: | 432 | case OID_GEN_DIRECTED_FRAMES_XMIT: |
| 433 | DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__); | 433 | DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__); |
| 434 | /* dito */ | 434 | /* dito */ |
| 435 | if (rndis_per_dev_params [configNr].stats) { | 435 | if (rndis_per_dev_params [configNr].stats) { |
| 436 | *outbuf = cpu_to_le32 ( | 436 | *outbuf = cpu_to_le32 ( |
| 437 | (rndis_per_dev_params [configNr] | 437 | (rndis_per_dev_params [configNr] |
| 438 | .stats->tx_packets - | 438 | .stats->tx_packets - |
| 439 | rndis_per_dev_params [configNr] | 439 | rndis_per_dev_params [configNr] |
| 440 | .stats->tx_errors - | 440 | .stats->tx_errors - |
| 441 | rndis_per_dev_params [configNr] | 441 | rndis_per_dev_params [configNr] |
| @@ -444,7 +444,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 444 | retval = 0; | 444 | retval = 0; |
| 445 | } | 445 | } |
| 446 | break; | 446 | break; |
| 447 | 447 | ||
| 448 | case OID_GEN_MULTICAST_BYTES_XMIT: | 448 | case OID_GEN_MULTICAST_BYTES_XMIT: |
| 449 | DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__); | 449 | DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__); |
| 450 | if (rndis_per_dev_params [configNr].stats) { | 450 | if (rndis_per_dev_params [configNr].stats) { |
| @@ -453,7 +453,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 453 | retval = 0; | 453 | retval = 0; |
| 454 | } | 454 | } |
| 455 | break; | 455 | break; |
| 456 | 456 | ||
| 457 | case OID_GEN_MULTICAST_FRAMES_XMIT: | 457 | case OID_GEN_MULTICAST_FRAMES_XMIT: |
| 458 | DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__); | 458 | DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__); |
| 459 | if (rndis_per_dev_params [configNr].stats) { | 459 | if (rndis_per_dev_params [configNr].stats) { |
| @@ -462,7 +462,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 462 | retval = 0; | 462 | retval = 0; |
| 463 | } | 463 | } |
| 464 | break; | 464 | break; |
| 465 | 465 | ||
| 466 | case OID_GEN_BROADCAST_BYTES_XMIT: | 466 | case OID_GEN_BROADCAST_BYTES_XMIT: |
| 467 | DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__); | 467 | DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__); |
| 468 | if (rndis_per_dev_params [configNr].stats) { | 468 | if (rndis_per_dev_params [configNr].stats) { |
| @@ -471,7 +471,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 471 | retval = 0; | 471 | retval = 0; |
| 472 | } | 472 | } |
| 473 | break; | 473 | break; |
| 474 | 474 | ||
| 475 | case OID_GEN_BROADCAST_FRAMES_XMIT: | 475 | case OID_GEN_BROADCAST_FRAMES_XMIT: |
| 476 | DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__); | 476 | DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__); |
| 477 | if (rndis_per_dev_params [configNr].stats) { | 477 | if (rndis_per_dev_params [configNr].stats) { |
| @@ -480,19 +480,19 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 480 | retval = 0; | 480 | retval = 0; |
| 481 | } | 481 | } |
| 482 | break; | 482 | break; |
| 483 | 483 | ||
| 484 | case OID_GEN_DIRECTED_BYTES_RCV: | 484 | case OID_GEN_DIRECTED_BYTES_RCV: |
| 485 | DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__); | 485 | DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__); |
| 486 | *outbuf = __constant_cpu_to_le32 (0); | 486 | *outbuf = __constant_cpu_to_le32 (0); |
| 487 | retval = 0; | 487 | retval = 0; |
| 488 | break; | 488 | break; |
| 489 | 489 | ||
| 490 | case OID_GEN_DIRECTED_FRAMES_RCV: | 490 | case OID_GEN_DIRECTED_FRAMES_RCV: |
| 491 | DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__); | 491 | DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__); |
| 492 | *outbuf = __constant_cpu_to_le32 (0); | 492 | *outbuf = __constant_cpu_to_le32 (0); |
| 493 | retval = 0; | 493 | retval = 0; |
| 494 | break; | 494 | break; |
| 495 | 495 | ||
| 496 | case OID_GEN_MULTICAST_BYTES_RCV: | 496 | case OID_GEN_MULTICAST_BYTES_RCV: |
| 497 | DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__); | 497 | DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__); |
| 498 | if (rndis_per_dev_params [configNr].stats) { | 498 | if (rndis_per_dev_params [configNr].stats) { |
| @@ -501,7 +501,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 501 | retval = 0; | 501 | retval = 0; |
| 502 | } | 502 | } |
| 503 | break; | 503 | break; |
| 504 | 504 | ||
| 505 | case OID_GEN_MULTICAST_FRAMES_RCV: | 505 | case OID_GEN_MULTICAST_FRAMES_RCV: |
| 506 | DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__); | 506 | DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__); |
| 507 | if (rndis_per_dev_params [configNr].stats) { | 507 | if (rndis_per_dev_params [configNr].stats) { |
| @@ -510,7 +510,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 510 | retval = 0; | 510 | retval = 0; |
| 511 | } | 511 | } |
| 512 | break; | 512 | break; |
| 513 | 513 | ||
| 514 | case OID_GEN_BROADCAST_BYTES_RCV: | 514 | case OID_GEN_BROADCAST_BYTES_RCV: |
| 515 | DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__); | 515 | DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__); |
| 516 | if (rndis_per_dev_params [configNr].stats) { | 516 | if (rndis_per_dev_params [configNr].stats) { |
| @@ -519,7 +519,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 519 | retval = 0; | 519 | retval = 0; |
| 520 | } | 520 | } |
| 521 | break; | 521 | break; |
| 522 | 522 | ||
| 523 | case OID_GEN_BROADCAST_FRAMES_RCV: | 523 | case OID_GEN_BROADCAST_FRAMES_RCV: |
| 524 | DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__); | 524 | DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__); |
| 525 | if (rndis_per_dev_params [configNr].stats) { | 525 | if (rndis_per_dev_params [configNr].stats) { |
| @@ -528,7 +528,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 528 | retval = 0; | 528 | retval = 0; |
| 529 | } | 529 | } |
| 530 | break; | 530 | break; |
| 531 | 531 | ||
| 532 | case OID_GEN_RCV_CRC_ERROR: | 532 | case OID_GEN_RCV_CRC_ERROR: |
| 533 | DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__); | 533 | DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__); |
| 534 | if (rndis_per_dev_params [configNr].stats) { | 534 | if (rndis_per_dev_params [configNr].stats) { |
| @@ -537,7 +537,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 537 | retval = 0; | 537 | retval = 0; |
| 538 | } | 538 | } |
| 539 | break; | 539 | break; |
| 540 | 540 | ||
| 541 | case OID_GEN_TRANSMIT_QUEUE_LENGTH: | 541 | case OID_GEN_TRANSMIT_QUEUE_LENGTH: |
| 542 | DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__); | 542 | DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__); |
| 543 | *outbuf = __constant_cpu_to_le32 (0); | 543 | *outbuf = __constant_cpu_to_le32 (0); |
| @@ -558,7 +558,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 558 | retval = 0; | 558 | retval = 0; |
| 559 | } | 559 | } |
| 560 | break; | 560 | break; |
| 561 | 561 | ||
| 562 | /* mandatory */ | 562 | /* mandatory */ |
| 563 | case OID_802_3_CURRENT_ADDRESS: | 563 | case OID_802_3_CURRENT_ADDRESS: |
| 564 | DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); | 564 | DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__); |
| @@ -570,7 +570,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 570 | retval = 0; | 570 | retval = 0; |
| 571 | } | 571 | } |
| 572 | break; | 572 | break; |
| 573 | 573 | ||
| 574 | /* mandatory */ | 574 | /* mandatory */ |
| 575 | case OID_802_3_MULTICAST_LIST: | 575 | case OID_802_3_MULTICAST_LIST: |
| 576 | DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); | 576 | DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); |
| @@ -578,7 +578,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 578 | *outbuf = __constant_cpu_to_le32 (0xE0000000); | 578 | *outbuf = __constant_cpu_to_le32 (0xE0000000); |
| 579 | retval = 0; | 579 | retval = 0; |
| 580 | break; | 580 | break; |
| 581 | 581 | ||
| 582 | /* mandatory */ | 582 | /* mandatory */ |
| 583 | case OID_802_3_MAXIMUM_LIST_SIZE: | 583 | case OID_802_3_MAXIMUM_LIST_SIZE: |
| 584 | DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); | 584 | DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__); |
| @@ -586,7 +586,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 586 | *outbuf = __constant_cpu_to_le32 (1); | 586 | *outbuf = __constant_cpu_to_le32 (1); |
| 587 | retval = 0; | 587 | retval = 0; |
| 588 | break; | 588 | break; |
| 589 | 589 | ||
| 590 | case OID_802_3_MAC_OPTIONS: | 590 | case OID_802_3_MAC_OPTIONS: |
| 591 | DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__); | 591 | DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__); |
| 592 | break; | 592 | break; |
| @@ -602,56 +602,56 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 602 | retval = 0; | 602 | retval = 0; |
| 603 | } | 603 | } |
| 604 | break; | 604 | break; |
| 605 | 605 | ||
| 606 | /* mandatory */ | 606 | /* mandatory */ |
| 607 | case OID_802_3_XMIT_ONE_COLLISION: | 607 | case OID_802_3_XMIT_ONE_COLLISION: |
| 608 | DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__); | 608 | DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__); |
| 609 | *outbuf = __constant_cpu_to_le32 (0); | 609 | *outbuf = __constant_cpu_to_le32 (0); |
| 610 | retval = 0; | 610 | retval = 0; |
| 611 | break; | 611 | break; |
| 612 | 612 | ||
| 613 | /* mandatory */ | 613 | /* mandatory */ |
| 614 | case OID_802_3_XMIT_MORE_COLLISIONS: | 614 | case OID_802_3_XMIT_MORE_COLLISIONS: |
| 615 | DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__); | 615 | DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__); |
| 616 | *outbuf = __constant_cpu_to_le32 (0); | 616 | *outbuf = __constant_cpu_to_le32 (0); |
| 617 | retval = 0; | 617 | retval = 0; |
| 618 | break; | 618 | break; |
| 619 | 619 | ||
| 620 | #ifdef RNDIS_OPTIONAL_STATS | 620 | #ifdef RNDIS_OPTIONAL_STATS |
| 621 | case OID_802_3_XMIT_DEFERRED: | 621 | case OID_802_3_XMIT_DEFERRED: |
| 622 | DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__); | 622 | DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__); |
| 623 | /* TODO */ | 623 | /* TODO */ |
| 624 | break; | 624 | break; |
| 625 | 625 | ||
| 626 | case OID_802_3_XMIT_MAX_COLLISIONS: | 626 | case OID_802_3_XMIT_MAX_COLLISIONS: |
| 627 | DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__); | 627 | DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__); |
| 628 | /* TODO */ | 628 | /* TODO */ |
| 629 | break; | 629 | break; |
| 630 | 630 | ||
| 631 | case OID_802_3_RCV_OVERRUN: | 631 | case OID_802_3_RCV_OVERRUN: |
| 632 | DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__); | 632 | DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__); |
| 633 | /* TODO */ | 633 | /* TODO */ |
| 634 | break; | 634 | break; |
| 635 | 635 | ||
| 636 | case OID_802_3_XMIT_UNDERRUN: | 636 | case OID_802_3_XMIT_UNDERRUN: |
| 637 | DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__); | 637 | DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__); |
| 638 | /* TODO */ | 638 | /* TODO */ |
| 639 | break; | 639 | break; |
| 640 | 640 | ||
| 641 | case OID_802_3_XMIT_HEARTBEAT_FAILURE: | 641 | case OID_802_3_XMIT_HEARTBEAT_FAILURE: |
| 642 | DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__); | 642 | DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__); |
| 643 | /* TODO */ | 643 | /* TODO */ |
| 644 | break; | 644 | break; |
| 645 | 645 | ||
| 646 | case OID_802_3_XMIT_TIMES_CRS_LOST: | 646 | case OID_802_3_XMIT_TIMES_CRS_LOST: |
| 647 | DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__); | 647 | DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__); |
| 648 | /* TODO */ | 648 | /* TODO */ |
| 649 | break; | 649 | break; |
| 650 | 650 | ||
| 651 | case OID_802_3_XMIT_LATE_COLLISIONS: | 651 | case OID_802_3_XMIT_LATE_COLLISIONS: |
| 652 | DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__); | 652 | DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__); |
| 653 | /* TODO */ | 653 | /* TODO */ |
| 654 | break; | 654 | break; |
| 655 | #endif /* RNDIS_OPTIONAL_STATS */ | 655 | #endif /* RNDIS_OPTIONAL_STATS */ |
| 656 | 656 | ||
| 657 | #ifdef RNDIS_PM | 657 | #ifdef RNDIS_PM |
| @@ -676,23 +676,23 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, | |||
| 676 | #endif | 676 | #endif |
| 677 | 677 | ||
| 678 | default: | 678 | default: |
| 679 | printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", | 679 | printk (KERN_WARNING "%s: query unknown OID 0x%08X\n", |
| 680 | __FUNCTION__, OID); | 680 | __FUNCTION__, OID); |
| 681 | } | 681 | } |
| 682 | if (retval < 0) | 682 | if (retval < 0) |
| 683 | length = 0; | 683 | length = 0; |
| 684 | 684 | ||
| 685 | resp->InformationBufferLength = cpu_to_le32 (length); | 685 | resp->InformationBufferLength = cpu_to_le32 (length); |
| 686 | r->length = length + sizeof *resp; | 686 | r->length = length + sizeof *resp; |
| 687 | resp->MessageLength = cpu_to_le32 (r->length); | 687 | resp->MessageLength = cpu_to_le32 (r->length); |
| 688 | return retval; | 688 | return retval; |
| 689 | } | 689 | } |
| 690 | 690 | ||
| 691 | static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, | 691 | static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, |
| 692 | rndis_resp_t *r) | 692 | rndis_resp_t *r) |
| 693 | { | 693 | { |
| 694 | rndis_set_cmplt_type *resp; | 694 | rndis_set_cmplt_type *resp; |
| 695 | int i, retval = -ENOTSUPP; | 695 | int i, retval = -ENOTSUPP; |
| 696 | struct rndis_params *params; | 696 | struct rndis_params *params; |
| 697 | 697 | ||
| 698 | if (!r) | 698 | if (!r) |
| @@ -745,9 +745,9 @@ update_linkstate: | |||
| 745 | netif_stop_queue (params->dev); | 745 | netif_stop_queue (params->dev); |
| 746 | } | 746 | } |
| 747 | break; | 747 | break; |
| 748 | 748 | ||
| 749 | case OID_802_3_MULTICAST_LIST: | 749 | case OID_802_3_MULTICAST_LIST: |
| 750 | /* I think we can ignore this */ | 750 | /* I think we can ignore this */ |
| 751 | DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); | 751 | DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__); |
| 752 | retval = 0; | 752 | retval = 0; |
| 753 | break; | 753 | break; |
| @@ -796,29 +796,29 @@ update_linkstate: | |||
| 796 | #endif /* RNDIS_PM */ | 796 | #endif /* RNDIS_PM */ |
| 797 | 797 | ||
| 798 | default: | 798 | default: |
| 799 | printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", | 799 | printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n", |
| 800 | __FUNCTION__, OID, buf_len); | 800 | __FUNCTION__, OID, buf_len); |
| 801 | } | 801 | } |
| 802 | 802 | ||
| 803 | return retval; | 803 | return retval; |
| 804 | } | 804 | } |
| 805 | 805 | ||
| 806 | /* | 806 | /* |
| 807 | * Response Functions | 807 | * Response Functions |
| 808 | */ | 808 | */ |
| 809 | 809 | ||
| 810 | static int rndis_init_response (int configNr, rndis_init_msg_type *buf) | 810 | static int rndis_init_response (int configNr, rndis_init_msg_type *buf) |
| 811 | { | 811 | { |
| 812 | rndis_init_cmplt_type *resp; | 812 | rndis_init_cmplt_type *resp; |
| 813 | rndis_resp_t *r; | 813 | rndis_resp_t *r; |
| 814 | 814 | ||
| 815 | if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; | 815 | if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; |
| 816 | 816 | ||
| 817 | r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type)); | 817 | r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type)); |
| 818 | if (!r) | 818 | if (!r) |
| 819 | return -ENOMEM; | 819 | return -ENOMEM; |
| 820 | resp = (rndis_init_cmplt_type *) r->buf; | 820 | resp = (rndis_init_cmplt_type *) r->buf; |
| 821 | 821 | ||
| 822 | resp->MessageType = __constant_cpu_to_le32 ( | 822 | resp->MessageType = __constant_cpu_to_le32 ( |
| 823 | REMOTE_NDIS_INITIALIZE_CMPLT); | 823 | REMOTE_NDIS_INITIALIZE_CMPLT); |
| 824 | resp->MessageLength = __constant_cpu_to_le32 (52); | 824 | resp->MessageLength = __constant_cpu_to_le32 (52); |
| @@ -837,11 +837,11 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf) | |||
| 837 | resp->PacketAlignmentFactor = __constant_cpu_to_le32 (0); | 837 | resp->PacketAlignmentFactor = __constant_cpu_to_le32 (0); |
| 838 | resp->AFListOffset = __constant_cpu_to_le32 (0); | 838 | resp->AFListOffset = __constant_cpu_to_le32 (0); |
| 839 | resp->AFListSize = __constant_cpu_to_le32 (0); | 839 | resp->AFListSize = __constant_cpu_to_le32 (0); |
| 840 | 840 | ||
| 841 | if (rndis_per_dev_params [configNr].ack) | 841 | if (rndis_per_dev_params [configNr].ack) |
| 842 | rndis_per_dev_params [configNr].ack ( | 842 | rndis_per_dev_params [configNr].ack ( |
| 843 | rndis_per_dev_params [configNr].dev); | 843 | rndis_per_dev_params [configNr].dev); |
| 844 | 844 | ||
| 845 | return 0; | 845 | return 0; |
| 846 | } | 846 | } |
| 847 | 847 | ||
| @@ -849,10 +849,10 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf) | |||
| 849 | { | 849 | { |
| 850 | rndis_query_cmplt_type *resp; | 850 | rndis_query_cmplt_type *resp; |
| 851 | rndis_resp_t *r; | 851 | rndis_resp_t *r; |
| 852 | 852 | ||
| 853 | // DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID)); | 853 | // DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID)); |
| 854 | if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; | 854 | if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP; |
| 855 | 855 | ||
| 856 | /* | 856 | /* |
| 857 | * we need more memory: | 857 | * we need more memory: |
| 858 | * gen_ndis_query_resp expects enough space for | 858 | * gen_ndis_query_resp expects enough space for |
| @@ -864,10 +864,10 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf) | |||
| 864 | if (!r) | 864 | if (!r) |
| 865 | return -ENOMEM; | 865 | return -ENOMEM; |
| 866 | resp = (rndis_query_cmplt_type *) r->buf; | 866 | resp = (rndis_query_cmplt_type *) r->buf; |
| 867 | 867 | ||
| 868 | resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT); | 868 | resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT); |
| 869 | resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ | 869 | resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ |
| 870 | 870 | ||
| 871 | if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), | 871 | if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), |
| 872 | le32_to_cpu(buf->InformationBufferOffset) | 872 | le32_to_cpu(buf->InformationBufferOffset) |
| 873 | + 8 + (u8 *) buf, | 873 | + 8 + (u8 *) buf, |
| @@ -881,10 +881,10 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf) | |||
| 881 | resp->InformationBufferOffset = __constant_cpu_to_le32 (0); | 881 | resp->InformationBufferOffset = __constant_cpu_to_le32 (0); |
| 882 | } else | 882 | } else |
| 883 | resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS); | 883 | resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS); |
| 884 | 884 | ||
| 885 | if (rndis_per_dev_params [configNr].ack) | 885 | if (rndis_per_dev_params [configNr].ack) |
| 886 | rndis_per_dev_params [configNr].ack ( | 886 | rndis_per_dev_params [configNr].ack ( |
| 887 | rndis_per_dev_params [configNr].dev); | 887 | rndis_per_dev_params [configNr].dev); |
| 888 | return 0; | 888 | return 0; |
| 889 | } | 889 | } |
| 890 | 890 | ||
| @@ -893,7 +893,7 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf) | |||
| 893 | u32 BufLength, BufOffset; | 893 | u32 BufLength, BufOffset; |
| 894 | rndis_set_cmplt_type *resp; | 894 | rndis_set_cmplt_type *resp; |
| 895 | rndis_resp_t *r; | 895 | rndis_resp_t *r; |
| 896 | 896 | ||
| 897 | r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type)); | 897 | r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type)); |
| 898 | if (!r) | 898 | if (!r) |
| 899 | return -ENOMEM; | 899 | return -ENOMEM; |
| @@ -906,26 +906,27 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf) | |||
| 906 | DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength); | 906 | DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength); |
| 907 | DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset); | 907 | DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset); |
| 908 | DEBUG("%s: InfoBuffer: ", __FUNCTION__); | 908 | DEBUG("%s: InfoBuffer: ", __FUNCTION__); |
| 909 | 909 | ||
| 910 | for (i = 0; i < BufLength; i++) { | 910 | for (i = 0; i < BufLength; i++) { |
| 911 | DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset)); | 911 | DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset)); |
| 912 | } | 912 | } |
| 913 | 913 | ||
| 914 | DEBUG ("\n"); | 914 | DEBUG ("\n"); |
| 915 | #endif | 915 | #endif |
| 916 | 916 | ||
| 917 | resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT); | 917 | resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT); |
| 918 | resp->MessageLength = __constant_cpu_to_le32 (16); | 918 | resp->MessageLength = __constant_cpu_to_le32 (16); |
| 919 | resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ | 919 | resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ |
| 920 | if (gen_ndis_set_resp (configNr, le32_to_cpu (buf->OID), | 920 | if (gen_ndis_set_resp (configNr, le32_to_cpu (buf->OID), |
| 921 | ((u8 *) buf) + 8 + BufOffset, BufLength, r)) | 921 | ((u8 *) buf) + 8 + BufOffset, BufLength, r)) |
| 922 | resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_NOT_SUPPORTED); | 922 | resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_NOT_SUPPORTED); |
| 923 | else resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS); | 923 | else |
| 924 | 924 | resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS); | |
| 925 | |||
| 925 | if (rndis_per_dev_params [configNr].ack) | 926 | if (rndis_per_dev_params [configNr].ack) |
| 926 | rndis_per_dev_params [configNr].ack ( | 927 | rndis_per_dev_params [configNr].ack ( |
| 927 | rndis_per_dev_params [configNr].dev); | 928 | rndis_per_dev_params [configNr].dev); |
| 928 | 929 | ||
| 929 | return 0; | 930 | return 0; |
| 930 | } | 931 | } |
| 931 | 932 | ||
| @@ -933,27 +934,27 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf) | |||
| 933 | { | 934 | { |
| 934 | rndis_reset_cmplt_type *resp; | 935 | rndis_reset_cmplt_type *resp; |
| 935 | rndis_resp_t *r; | 936 | rndis_resp_t *r; |
| 936 | 937 | ||
| 937 | r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type)); | 938 | r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type)); |
| 938 | if (!r) | 939 | if (!r) |
| 939 | return -ENOMEM; | 940 | return -ENOMEM; |
| 940 | resp = (rndis_reset_cmplt_type *) r->buf; | 941 | resp = (rndis_reset_cmplt_type *) r->buf; |
| 941 | 942 | ||
| 942 | resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT); | 943 | resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT); |
| 943 | resp->MessageLength = __constant_cpu_to_le32 (16); | 944 | resp->MessageLength = __constant_cpu_to_le32 (16); |
| 944 | resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS); | 945 | resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS); |
| 945 | /* resent information */ | 946 | /* resent information */ |
| 946 | resp->AddressingReset = __constant_cpu_to_le32 (1); | 947 | resp->AddressingReset = __constant_cpu_to_le32 (1); |
| 947 | 948 | ||
| 948 | if (rndis_per_dev_params [configNr].ack) | 949 | if (rndis_per_dev_params [configNr].ack) |
| 949 | rndis_per_dev_params [configNr].ack ( | 950 | rndis_per_dev_params [configNr].ack ( |
| 950 | rndis_per_dev_params [configNr].dev); | 951 | rndis_per_dev_params [configNr].dev); |
| 951 | 952 | ||
| 952 | return 0; | 953 | return 0; |
| 953 | } | 954 | } |
| 954 | 955 | ||
| 955 | static int rndis_keepalive_response (int configNr, | 956 | static int rndis_keepalive_response (int configNr, |
| 956 | rndis_keepalive_msg_type *buf) | 957 | rndis_keepalive_msg_type *buf) |
| 957 | { | 958 | { |
| 958 | rndis_keepalive_cmplt_type *resp; | 959 | rndis_keepalive_cmplt_type *resp; |
| 959 | rndis_resp_t *r; | 960 | rndis_resp_t *r; |
| @@ -964,48 +965,48 @@ static int rndis_keepalive_response (int configNr, | |||
| 964 | if (!r) | 965 | if (!r) |
| 965 | return -ENOMEM; | 966 | return -ENOMEM; |
| 966 | resp = (rndis_keepalive_cmplt_type *) r->buf; | 967 | resp = (rndis_keepalive_cmplt_type *) r->buf; |
| 967 | 968 | ||
| 968 | resp->MessageType = __constant_cpu_to_le32 ( | 969 | resp->MessageType = __constant_cpu_to_le32 ( |
| 969 | REMOTE_NDIS_KEEPALIVE_CMPLT); | 970 | REMOTE_NDIS_KEEPALIVE_CMPLT); |
| 970 | resp->MessageLength = __constant_cpu_to_le32 (16); | 971 | resp->MessageLength = __constant_cpu_to_le32 (16); |
| 971 | resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ | 972 | resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ |
| 972 | resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS); | 973 | resp->Status = __constant_cpu_to_le32 (RNDIS_STATUS_SUCCESS); |
| 973 | 974 | ||
| 974 | if (rndis_per_dev_params [configNr].ack) | 975 | if (rndis_per_dev_params [configNr].ack) |
| 975 | rndis_per_dev_params [configNr].ack ( | 976 | rndis_per_dev_params [configNr].ack ( |
| 976 | rndis_per_dev_params [configNr].dev); | 977 | rndis_per_dev_params [configNr].dev); |
| 977 | 978 | ||
| 978 | return 0; | 979 | return 0; |
| 979 | } | 980 | } |
| 980 | 981 | ||
| 981 | 982 | ||
| 982 | /* | 983 | /* |
| 983 | * Device to Host Comunication | 984 | * Device to Host Comunication |
| 984 | */ | 985 | */ |
| 985 | static int rndis_indicate_status_msg (int configNr, u32 status) | 986 | static int rndis_indicate_status_msg (int configNr, u32 status) |
| 986 | { | 987 | { |
| 987 | rndis_indicate_status_msg_type *resp; | 988 | rndis_indicate_status_msg_type *resp; |
| 988 | rndis_resp_t *r; | 989 | rndis_resp_t *r; |
| 989 | 990 | ||
| 990 | if (rndis_per_dev_params [configNr].state == RNDIS_UNINITIALIZED) | 991 | if (rndis_per_dev_params [configNr].state == RNDIS_UNINITIALIZED) |
| 991 | return -ENOTSUPP; | 992 | return -ENOTSUPP; |
| 992 | 993 | ||
| 993 | r = rndis_add_response (configNr, | 994 | r = rndis_add_response (configNr, |
| 994 | sizeof (rndis_indicate_status_msg_type)); | 995 | sizeof (rndis_indicate_status_msg_type)); |
| 995 | if (!r) | 996 | if (!r) |
| 996 | return -ENOMEM; | 997 | return -ENOMEM; |
| 997 | resp = (rndis_indicate_status_msg_type *) r->buf; | 998 | resp = (rndis_indicate_status_msg_type *) r->buf; |
| 998 | 999 | ||
| 999 | resp->MessageType = __constant_cpu_to_le32 ( | 1000 | resp->MessageType = __constant_cpu_to_le32 ( |
| 1000 | REMOTE_NDIS_INDICATE_STATUS_MSG); | 1001 | REMOTE_NDIS_INDICATE_STATUS_MSG); |
| 1001 | resp->MessageLength = __constant_cpu_to_le32 (20); | 1002 | resp->MessageLength = __constant_cpu_to_le32 (20); |
| 1002 | resp->Status = cpu_to_le32 (status); | 1003 | resp->Status = cpu_to_le32 (status); |
| 1003 | resp->StatusBufferLength = __constant_cpu_to_le32 (0); | 1004 | resp->StatusBufferLength = __constant_cpu_to_le32 (0); |
| 1004 | resp->StatusBufferOffset = __constant_cpu_to_le32 (0); | 1005 | resp->StatusBufferOffset = __constant_cpu_to_le32 (0); |
| 1005 | 1006 | ||
| 1006 | if (rndis_per_dev_params [configNr].ack) | 1007 | if (rndis_per_dev_params [configNr].ack) |
| 1007 | rndis_per_dev_params [configNr].ack ( | 1008 | rndis_per_dev_params [configNr].ack ( |
| 1008 | rndis_per_dev_params [configNr].dev); | 1009 | rndis_per_dev_params [configNr].dev); |
| 1009 | return 0; | 1010 | return 0; |
| 1010 | } | 1011 | } |
| 1011 | 1012 | ||
| @@ -1013,7 +1014,7 @@ int rndis_signal_connect (int configNr) | |||
| 1013 | { | 1014 | { |
| 1014 | rndis_per_dev_params [configNr].media_state | 1015 | rndis_per_dev_params [configNr].media_state |
| 1015 | = NDIS_MEDIA_STATE_CONNECTED; | 1016 | = NDIS_MEDIA_STATE_CONNECTED; |
| 1016 | return rndis_indicate_status_msg (configNr, | 1017 | return rndis_indicate_status_msg (configNr, |
| 1017 | RNDIS_STATUS_MEDIA_CONNECT); | 1018 | RNDIS_STATUS_MEDIA_CONNECT); |
| 1018 | } | 1019 | } |
| 1019 | 1020 | ||
| @@ -1045,26 +1046,26 @@ void rndis_set_host_mac (int configNr, const u8 *addr) | |||
| 1045 | rndis_per_dev_params [configNr].host_mac = addr; | 1046 | rndis_per_dev_params [configNr].host_mac = addr; |
| 1046 | } | 1047 | } |
| 1047 | 1048 | ||
| 1048 | /* | 1049 | /* |
| 1049 | * Message Parser | 1050 | * Message Parser |
| 1050 | */ | 1051 | */ |
| 1051 | int rndis_msg_parser (u8 configNr, u8 *buf) | 1052 | int rndis_msg_parser (u8 configNr, u8 *buf) |
| 1052 | { | 1053 | { |
| 1053 | u32 MsgType, MsgLength; | 1054 | u32 MsgType, MsgLength; |
| 1054 | __le32 *tmp; | 1055 | __le32 *tmp; |
| 1055 | struct rndis_params *params; | 1056 | struct rndis_params *params; |
| 1056 | 1057 | ||
| 1057 | if (!buf) | 1058 | if (!buf) |
| 1058 | return -ENOMEM; | 1059 | return -ENOMEM; |
| 1059 | 1060 | ||
| 1060 | tmp = (__le32 *) buf; | 1061 | tmp = (__le32 *) buf; |
| 1061 | MsgType = le32_to_cpup(tmp++); | 1062 | MsgType = le32_to_cpup(tmp++); |
| 1062 | MsgLength = le32_to_cpup(tmp++); | 1063 | MsgLength = le32_to_cpup(tmp++); |
| 1063 | 1064 | ||
| 1064 | if (configNr >= RNDIS_MAX_CONFIGS) | 1065 | if (configNr >= RNDIS_MAX_CONFIGS) |
| 1065 | return -ENOTSUPP; | 1066 | return -ENOTSUPP; |
| 1066 | params = &rndis_per_dev_params [configNr]; | 1067 | params = &rndis_per_dev_params [configNr]; |
| 1067 | 1068 | ||
| 1068 | /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for | 1069 | /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for |
| 1069 | * rx/tx statistics and link status, in addition to KEEPALIVE traffic | 1070 | * rx/tx statistics and link status, in addition to KEEPALIVE traffic |
| 1070 | * and normal HC level polling to see if there's any IN traffic. | 1071 | * and normal HC level polling to see if there's any IN traffic. |
| @@ -1073,12 +1074,12 @@ int rndis_msg_parser (u8 configNr, u8 *buf) | |||
| 1073 | /* For USB: responses may take up to 10 seconds */ | 1074 | /* For USB: responses may take up to 10 seconds */ |
| 1074 | switch (MsgType) { | 1075 | switch (MsgType) { |
| 1075 | case REMOTE_NDIS_INITIALIZE_MSG: | 1076 | case REMOTE_NDIS_INITIALIZE_MSG: |
| 1076 | DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", | 1077 | DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n", |
| 1077 | __FUNCTION__ ); | 1078 | __FUNCTION__ ); |
| 1078 | params->state = RNDIS_INITIALIZED; | 1079 | params->state = RNDIS_INITIALIZED; |
| 1079 | return rndis_init_response (configNr, | 1080 | return rndis_init_response (configNr, |
| 1080 | (rndis_init_msg_type *) buf); | 1081 | (rndis_init_msg_type *) buf); |
| 1081 | 1082 | ||
| 1082 | case REMOTE_NDIS_HALT_MSG: | 1083 | case REMOTE_NDIS_HALT_MSG: |
| 1083 | DEBUG("%s: REMOTE_NDIS_HALT_MSG\n", | 1084 | DEBUG("%s: REMOTE_NDIS_HALT_MSG\n", |
| 1084 | __FUNCTION__ ); | 1085 | __FUNCTION__ ); |
| @@ -1088,37 +1089,37 @@ int rndis_msg_parser (u8 configNr, u8 *buf) | |||
| 1088 | netif_stop_queue (params->dev); | 1089 | netif_stop_queue (params->dev); |
| 1089 | } | 1090 | } |
| 1090 | return 0; | 1091 | return 0; |
| 1091 | 1092 | ||
| 1092 | case REMOTE_NDIS_QUERY_MSG: | 1093 | case REMOTE_NDIS_QUERY_MSG: |
| 1093 | return rndis_query_response (configNr, | 1094 | return rndis_query_response (configNr, |
| 1094 | (rndis_query_msg_type *) buf); | 1095 | (rndis_query_msg_type *) buf); |
| 1095 | 1096 | ||
| 1096 | case REMOTE_NDIS_SET_MSG: | 1097 | case REMOTE_NDIS_SET_MSG: |
| 1097 | return rndis_set_response (configNr, | 1098 | return rndis_set_response (configNr, |
| 1098 | (rndis_set_msg_type *) buf); | 1099 | (rndis_set_msg_type *) buf); |
| 1099 | 1100 | ||
| 1100 | case REMOTE_NDIS_RESET_MSG: | 1101 | case REMOTE_NDIS_RESET_MSG: |
| 1101 | DEBUG("%s: REMOTE_NDIS_RESET_MSG\n", | 1102 | DEBUG("%s: REMOTE_NDIS_RESET_MSG\n", |
| 1102 | __FUNCTION__ ); | 1103 | __FUNCTION__ ); |
| 1103 | return rndis_reset_response (configNr, | 1104 | return rndis_reset_response (configNr, |
| 1104 | (rndis_reset_msg_type *) buf); | 1105 | (rndis_reset_msg_type *) buf); |
| 1105 | 1106 | ||
| 1106 | case REMOTE_NDIS_KEEPALIVE_MSG: | 1107 | case REMOTE_NDIS_KEEPALIVE_MSG: |
| 1107 | /* For USB: host does this every 5 seconds */ | 1108 | /* For USB: host does this every 5 seconds */ |
| 1108 | if (rndis_debug > 1) | 1109 | if (rndis_debug > 1) |
| 1109 | DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", | 1110 | DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", |
| 1110 | __FUNCTION__ ); | 1111 | __FUNCTION__ ); |
| 1111 | return rndis_keepalive_response (configNr, | 1112 | return rndis_keepalive_response (configNr, |
| 1112 | (rndis_keepalive_msg_type *) | 1113 | (rndis_keepalive_msg_type *) |
| 1113 | buf); | 1114 | buf); |
| 1114 | 1115 | ||
| 1115 | default: | 1116 | default: |
| 1116 | /* At least Windows XP emits some undefined RNDIS messages. | 1117 | /* At least Windows XP emits some undefined RNDIS messages. |
| 1117 | * In one case those messages seemed to relate to the host | 1118 | * In one case those messages seemed to relate to the host |
| 1118 | * suspending itself. | 1119 | * suspending itself. |
| 1119 | */ | 1120 | */ |
| 1120 | printk (KERN_WARNING | 1121 | printk (KERN_WARNING |
| 1121 | "%s: unknown RNDIS message 0x%08X len %d\n", | 1122 | "%s: unknown RNDIS message 0x%08X len %d\n", |
| 1122 | __FUNCTION__ , MsgType, MsgLength); | 1123 | __FUNCTION__ , MsgType, MsgLength); |
| 1123 | { | 1124 | { |
| 1124 | unsigned i; | 1125 | unsigned i; |
| @@ -1142,14 +1143,14 @@ int rndis_msg_parser (u8 configNr, u8 *buf) | |||
| 1142 | } | 1143 | } |
| 1143 | break; | 1144 | break; |
| 1144 | } | 1145 | } |
| 1145 | 1146 | ||
| 1146 | return -ENOTSUPP; | 1147 | return -ENOTSUPP; |
| 1147 | } | 1148 | } |
| 1148 | 1149 | ||
| 1149 | int rndis_register (int (* rndis_control_ack) (struct net_device *)) | 1150 | int rndis_register (int (* rndis_control_ack) (struct net_device *)) |
| 1150 | { | 1151 | { |
| 1151 | u8 i; | 1152 | u8 i; |
| 1152 | 1153 | ||
| 1153 | for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { | 1154 | for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { |
| 1154 | if (!rndis_per_dev_params [i].used) { | 1155 | if (!rndis_per_dev_params [i].used) { |
| 1155 | rndis_per_dev_params [i].used = 1; | 1156 | rndis_per_dev_params [i].used = 1; |
| @@ -1159,32 +1160,32 @@ int rndis_register (int (* rndis_control_ack) (struct net_device *)) | |||
| 1159 | } | 1160 | } |
| 1160 | } | 1161 | } |
| 1161 | DEBUG("failed\n"); | 1162 | DEBUG("failed\n"); |
| 1162 | 1163 | ||
| 1163 | return -1; | 1164 | return -1; |
| 1164 | } | 1165 | } |
| 1165 | 1166 | ||
| 1166 | void rndis_deregister (int configNr) | 1167 | void rndis_deregister (int configNr) |
| 1167 | { | 1168 | { |
| 1168 | DEBUG("%s: \n", __FUNCTION__ ); | 1169 | DEBUG("%s: \n", __FUNCTION__ ); |
| 1169 | 1170 | ||
| 1170 | if (configNr >= RNDIS_MAX_CONFIGS) return; | 1171 | if (configNr >= RNDIS_MAX_CONFIGS) return; |
| 1171 | rndis_per_dev_params [configNr].used = 0; | 1172 | rndis_per_dev_params [configNr].used = 0; |
| 1172 | 1173 | ||
| 1173 | return; | 1174 | return; |
| 1174 | } | 1175 | } |
| 1175 | 1176 | ||
| 1176 | int rndis_set_param_dev (u8 configNr, struct net_device *dev, | 1177 | int rndis_set_param_dev (u8 configNr, struct net_device *dev, |
| 1177 | struct net_device_stats *stats, | 1178 | struct net_device_stats *stats, |
| 1178 | u16 *cdc_filter) | 1179 | u16 *cdc_filter) |
| 1179 | { | 1180 | { |
| 1180 | DEBUG("%s:\n", __FUNCTION__ ); | 1181 | DEBUG("%s:\n", __FUNCTION__ ); |
| 1181 | if (!dev || !stats) return -1; | 1182 | if (!dev || !stats) return -1; |
| 1182 | if (configNr >= RNDIS_MAX_CONFIGS) return -1; | 1183 | if (configNr >= RNDIS_MAX_CONFIGS) return -1; |
| 1183 | 1184 | ||
| 1184 | rndis_per_dev_params [configNr].dev = dev; | 1185 | rndis_per_dev_params [configNr].dev = dev; |
| 1185 | rndis_per_dev_params [configNr].stats = stats; | 1186 | rndis_per_dev_params [configNr].stats = stats; |
| 1186 | rndis_per_dev_params [configNr].filter = cdc_filter; | 1187 | rndis_per_dev_params [configNr].filter = cdc_filter; |
| 1187 | 1188 | ||
| 1188 | return 0; | 1189 | return 0; |
| 1189 | } | 1190 | } |
| 1190 | 1191 | ||
| @@ -1193,10 +1194,10 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr) | |||
| 1193 | DEBUG("%s:\n", __FUNCTION__ ); | 1194 | DEBUG("%s:\n", __FUNCTION__ ); |
| 1194 | if (!vendorDescr) return -1; | 1195 | if (!vendorDescr) return -1; |
| 1195 | if (configNr >= RNDIS_MAX_CONFIGS) return -1; | 1196 | if (configNr >= RNDIS_MAX_CONFIGS) return -1; |
| 1196 | 1197 | ||
| 1197 | rndis_per_dev_params [configNr].vendorID = vendorID; | 1198 | rndis_per_dev_params [configNr].vendorID = vendorID; |
| 1198 | rndis_per_dev_params [configNr].vendorDescr = vendorDescr; | 1199 | rndis_per_dev_params [configNr].vendorDescr = vendorDescr; |
| 1199 | 1200 | ||
| 1200 | return 0; | 1201 | return 0; |
| 1201 | } | 1202 | } |
| 1202 | 1203 | ||
| @@ -1204,10 +1205,10 @@ int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed) | |||
| 1204 | { | 1205 | { |
| 1205 | DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed); | 1206 | DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed); |
| 1206 | if (configNr >= RNDIS_MAX_CONFIGS) return -1; | 1207 | if (configNr >= RNDIS_MAX_CONFIGS) return -1; |
| 1207 | 1208 | ||
| 1208 | rndis_per_dev_params [configNr].medium = medium; | 1209 | rndis_per_dev_params [configNr].medium = medium; |
| 1209 | rndis_per_dev_params [configNr].speed = speed; | 1210 | rndis_per_dev_params [configNr].speed = speed; |
| 1210 | 1211 | ||
| 1211 | return 0; | 1212 | return 0; |
| 1212 | } | 1213 | } |
| 1213 | 1214 | ||
| @@ -1229,9 +1230,9 @@ void rndis_free_response (int configNr, u8 *buf) | |||
| 1229 | { | 1230 | { |
| 1230 | rndis_resp_t *r; | 1231 | rndis_resp_t *r; |
| 1231 | struct list_head *act, *tmp; | 1232 | struct list_head *act, *tmp; |
| 1232 | 1233 | ||
| 1233 | list_for_each_safe (act, tmp, | 1234 | list_for_each_safe (act, tmp, |
| 1234 | &(rndis_per_dev_params [configNr].resp_queue)) | 1235 | &(rndis_per_dev_params [configNr].resp_queue)) |
| 1235 | { | 1236 | { |
| 1236 | r = list_entry (act, rndis_resp_t, list); | 1237 | r = list_entry (act, rndis_resp_t, list); |
| 1237 | if (r && r->buf == buf) { | 1238 | if (r && r->buf == buf) { |
| @@ -1244,12 +1245,12 @@ void rndis_free_response (int configNr, u8 *buf) | |||
| 1244 | u8 *rndis_get_next_response (int configNr, u32 *length) | 1245 | u8 *rndis_get_next_response (int configNr, u32 *length) |
| 1245 | { | 1246 | { |
| 1246 | rndis_resp_t *r; | 1247 | rndis_resp_t *r; |
| 1247 | struct list_head *act, *tmp; | 1248 | struct list_head *act, *tmp; |
| 1248 | 1249 | ||
| 1249 | if (!length) return NULL; | 1250 | if (!length) return NULL; |
| 1250 | 1251 | ||
| 1251 | list_for_each_safe (act, tmp, | 1252 | list_for_each_safe (act, tmp, |
| 1252 | &(rndis_per_dev_params [configNr].resp_queue)) | 1253 | &(rndis_per_dev_params [configNr].resp_queue)) |
| 1253 | { | 1254 | { |
| 1254 | r = list_entry (act, rndis_resp_t, list); | 1255 | r = list_entry (act, rndis_resp_t, list); |
| 1255 | if (!r->send) { | 1256 | if (!r->send) { |
| @@ -1258,24 +1259,24 @@ u8 *rndis_get_next_response (int configNr, u32 *length) | |||
| 1258 | return r->buf; | 1259 | return r->buf; |
| 1259 | } | 1260 | } |
| 1260 | } | 1261 | } |
| 1261 | 1262 | ||
| 1262 | return NULL; | 1263 | return NULL; |
| 1263 | } | 1264 | } |
| 1264 | 1265 | ||
| 1265 | static rndis_resp_t *rndis_add_response (int configNr, u32 length) | 1266 | static rndis_resp_t *rndis_add_response (int configNr, u32 length) |
| 1266 | { | 1267 | { |
| 1267 | rndis_resp_t *r; | 1268 | rndis_resp_t *r; |
| 1268 | 1269 | ||
| 1269 | /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */ | 1270 | /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */ |
| 1270 | r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC); | 1271 | r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC); |
| 1271 | if (!r) return NULL; | 1272 | if (!r) return NULL; |
| 1272 | 1273 | ||
| 1273 | r->buf = (u8 *) (r + 1); | 1274 | r->buf = (u8 *) (r + 1); |
| 1274 | r->length = length; | 1275 | r->length = length; |
| 1275 | r->send = 0; | 1276 | r->send = 0; |
| 1276 | 1277 | ||
| 1277 | list_add_tail (&r->list, | 1278 | list_add_tail (&r->list, |
| 1278 | &(rndis_per_dev_params [configNr].resp_queue)); | 1279 | &(rndis_per_dev_params [configNr].resp_queue)); |
| 1279 | return r; | 1280 | return r; |
| 1280 | } | 1281 | } |
| 1281 | 1282 | ||
| @@ -1301,14 +1302,14 @@ int rndis_rm_hdr(struct sk_buff *skb) | |||
| 1301 | 1302 | ||
| 1302 | #ifdef CONFIG_USB_GADGET_DEBUG_FILES | 1303 | #ifdef CONFIG_USB_GADGET_DEBUG_FILES |
| 1303 | 1304 | ||
| 1304 | static int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof, | 1305 | static int rndis_proc_read (char *page, char **start, off_t off, int count, int *eof, |
| 1305 | void *data) | 1306 | void *data) |
| 1306 | { | 1307 | { |
| 1307 | char *out = page; | 1308 | char *out = page; |
| 1308 | int len; | 1309 | int len; |
| 1309 | rndis_params *param = (rndis_params *) data; | 1310 | rndis_params *param = (rndis_params *) data; |
| 1310 | 1311 | ||
| 1311 | out += snprintf (out, count, | 1312 | out += snprintf (out, count, |
| 1312 | "Config Nr. %d\n" | 1313 | "Config Nr. %d\n" |
| 1313 | "used : %s\n" | 1314 | "used : %s\n" |
| 1314 | "state : %s\n" | 1315 | "state : %s\n" |
| @@ -1316,8 +1317,8 @@ static int rndis_proc_read (char *page, char **start, off_t off, int count, int | |||
| 1316 | "speed : %d\n" | 1317 | "speed : %d\n" |
| 1317 | "cable : %s\n" | 1318 | "cable : %s\n" |
| 1318 | "vendor ID : 0x%08X\n" | 1319 | "vendor ID : 0x%08X\n" |
| 1319 | "vendor : %s\n", | 1320 | "vendor : %s\n", |
| 1320 | param->confignr, (param->used) ? "y" : "n", | 1321 | param->confignr, (param->used) ? "y" : "n", |
| 1321 | ({ char *s = "?"; | 1322 | ({ char *s = "?"; |
| 1322 | switch (param->state) { | 1323 | switch (param->state) { |
| 1323 | case RNDIS_UNINITIALIZED: | 1324 | case RNDIS_UNINITIALIZED: |
| @@ -1327,32 +1328,32 @@ static int rndis_proc_read (char *page, char **start, off_t off, int count, int | |||
| 1327 | case RNDIS_DATA_INITIALIZED: | 1328 | case RNDIS_DATA_INITIALIZED: |
| 1328 | s = "RNDIS_DATA_INITIALIZED"; break; | 1329 | s = "RNDIS_DATA_INITIALIZED"; break; |
| 1329 | }; s; }), | 1330 | }; s; }), |
| 1330 | param->medium, | 1331 | param->medium, |
| 1331 | (param->media_state) ? 0 : param->speed*100, | 1332 | (param->media_state) ? 0 : param->speed*100, |
| 1332 | (param->media_state) ? "disconnected" : "connected", | 1333 | (param->media_state) ? "disconnected" : "connected", |
| 1333 | param->vendorID, param->vendorDescr); | 1334 | param->vendorID, param->vendorDescr); |
| 1334 | 1335 | ||
| 1335 | len = out - page; | 1336 | len = out - page; |
| 1336 | len -= off; | 1337 | len -= off; |
| 1337 | 1338 | ||
| 1338 | if (len < count) { | 1339 | if (len < count) { |
| 1339 | *eof = 1; | 1340 | *eof = 1; |
| 1340 | if (len <= 0) | 1341 | if (len <= 0) |
| 1341 | return 0; | 1342 | return 0; |
| 1342 | } else | 1343 | } else |
| 1343 | len = count; | 1344 | len = count; |
| 1344 | 1345 | ||
| 1345 | *start = page + off; | 1346 | *start = page + off; |
| 1346 | return len; | 1347 | return len; |
| 1347 | } | 1348 | } |
| 1348 | 1349 | ||
| 1349 | static int rndis_proc_write (struct file *file, const char __user *buffer, | 1350 | static int rndis_proc_write (struct file *file, const char __user *buffer, |
| 1350 | unsigned long count, void *data) | 1351 | unsigned long count, void *data) |
| 1351 | { | 1352 | { |
| 1352 | rndis_params *p = data; | 1353 | rndis_params *p = data; |
| 1353 | u32 speed = 0; | 1354 | u32 speed = 0; |
| 1354 | int i, fl_speed = 0; | 1355 | int i, fl_speed = 0; |
| 1355 | 1356 | ||
| 1356 | for (i = 0; i < count; i++) { | 1357 | for (i = 0; i < count; i++) { |
| 1357 | char c; | 1358 | char c; |
| 1358 | if (get_user(c, buffer)) | 1359 | if (get_user(c, buffer)) |
| @@ -1379,15 +1380,15 @@ static int rndis_proc_write (struct file *file, const char __user *buffer, | |||
| 1379 | case 'd': | 1380 | case 'd': |
| 1380 | rndis_signal_disconnect(p->confignr); | 1381 | rndis_signal_disconnect(p->confignr); |
| 1381 | break; | 1382 | break; |
| 1382 | default: | 1383 | default: |
| 1383 | if (fl_speed) p->speed = speed; | 1384 | if (fl_speed) p->speed = speed; |
| 1384 | else DEBUG ("%c is not valid\n", c); | 1385 | else DEBUG ("%c is not valid\n", c); |
| 1385 | break; | 1386 | break; |
| 1386 | } | 1387 | } |
| 1387 | 1388 | ||
| 1388 | buffer++; | 1389 | buffer++; |
| 1389 | } | 1390 | } |
| 1390 | 1391 | ||
| 1391 | return count; | 1392 | return count; |
| 1392 | } | 1393 | } |
| 1393 | 1394 | ||
| @@ -1408,7 +1409,7 @@ int __init rndis_init (void) | |||
| 1408 | 1409 | ||
| 1409 | sprintf (name, NAME_TEMPLATE, i); | 1410 | sprintf (name, NAME_TEMPLATE, i); |
| 1410 | if (!(rndis_connect_state [i] | 1411 | if (!(rndis_connect_state [i] |
| 1411 | = create_proc_entry (name, 0660, NULL))) | 1412 | = create_proc_entry (name, 0660, NULL))) |
| 1412 | { | 1413 | { |
| 1413 | DEBUG ("%s :remove entries", __FUNCTION__); | 1414 | DEBUG ("%s :remove entries", __FUNCTION__); |
| 1414 | while (i) { | 1415 | while (i) { |
| @@ -1432,7 +1433,7 @@ int __init rndis_init (void) | |||
| 1432 | = NDIS_MEDIA_STATE_DISCONNECTED; | 1433 | = NDIS_MEDIA_STATE_DISCONNECTED; |
| 1433 | INIT_LIST_HEAD (&(rndis_per_dev_params [i].resp_queue)); | 1434 | INIT_LIST_HEAD (&(rndis_per_dev_params [i].resp_queue)); |
| 1434 | } | 1435 | } |
| 1435 | 1436 | ||
| 1436 | return 0; | 1437 | return 0; |
| 1437 | } | 1438 | } |
| 1438 | 1439 | ||
| @@ -1441,7 +1442,7 @@ void rndis_exit (void) | |||
| 1441 | #ifdef CONFIG_USB_GADGET_DEBUG_FILES | 1442 | #ifdef CONFIG_USB_GADGET_DEBUG_FILES |
| 1442 | u8 i; | 1443 | u8 i; |
| 1443 | char name [20]; | 1444 | char name [20]; |
| 1444 | 1445 | ||
| 1445 | for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { | 1446 | for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { |
| 1446 | sprintf (name, NAME_TEMPLATE, i); | 1447 | sprintf (name, NAME_TEMPLATE, i); |
| 1447 | remove_proc_entry (name, NULL); | 1448 | remove_proc_entry (name, NULL); |
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h index 95b4c6326100..2956608be751 100644 --- a/drivers/usb/gadget/rndis.h +++ b/drivers/usb/gadget/rndis.h | |||
| @@ -1,15 +1,15 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * RNDIS Definitions for Remote NDIS | 2 | * RNDIS Definitions for Remote NDIS |
| 3 | * | 3 | * |
| 4 | * Version: $Id: rndis.h,v 1.15 2004/03/25 21:33:46 robert Exp $ | 4 | * Version: $Id: rndis.h,v 1.15 2004/03/25 21:33:46 robert Exp $ |
| 5 | * | 5 | * |
| 6 | * Authors: Benedikt Spranger, Pengutronix | 6 | * Authors: Benedikt Spranger, Pengutronix |
| 7 | * Robert Schwebel, Pengutronix | 7 | * Robert Schwebel, Pengutronix |
| 8 | * | 8 | * |
| 9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
| 11 | * version 2, as published by the Free Software Foundation. | 11 | * version 2, as published by the Free Software Foundation. |
| 12 | * | 12 | * |
| 13 | * This software was originally developed in conformance with | 13 | * This software was originally developed in conformance with |
| 14 | * Microsoft's Remote NDIS Specification License Agreement. | 14 | * Microsoft's Remote NDIS Specification License Agreement. |
| 15 | */ | 15 | */ |
| @@ -34,7 +34,7 @@ | |||
| 34 | #define RNDIS_STATUS_MEDIA_CONNECT 0x4001000BU /* Device connected */ | 34 | #define RNDIS_STATUS_MEDIA_CONNECT 0x4001000BU /* Device connected */ |
| 35 | #define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000CU /* Device disconnected */ | 35 | #define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000CU /* Device disconnected */ |
| 36 | /* For all not specified status messages: | 36 | /* For all not specified status messages: |
| 37 | * RNDIS_STATUS_Xxx -> NDIS_STATUS_Xxx | 37 | * RNDIS_STATUS_Xxx -> NDIS_STATUS_Xxx |
| 38 | */ | 38 | */ |
| 39 | 39 | ||
| 40 | /* Message Set for Connectionless (802.3) Devices */ | 40 | /* Message Set for Connectionless (802.3) Devices */ |
| @@ -69,7 +69,7 @@ | |||
| 69 | #define OID_PNP_ENABLE_WAKE_UP 0xFD010106 | 69 | #define OID_PNP_ENABLE_WAKE_UP 0xFD010106 |
| 70 | 70 | ||
| 71 | 71 | ||
| 72 | typedef struct rndis_init_msg_type | 72 | typedef struct rndis_init_msg_type |
| 73 | { | 73 | { |
| 74 | __le32 MessageType; | 74 | __le32 MessageType; |
| 75 | __le32 MessageLength; | 75 | __le32 MessageLength; |
| @@ -234,12 +234,12 @@ typedef struct rndis_params | |||
| 234 | 234 | ||
| 235 | const u8 *host_mac; | 235 | const u8 *host_mac; |
| 236 | u16 *filter; | 236 | u16 *filter; |
| 237 | struct net_device *dev; | 237 | struct net_device *dev; |
| 238 | struct net_device_stats *stats; | 238 | struct net_device_stats *stats; |
| 239 | 239 | ||
| 240 | u32 vendorID; | 240 | u32 vendorID; |
| 241 | const char *vendorDescr; | 241 | const char *vendorDescr; |
| 242 | int (*ack) (struct net_device *); | 242 | int (*ack) (struct net_device *); |
| 243 | struct list_head resp_queue; | 243 | struct list_head resp_queue; |
| 244 | } rndis_params; | 244 | } rndis_params; |
| 245 | 245 | ||
| @@ -250,7 +250,7 @@ void rndis_deregister (int configNr); | |||
| 250 | int rndis_set_param_dev (u8 configNr, struct net_device *dev, | 250 | int rndis_set_param_dev (u8 configNr, struct net_device *dev, |
| 251 | struct net_device_stats *stats, | 251 | struct net_device_stats *stats, |
| 252 | u16 *cdc_filter); | 252 | u16 *cdc_filter); |
| 253 | int rndis_set_param_vendor (u8 configNr, u32 vendorID, | 253 | int rndis_set_param_vendor (u8 configNr, u32 vendorID, |
| 254 | const char *vendorDescr); | 254 | const char *vendorDescr); |
| 255 | int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); | 255 | int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); |
| 256 | void rndis_add_hdr (struct sk_buff *skb); | 256 | void rndis_add_hdr (struct sk_buff *skb); |
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index b992546c394d..9d6e1d295528 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c | |||
| @@ -45,88 +45,16 @@ | |||
| 45 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
| 46 | 46 | ||
| 47 | #include <linux/usb_ch9.h> | 47 | #include <linux/usb_ch9.h> |
| 48 | #include <linux/usb_cdc.h> | 48 | #include <linux/usb/cdc.h> |
| 49 | #include <linux/usb_gadget.h> | 49 | #include <linux/usb_gadget.h> |
| 50 | 50 | ||
| 51 | #include "gadget_chips.h" | 51 | #include "gadget_chips.h" |
| 52 | 52 | ||
| 53 | 53 | ||
| 54 | /* Wait Cond */ | ||
| 55 | |||
| 56 | #define __wait_cond_interruptible(wq, condition, lock, flags, ret) \ | ||
| 57 | do { \ | ||
| 58 | wait_queue_t __wait; \ | ||
| 59 | init_waitqueue_entry(&__wait, current); \ | ||
| 60 | \ | ||
| 61 | add_wait_queue(&wq, &__wait); \ | ||
| 62 | for (;;) { \ | ||
| 63 | set_current_state(TASK_INTERRUPTIBLE); \ | ||
| 64 | if (condition) \ | ||
| 65 | break; \ | ||
| 66 | if (!signal_pending(current)) { \ | ||
| 67 | spin_unlock_irqrestore(lock, flags); \ | ||
| 68 | schedule(); \ | ||
| 69 | spin_lock_irqsave(lock, flags); \ | ||
| 70 | continue; \ | ||
| 71 | } \ | ||
| 72 | ret = -ERESTARTSYS; \ | ||
| 73 | break; \ | ||
| 74 | } \ | ||
| 75 | current->state = TASK_RUNNING; \ | ||
| 76 | remove_wait_queue(&wq, &__wait); \ | ||
| 77 | } while (0) | ||
| 78 | |||
| 79 | #define wait_cond_interruptible(wq, condition, lock, flags) \ | ||
| 80 | ({ \ | ||
| 81 | int __ret = 0; \ | ||
| 82 | if (!(condition)) \ | ||
| 83 | __wait_cond_interruptible(wq, condition, lock, flags, \ | ||
| 84 | __ret); \ | ||
| 85 | __ret; \ | ||
| 86 | }) | ||
| 87 | |||
| 88 | #define __wait_cond_interruptible_timeout(wq, condition, lock, flags, \ | ||
| 89 | timeout, ret) \ | ||
| 90 | do { \ | ||
| 91 | signed long __timeout = timeout; \ | ||
| 92 | wait_queue_t __wait; \ | ||
| 93 | init_waitqueue_entry(&__wait, current); \ | ||
| 94 | \ | ||
| 95 | add_wait_queue(&wq, &__wait); \ | ||
| 96 | for (;;) { \ | ||
| 97 | set_current_state(TASK_INTERRUPTIBLE); \ | ||
| 98 | if (__timeout == 0) \ | ||
| 99 | break; \ | ||
| 100 | if (condition) \ | ||
| 101 | break; \ | ||
| 102 | if (!signal_pending(current)) { \ | ||
| 103 | spin_unlock_irqrestore(lock, flags); \ | ||
| 104 | __timeout = schedule_timeout(__timeout); \ | ||
| 105 | spin_lock_irqsave(lock, flags); \ | ||
| 106 | continue; \ | ||
| 107 | } \ | ||
| 108 | ret = -ERESTARTSYS; \ | ||
| 109 | break; \ | ||
| 110 | } \ | ||
| 111 | current->state = TASK_RUNNING; \ | ||
| 112 | remove_wait_queue(&wq, &__wait); \ | ||
| 113 | } while (0) | ||
| 114 | |||
| 115 | #define wait_cond_interruptible_timeout(wq, condition, lock, flags, \ | ||
| 116 | timeout) \ | ||
| 117 | ({ \ | ||
| 118 | int __ret = 0; \ | ||
| 119 | if (!(condition)) \ | ||
| 120 | __wait_cond_interruptible_timeout(wq, condition, lock, \ | ||
| 121 | flags, timeout, __ret); \ | ||
| 122 | __ret; \ | ||
| 123 | }) | ||
| 124 | |||
| 125 | |||
| 126 | /* Defines */ | 54 | /* Defines */ |
| 127 | 55 | ||
| 128 | #define GS_VERSION_STR "v2.0" | 56 | #define GS_VERSION_STR "v2.2" |
| 129 | #define GS_VERSION_NUM 0x0200 | 57 | #define GS_VERSION_NUM 0x0202 |
| 130 | 58 | ||
| 131 | #define GS_LONG_NAME "Gadget Serial" | 59 | #define GS_LONG_NAME "Gadget Serial" |
| 132 | #define GS_SHORT_NAME "g_serial" | 60 | #define GS_SHORT_NAME "g_serial" |
| @@ -843,9 +771,19 @@ exit_unlock_dev: | |||
| 843 | /* | 771 | /* |
| 844 | * gs_close | 772 | * gs_close |
| 845 | */ | 773 | */ |
| 774 | |||
| 775 | #define GS_WRITE_FINISHED_EVENT_SAFELY(p) \ | ||
| 776 | ({ \ | ||
| 777 | int cond; \ | ||
| 778 | \ | ||
| 779 | spin_lock_irq(&(p)->port_lock); \ | ||
| 780 | cond = !(p)->port_dev || !gs_buf_data_avail((p)->port_write_buf); \ | ||
| 781 | spin_unlock_irq(&(p)->port_lock); \ | ||
| 782 | cond; \ | ||
| 783 | }) | ||
| 784 | |||
| 846 | static void gs_close(struct tty_struct *tty, struct file *file) | 785 | static void gs_close(struct tty_struct *tty, struct file *file) |
| 847 | { | 786 | { |
| 848 | unsigned long flags; | ||
| 849 | struct gs_port *port = tty->driver_data; | 787 | struct gs_port *port = tty->driver_data; |
| 850 | struct semaphore *sem; | 788 | struct semaphore *sem; |
| 851 | 789 | ||
| @@ -859,7 +797,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) | |||
| 859 | sem = &gs_open_close_sem[port->port_num]; | 797 | sem = &gs_open_close_sem[port->port_num]; |
| 860 | down(sem); | 798 | down(sem); |
| 861 | 799 | ||
| 862 | spin_lock_irqsave(&port->port_lock, flags); | 800 | spin_lock_irq(&port->port_lock); |
| 863 | 801 | ||
| 864 | if (port->port_open_count == 0) { | 802 | if (port->port_open_count == 0) { |
| 865 | printk(KERN_ERR | 803 | printk(KERN_ERR |
| @@ -887,12 +825,11 @@ static void gs_close(struct tty_struct *tty, struct file *file) | |||
| 887 | /* wait for write buffer to drain, or */ | 825 | /* wait for write buffer to drain, or */ |
| 888 | /* at most GS_CLOSE_TIMEOUT seconds */ | 826 | /* at most GS_CLOSE_TIMEOUT seconds */ |
| 889 | if (gs_buf_data_avail(port->port_write_buf) > 0) { | 827 | if (gs_buf_data_avail(port->port_write_buf) > 0) { |
| 890 | spin_unlock_irqrestore(&port->port_lock, flags); | 828 | spin_unlock_irq(&port->port_lock); |
| 891 | wait_cond_interruptible_timeout(port->port_write_wait, | 829 | wait_event_interruptible_timeout(port->port_write_wait, |
| 892 | port->port_dev == NULL | 830 | GS_WRITE_FINISHED_EVENT_SAFELY(port), |
| 893 | || gs_buf_data_avail(port->port_write_buf) == 0, | 831 | GS_CLOSE_TIMEOUT * HZ); |
| 894 | &port->port_lock, flags, GS_CLOSE_TIMEOUT * HZ); | 832 | spin_lock_irq(&port->port_lock); |
| 895 | spin_lock_irqsave(&port->port_lock, flags); | ||
| 896 | } | 833 | } |
| 897 | 834 | ||
| 898 | /* free disconnected port on final close */ | 835 | /* free disconnected port on final close */ |
| @@ -912,7 +849,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) | |||
| 912 | port->port_num, tty, file); | 849 | port->port_num, tty, file); |
| 913 | 850 | ||
| 914 | exit: | 851 | exit: |
| 915 | spin_unlock_irqrestore(&port->port_lock, flags); | 852 | spin_unlock_irq(&port->port_lock); |
| 916 | up(sem); | 853 | up(sem); |
| 917 | } | 854 | } |
| 918 | 855 | ||
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index e27b79a3c05f..c060eb9b3b19 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig | |||
| @@ -47,7 +47,25 @@ config USB_EHCI_ROOT_HUB_TT | |||
| 47 | controller is needed. It's safe to say "y" even if your | 47 | controller is needed. It's safe to say "y" even if your |
| 48 | controller doesn't support this feature. | 48 | controller doesn't support this feature. |
| 49 | 49 | ||
| 50 | This supports the EHCI implementation from TransDimension Inc. | 50 | This supports the EHCI implementation that's originally |
| 51 | from ARC, and has since changed hands a few times. | ||
| 52 | |||
| 53 | config USB_EHCI_TT_NEWSCHED | ||
| 54 | bool "Improved Transaction Translator scheduling (EXPERIMENTAL)" | ||
| 55 | depends on USB_EHCI_HCD && EXPERIMENTAL | ||
| 56 | ---help--- | ||
| 57 | This changes the periodic scheduling code to fill more of the low | ||
| 58 | and full speed bandwidth available from the Transaction Translator | ||
| 59 | (TT) in USB 2.0 hubs. Without this, only one transfer will be | ||
| 60 | issued in each microframe, significantly reducing the number of | ||
| 61 | periodic low/fullspeed transfers possible. | ||
| 62 | |||
| 63 | If you have multiple periodic low/fullspeed devices connected to a | ||
| 64 | highspeed USB hub which is connected to a highspeed USB Host | ||
| 65 | Controller, and some of those devices will not work correctly | ||
| 66 | (possibly due to "ENOSPC" or "-28" errors), say Y. | ||
| 67 | |||
| 68 | If unsure, say N. | ||
| 51 | 69 | ||
| 52 | config USB_ISP116X_HCD | 70 | config USB_ISP116X_HCD |
| 53 | tristate "ISP116X HCD support" | 71 | tristate "ISP116X HCD support" |
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c index 63eadeec1324..9b4697add313 100644 --- a/drivers/usb/host/ehci-au1xxx.c +++ b/drivers/usb/host/ehci-au1xxx.c | |||
| @@ -16,10 +16,6 @@ | |||
| 16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
| 17 | #include <asm/mach-au1x00/au1000.h> | 17 | #include <asm/mach-au1x00/au1000.h> |
| 18 | 18 | ||
| 19 | #ifndef CONFIG_SOC_AU1200 | ||
| 20 | #error "this Alchemy chip doesn't have EHCI" | ||
| 21 | #else /* Au1200 */ | ||
| 22 | |||
| 23 | #define USB_HOST_CONFIG (USB_MSR_BASE + USB_MSR_MCFG) | 19 | #define USB_HOST_CONFIG (USB_MSR_BASE + USB_MSR_MCFG) |
| 24 | #define USB_MCFG_PFEN (1<<31) | 20 | #define USB_MCFG_PFEN (1<<31) |
| 25 | #define USB_MCFG_RDCOMB (1<<30) | 21 | #define USB_MCFG_RDCOMB (1<<30) |
| @@ -272,6 +268,8 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev) | |||
| 272 | return 0; | 268 | return 0; |
| 273 | } | 269 | } |
| 274 | */ | 270 | */ |
| 271 | MODULE_ALIAS("au1xxx-ehci"); | ||
| 272 | /* FIXME use "struct platform_driver" */ | ||
| 275 | static struct device_driver ehci_hcd_au1xxx_driver = { | 273 | static struct device_driver ehci_hcd_au1xxx_driver = { |
| 276 | .name = "au1xxx-ehci", | 274 | .name = "au1xxx-ehci", |
| 277 | .bus = &platform_bus_type, | 275 | .bus = &platform_bus_type, |
| @@ -280,18 +278,3 @@ static struct device_driver ehci_hcd_au1xxx_driver = { | |||
| 280 | /*.suspend = ehci_hcd_au1xxx_drv_suspend, */ | 278 | /*.suspend = ehci_hcd_au1xxx_drv_suspend, */ |
| 281 | /*.resume = ehci_hcd_au1xxx_drv_resume, */ | 279 | /*.resume = ehci_hcd_au1xxx_drv_resume, */ |
| 282 | }; | 280 | }; |
| 283 | |||
| 284 | static int __init ehci_hcd_au1xxx_init(void) | ||
| 285 | { | ||
| 286 | pr_debug(DRIVER_INFO " (Au1xxx)\n"); | ||
| 287 | |||
| 288 | return driver_register(&ehci_hcd_au1xxx_driver); | ||
| 289 | } | ||
| 290 | |||
| 291 | static void __exit ehci_hcd_au1xxx_cleanup(void) | ||
| 292 | { | ||
| 293 | driver_unregister(&ehci_hcd_au1xxx_driver); | ||
| 294 | } | ||
| 295 | |||
| 296 | module_init(ehci_hcd_au1xxx_init); | ||
| 297 | module_exit(ehci_hcd_au1xxx_cleanup); | ||
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index f985f121a245..a49a689bf423 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c | |||
| @@ -324,43 +324,12 @@ static int ehci_fsl_drv_remove(struct platform_device *pdev) | |||
| 324 | return 0; | 324 | return 0; |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | static struct platform_driver ehci_fsl_dr_driver = { | 327 | MODULE_ALIAS("fsl-ehci"); |
| 328 | .probe = ehci_fsl_drv_probe, | ||
| 329 | .remove = ehci_fsl_drv_remove, | ||
| 330 | .driver = { | ||
| 331 | .name = "fsl-usb2-dr", | ||
| 332 | }, | ||
| 333 | }; | ||
| 334 | 328 | ||
| 335 | static struct platform_driver ehci_fsl_mph_driver = { | 329 | static struct platform_driver ehci_fsl_driver = { |
| 336 | .probe = ehci_fsl_drv_probe, | 330 | .probe = ehci_fsl_drv_probe, |
| 337 | .remove = ehci_fsl_drv_remove, | 331 | .remove = ehci_fsl_drv_remove, |
| 338 | .driver = { | 332 | .driver = { |
| 339 | .name = "fsl-usb2-mph", | 333 | .name = "fsl-ehci", |
| 340 | }, | 334 | }, |
| 341 | }; | 335 | }; |
| 342 | |||
| 343 | static int __init ehci_fsl_init(void) | ||
| 344 | { | ||
| 345 | int retval; | ||
| 346 | |||
| 347 | pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", | ||
| 348 | hcd_name, | ||
| 349 | sizeof(struct ehci_qh), sizeof(struct ehci_qtd), | ||
| 350 | sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); | ||
| 351 | |||
| 352 | retval = platform_driver_register(&ehci_fsl_dr_driver); | ||
| 353 | if (retval) | ||
| 354 | return retval; | ||
| 355 | |||
| 356 | return platform_driver_register(&ehci_fsl_mph_driver); | ||
| 357 | } | ||
| 358 | |||
| 359 | static void __exit ehci_fsl_cleanup(void) | ||
| 360 | { | ||
| 361 | platform_driver_unregister(&ehci_fsl_mph_driver); | ||
| 362 | platform_driver_unregister(&ehci_fsl_dr_driver); | ||
| 363 | } | ||
| 364 | |||
| 365 | module_init(ehci_fsl_init); | ||
| 366 | module_exit(ehci_fsl_cleanup); | ||
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 79f2d8b9bfb6..9b37e508ada3 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
| @@ -889,19 +889,59 @@ MODULE_LICENSE ("GPL"); | |||
| 889 | 889 | ||
| 890 | #ifdef CONFIG_PCI | 890 | #ifdef CONFIG_PCI |
| 891 | #include "ehci-pci.c" | 891 | #include "ehci-pci.c" |
| 892 | #define EHCI_BUS_GLUED | 892 | #define PCI_DRIVER ehci_pci_driver |
| 893 | #endif | 893 | #endif |
| 894 | 894 | ||
| 895 | #ifdef CONFIG_PPC_83xx | 895 | #ifdef CONFIG_PPC_83xx |
| 896 | #include "ehci-fsl.c" | 896 | #include "ehci-fsl.c" |
| 897 | #define EHCI_BUS_GLUED | 897 | #define PLATFORM_DRIVER ehci_fsl_driver |
| 898 | #endif | 898 | #endif |
| 899 | 899 | ||
| 900 | #ifdef CONFIG_SOC_AU1X00 | 900 | #ifdef CONFIG_SOC_AU1200 |
| 901 | #include "ehci-au1xxx.c" | 901 | #include "ehci-au1xxx.c" |
| 902 | #define EHCI_BUS_GLUED | 902 | #define PLATFORM_DRIVER ehci_hcd_au1xxx_driver |
| 903 | #endif | 903 | #endif |
| 904 | 904 | ||
| 905 | #ifndef EHCI_BUS_GLUED | 905 | #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) |
| 906 | #error "missing bus glue for ehci-hcd" | 906 | #error "missing bus glue for ehci-hcd" |
| 907 | #endif | 907 | #endif |
| 908 | |||
| 909 | static int __init ehci_hcd_init(void) | ||
| 910 | { | ||
| 911 | int retval = 0; | ||
| 912 | |||
| 913 | pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", | ||
| 914 | hcd_name, | ||
| 915 | sizeof(struct ehci_qh), sizeof(struct ehci_qtd), | ||
| 916 | sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); | ||
| 917 | |||
| 918 | #ifdef PLATFORM_DRIVER | ||
| 919 | retval = platform_driver_register(&PLATFORM_DRIVER); | ||
| 920 | if (retval < 0) | ||
| 921 | return retval; | ||
| 922 | #endif | ||
| 923 | |||
| 924 | #ifdef PCI_DRIVER | ||
| 925 | retval = pci_register_driver(&PCI_DRIVER); | ||
| 926 | if (retval < 0) { | ||
| 927 | #ifdef PLATFORM_DRIVER | ||
| 928 | platform_driver_unregister(&PLATFORM_DRIVER); | ||
| 929 | #endif | ||
| 930 | } | ||
| 931 | #endif | ||
| 932 | |||
| 933 | return retval; | ||
| 934 | } | ||
| 935 | module_init(ehci_hcd_init); | ||
| 936 | |||
| 937 | static void __exit ehci_hcd_cleanup(void) | ||
| 938 | { | ||
| 939 | #ifdef PLATFORM_DRIVER | ||
| 940 | platform_driver_unregister(&PLATFORM_DRIVER); | ||
| 941 | #endif | ||
| 942 | #ifdef PCI_DRIVER | ||
| 943 | pci_unregister_driver(&PCI_DRIVER); | ||
| 944 | #endif | ||
| 945 | } | ||
| 946 | module_exit(ehci_hcd_cleanup); | ||
| 947 | |||
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index a1bd2bea6deb..cadffacd945b 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c | |||
| @@ -76,6 +76,30 @@ static int ehci_pci_setup(struct usb_hcd *hcd) | |||
| 76 | dbg_hcs_params(ehci, "reset"); | 76 | dbg_hcs_params(ehci, "reset"); |
| 77 | dbg_hcc_params(ehci, "reset"); | 77 | dbg_hcc_params(ehci, "reset"); |
| 78 | 78 | ||
| 79 | /* ehci_init() causes memory for DMA transfers to be | ||
| 80 | * allocated. Thus, any vendor-specific workarounds based on | ||
| 81 | * limiting the type of memory used for DMA transfers must | ||
| 82 | * happen before ehci_init() is called. */ | ||
| 83 | switch (pdev->vendor) { | ||
| 84 | case PCI_VENDOR_ID_NVIDIA: | ||
| 85 | /* NVidia reports that certain chips don't handle | ||
| 86 | * QH, ITD, or SITD addresses above 2GB. (But TD, | ||
| 87 | * data buffer, and periodic schedule are normal.) | ||
| 88 | */ | ||
| 89 | switch (pdev->device) { | ||
| 90 | case 0x003c: /* MCP04 */ | ||
| 91 | case 0x005b: /* CK804 */ | ||
| 92 | case 0x00d8: /* CK8 */ | ||
| 93 | case 0x00e8: /* CK8S */ | ||
| 94 | if (pci_set_consistent_dma_mask(pdev, | ||
| 95 | DMA_31BIT_MASK) < 0) | ||
| 96 | ehci_warn(ehci, "can't enable NVidia " | ||
| 97 | "workaround for >2GB RAM\n"); | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | break; | ||
| 101 | } | ||
| 102 | |||
| 79 | /* cache this readonly data; minimize chip reads */ | 103 | /* cache this readonly data; minimize chip reads */ |
| 80 | ehci->hcs_params = readl(&ehci->caps->hcs_params); | 104 | ehci->hcs_params = readl(&ehci->caps->hcs_params); |
| 81 | 105 | ||
| @@ -88,8 +112,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) | |||
| 88 | if (retval) | 112 | if (retval) |
| 89 | return retval; | 113 | return retval; |
| 90 | 114 | ||
| 91 | /* NOTE: only the parts below this line are PCI-specific */ | ||
| 92 | |||
| 93 | switch (pdev->vendor) { | 115 | switch (pdev->vendor) { |
| 94 | case PCI_VENDOR_ID_TDI: | 116 | case PCI_VENDOR_ID_TDI: |
| 95 | if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { | 117 | if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { |
| @@ -107,19 +129,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) | |||
| 107 | break; | 129 | break; |
| 108 | case PCI_VENDOR_ID_NVIDIA: | 130 | case PCI_VENDOR_ID_NVIDIA: |
| 109 | switch (pdev->device) { | 131 | switch (pdev->device) { |
| 110 | /* NVidia reports that certain chips don't handle | ||
| 111 | * QH, ITD, or SITD addresses above 2GB. (But TD, | ||
| 112 | * data buffer, and periodic schedule are normal.) | ||
| 113 | */ | ||
| 114 | case 0x003c: /* MCP04 */ | ||
| 115 | case 0x005b: /* CK804 */ | ||
| 116 | case 0x00d8: /* CK8 */ | ||
| 117 | case 0x00e8: /* CK8S */ | ||
| 118 | if (pci_set_consistent_dma_mask(pdev, | ||
| 119 | DMA_31BIT_MASK) < 0) | ||
| 120 | ehci_warn(ehci, "can't enable NVidia " | ||
| 121 | "workaround for >2GB RAM\n"); | ||
| 122 | break; | ||
| 123 | /* Some NForce2 chips have problems with selective suspend; | 132 | /* Some NForce2 chips have problems with selective suspend; |
| 124 | * fixed in newer silicon. | 133 | * fixed in newer silicon. |
| 125 | */ | 134 | */ |
| @@ -370,23 +379,3 @@ static struct pci_driver ehci_pci_driver = { | |||
| 370 | .resume = usb_hcd_pci_resume, | 379 | .resume = usb_hcd_pci_resume, |
| 371 | #endif | 380 | #endif |
| 372 | }; | 381 | }; |
| 373 | |||
| 374 | static int __init ehci_hcd_pci_init(void) | ||
| 375 | { | ||
| 376 | if (usb_disabled()) | ||
| 377 | return -ENODEV; | ||
| 378 | |||
| 379 | pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", | ||
| 380 | hcd_name, | ||
| 381 | sizeof(struct ehci_qh), sizeof(struct ehci_qtd), | ||
| 382 | sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); | ||
| 383 | |||
| 384 | return pci_register_driver(&ehci_pci_driver); | ||
| 385 | } | ||
| 386 | module_init(ehci_hcd_pci_init); | ||
| 387 | |||
| 388 | static void __exit ehci_hcd_pci_cleanup(void) | ||
| 389 | { | ||
| 390 | pci_unregister_driver(&ehci_pci_driver); | ||
| 391 | } | ||
| 392 | module_exit(ehci_hcd_pci_cleanup); | ||
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 5871944e6145..4859900bd135 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
| @@ -163,6 +163,190 @@ static int same_tt (struct usb_device *dev1, struct usb_device *dev2) | |||
| 163 | return 1; | 163 | return 1; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | #ifdef CONFIG_USB_EHCI_TT_NEWSCHED | ||
| 167 | |||
| 168 | /* Which uframe does the low/fullspeed transfer start in? | ||
| 169 | * | ||
| 170 | * The parameter is the mask of ssplits in "H-frame" terms | ||
| 171 | * and this returns the transfer start uframe in "B-frame" terms, | ||
| 172 | * which allows both to match, e.g. a ssplit in "H-frame" uframe 0 | ||
| 173 | * will cause a transfer in "B-frame" uframe 0. "B-frames" lag | ||
| 174 | * "H-frames" by 1 uframe. See the EHCI spec sec 4.5 and figure 4.7. | ||
| 175 | */ | ||
| 176 | static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __le32 mask) | ||
| 177 | { | ||
| 178 | unsigned char smask = QH_SMASK & le32_to_cpu(mask); | ||
| 179 | if (!smask) { | ||
| 180 | ehci_err(ehci, "invalid empty smask!\n"); | ||
| 181 | /* uframe 7 can't have bw so this will indicate failure */ | ||
| 182 | return 7; | ||
| 183 | } | ||
| 184 | return ffs(smask) - 1; | ||
| 185 | } | ||
| 186 | |||
| 187 | static const unsigned char | ||
| 188 | max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 }; | ||
| 189 | |||
| 190 | /* carryover low/fullspeed bandwidth that crosses uframe boundries */ | ||
| 191 | static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) | ||
| 192 | { | ||
| 193 | int i; | ||
| 194 | for (i=0; i<7; i++) { | ||
| 195 | if (max_tt_usecs[i] < tt_usecs[i]) { | ||
| 196 | tt_usecs[i+1] += tt_usecs[i] - max_tt_usecs[i]; | ||
| 197 | tt_usecs[i] = max_tt_usecs[i]; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | /* How many of the tt's periodic downstream 1000 usecs are allocated? | ||
| 203 | * | ||
| 204 | * While this measures the bandwidth in terms of usecs/uframe, | ||
| 205 | * the low/fullspeed bus has no notion of uframes, so any particular | ||
| 206 | * low/fullspeed transfer can "carry over" from one uframe to the next, | ||
| 207 | * since the TT just performs downstream transfers in sequence. | ||
| 208 | * | ||
| 209 | * For example two seperate 100 usec transfers can start in the same uframe, | ||
| 210 | * and the second one would "carry over" 75 usecs into the next uframe. | ||
| 211 | */ | ||
| 212 | static void | ||
| 213 | periodic_tt_usecs ( | ||
| 214 | struct ehci_hcd *ehci, | ||
| 215 | struct usb_device *dev, | ||
| 216 | unsigned frame, | ||
| 217 | unsigned short tt_usecs[8] | ||
| 218 | ) | ||
| 219 | { | ||
| 220 | __le32 *hw_p = &ehci->periodic [frame]; | ||
| 221 | union ehci_shadow *q = &ehci->pshadow [frame]; | ||
| 222 | unsigned char uf; | ||
| 223 | |||
| 224 | memset(tt_usecs, 0, 16); | ||
| 225 | |||
| 226 | while (q->ptr) { | ||
| 227 | switch (Q_NEXT_TYPE(*hw_p)) { | ||
| 228 | case Q_TYPE_ITD: | ||
| 229 | hw_p = &q->itd->hw_next; | ||
| 230 | q = &q->itd->itd_next; | ||
| 231 | continue; | ||
| 232 | case Q_TYPE_QH: | ||
| 233 | if (same_tt(dev, q->qh->dev)) { | ||
| 234 | uf = tt_start_uframe(ehci, q->qh->hw_info2); | ||
| 235 | tt_usecs[uf] += q->qh->tt_usecs; | ||
| 236 | } | ||
| 237 | hw_p = &q->qh->hw_next; | ||
| 238 | q = &q->qh->qh_next; | ||
| 239 | continue; | ||
| 240 | case Q_TYPE_SITD: | ||
| 241 | if (same_tt(dev, q->sitd->urb->dev)) { | ||
| 242 | uf = tt_start_uframe(ehci, q->sitd->hw_uframe); | ||
| 243 | tt_usecs[uf] += q->sitd->stream->tt_usecs; | ||
| 244 | } | ||
| 245 | hw_p = &q->sitd->hw_next; | ||
| 246 | q = &q->sitd->sitd_next; | ||
| 247 | continue; | ||
| 248 | // case Q_TYPE_FSTN: | ||
| 249 | default: | ||
| 250 | ehci_dbg(ehci, | ||
| 251 | "ignoring periodic frame %d FSTN\n", frame); | ||
| 252 | hw_p = &q->fstn->hw_next; | ||
| 253 | q = &q->fstn->fstn_next; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | carryover_tt_bandwidth(tt_usecs); | ||
| 258 | |||
| 259 | if (max_tt_usecs[7] < tt_usecs[7]) | ||
| 260 | ehci_err(ehci, "frame %d tt sched overrun: %d usecs\n", | ||
| 261 | frame, tt_usecs[7] - max_tt_usecs[7]); | ||
| 262 | } | ||
| 263 | |||
| 264 | /* | ||
| 265 | * Return true if the device's tt's downstream bus is available for a | ||
| 266 | * periodic transfer of the specified length (usecs), starting at the | ||
| 267 | * specified frame/uframe. Note that (as summarized in section 11.19 | ||
| 268 | * of the usb 2.0 spec) TTs can buffer multiple transactions for each | ||
| 269 | * uframe. | ||
| 270 | * | ||
| 271 | * The uframe parameter is when the fullspeed/lowspeed transfer | ||
| 272 | * should be executed in "B-frame" terms, which is the same as the | ||
| 273 | * highspeed ssplit's uframe (which is in "H-frame" terms). For example | ||
| 274 | * a ssplit in "H-frame" 0 causes a transfer in "B-frame" 0. | ||
| 275 | * See the EHCI spec sec 4.5 and fig 4.7. | ||
| 276 | * | ||
| 277 | * This checks if the full/lowspeed bus, at the specified starting uframe, | ||
| 278 | * has the specified bandwidth available, according to rules listed | ||
| 279 | * in USB 2.0 spec section 11.18.1 fig 11-60. | ||
| 280 | * | ||
| 281 | * This does not check if the transfer would exceed the max ssplit | ||
| 282 | * limit of 16, specified in USB 2.0 spec section 11.18.4 requirement #4, | ||
| 283 | * since proper scheduling limits ssplits to less than 16 per uframe. | ||
| 284 | */ | ||
| 285 | static int tt_available ( | ||
| 286 | struct ehci_hcd *ehci, | ||
| 287 | unsigned period, | ||
| 288 | struct usb_device *dev, | ||
| 289 | unsigned frame, | ||
| 290 | unsigned uframe, | ||
| 291 | u16 usecs | ||
| 292 | ) | ||
| 293 | { | ||
| 294 | if ((period == 0) || (uframe >= 7)) /* error */ | ||
| 295 | return 0; | ||
| 296 | |||
| 297 | for (; frame < ehci->periodic_size; frame += period) { | ||
| 298 | unsigned short tt_usecs[8]; | ||
| 299 | |||
| 300 | periodic_tt_usecs (ehci, dev, frame, tt_usecs); | ||
| 301 | |||
| 302 | ehci_vdbg(ehci, "tt frame %d check %d usecs start uframe %d in" | ||
| 303 | " schedule %d/%d/%d/%d/%d/%d/%d/%d\n", | ||
| 304 | frame, usecs, uframe, | ||
| 305 | tt_usecs[0], tt_usecs[1], tt_usecs[2], tt_usecs[3], | ||
| 306 | tt_usecs[4], tt_usecs[5], tt_usecs[6], tt_usecs[7]); | ||
| 307 | |||
| 308 | if (max_tt_usecs[uframe] <= tt_usecs[uframe]) { | ||
| 309 | ehci_vdbg(ehci, "frame %d uframe %d fully scheduled\n", | ||
| 310 | frame, uframe); | ||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | /* special case for isoc transfers larger than 125us: | ||
| 315 | * the first and each subsequent fully used uframe | ||
| 316 | * must be empty, so as to not illegally delay | ||
| 317 | * already scheduled transactions | ||
| 318 | */ | ||
| 319 | if (125 < usecs) { | ||
| 320 | int ufs = (usecs / 125) - 1; | ||
| 321 | int i; | ||
| 322 | for (i = uframe; i < (uframe + ufs) && i < 8; i++) | ||
| 323 | if (0 < tt_usecs[i]) { | ||
| 324 | ehci_vdbg(ehci, | ||
| 325 | "multi-uframe xfer can't fit " | ||
| 326 | "in frame %d uframe %d\n", | ||
| 327 | frame, i); | ||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | tt_usecs[uframe] += usecs; | ||
| 333 | |||
| 334 | carryover_tt_bandwidth(tt_usecs); | ||
| 335 | |||
| 336 | /* fail if the carryover pushed bw past the last uframe's limit */ | ||
| 337 | if (max_tt_usecs[7] < tt_usecs[7]) { | ||
| 338 | ehci_vdbg(ehci, | ||
| 339 | "tt unavailable usecs %d frame %d uframe %d\n", | ||
| 340 | usecs, frame, uframe); | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | return 1; | ||
| 346 | } | ||
| 347 | |||
| 348 | #else | ||
| 349 | |||
| 166 | /* return true iff the device's transaction translator is available | 350 | /* return true iff the device's transaction translator is available |
| 167 | * for a periodic transfer starting at the specified frame, using | 351 | * for a periodic transfer starting at the specified frame, using |
| 168 | * all the uframes in the mask. | 352 | * all the uframes in the mask. |
| @@ -237,6 +421,8 @@ static int tt_no_collision ( | |||
| 237 | return 1; | 421 | return 1; |
| 238 | } | 422 | } |
| 239 | 423 | ||
| 424 | #endif /* CONFIG_USB_EHCI_TT_NEWSCHED */ | ||
| 425 | |||
| 240 | /*-------------------------------------------------------------------------*/ | 426 | /*-------------------------------------------------------------------------*/ |
| 241 | 427 | ||
| 242 | static int enable_periodic (struct ehci_hcd *ehci) | 428 | static int enable_periodic (struct ehci_hcd *ehci) |
| @@ -481,7 +667,7 @@ static int check_intr_schedule ( | |||
| 481 | ) | 667 | ) |
| 482 | { | 668 | { |
| 483 | int retval = -ENOSPC; | 669 | int retval = -ENOSPC; |
| 484 | u8 mask; | 670 | u8 mask = 0; |
| 485 | 671 | ||
| 486 | if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ | 672 | if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ |
| 487 | goto done; | 673 | goto done; |
| @@ -494,6 +680,24 @@ static int check_intr_schedule ( | |||
| 494 | goto done; | 680 | goto done; |
| 495 | } | 681 | } |
| 496 | 682 | ||
| 683 | #ifdef CONFIG_USB_EHCI_TT_NEWSCHED | ||
| 684 | if (tt_available (ehci, qh->period, qh->dev, frame, uframe, | ||
| 685 | qh->tt_usecs)) { | ||
| 686 | unsigned i; | ||
| 687 | |||
| 688 | /* TODO : this may need FSTN for SSPLIT in uframe 5. */ | ||
| 689 | for (i=uframe+1; i<8 && i<uframe+4; i++) | ||
| 690 | if (!check_period (ehci, frame, i, | ||
| 691 | qh->period, qh->c_usecs)) | ||
| 692 | goto done; | ||
| 693 | else | ||
| 694 | mask |= 1 << i; | ||
| 695 | |||
| 696 | retval = 0; | ||
| 697 | |||
| 698 | *c_maskp = cpu_to_le32 (mask << 8); | ||
| 699 | } | ||
| 700 | #else | ||
| 497 | /* Make sure this tt's buffer is also available for CSPLITs. | 701 | /* Make sure this tt's buffer is also available for CSPLITs. |
| 498 | * We pessimize a bit; probably the typical full speed case | 702 | * We pessimize a bit; probably the typical full speed case |
| 499 | * doesn't need the second CSPLIT. | 703 | * doesn't need the second CSPLIT. |
| @@ -514,6 +718,7 @@ static int check_intr_schedule ( | |||
| 514 | goto done; | 718 | goto done; |
| 515 | retval = 0; | 719 | retval = 0; |
| 516 | } | 720 | } |
| 721 | #endif | ||
| 517 | done: | 722 | done: |
| 518 | return retval; | 723 | return retval; |
| 519 | } | 724 | } |
| @@ -1047,12 +1252,21 @@ sitd_slot_ok ( | |||
| 1047 | frame = uframe >> 3; | 1252 | frame = uframe >> 3; |
| 1048 | uf = uframe & 7; | 1253 | uf = uframe & 7; |
| 1049 | 1254 | ||
| 1255 | #ifdef CONFIG_USB_EHCI_TT_NEWSCHED | ||
| 1256 | /* The tt's fullspeed bus bandwidth must be available. | ||
| 1257 | * tt_available scheduling guarantees 10+% for control/bulk. | ||
| 1258 | */ | ||
| 1259 | if (!tt_available (ehci, period_uframes << 3, | ||
| 1260 | stream->udev, frame, uf, stream->tt_usecs)) | ||
| 1261 | return 0; | ||
| 1262 | #else | ||
| 1050 | /* tt must be idle for start(s), any gap, and csplit. | 1263 | /* tt must be idle for start(s), any gap, and csplit. |
| 1051 | * assume scheduling slop leaves 10+% for control/bulk. | 1264 | * assume scheduling slop leaves 10+% for control/bulk. |
| 1052 | */ | 1265 | */ |
| 1053 | if (!tt_no_collision (ehci, period_uframes << 3, | 1266 | if (!tt_no_collision (ehci, period_uframes << 3, |
| 1054 | stream->udev, frame, mask)) | 1267 | stream->udev, frame, mask)) |
| 1055 | return 0; | 1268 | return 0; |
| 1269 | #endif | ||
| 1056 | 1270 | ||
| 1057 | /* check starts (OUT uses more than one) */ | 1271 | /* check starts (OUT uses more than one) */ |
| 1058 | max_used = 100 - stream->usecs; | 1272 | max_used = 100 - stream->usecs; |
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index e99210b7909b..14386254c870 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c | |||
| @@ -63,7 +63,7 @@ | |||
| 63 | #include <linux/init.h> | 63 | #include <linux/init.h> |
| 64 | #include <linux/list.h> | 64 | #include <linux/list.h> |
| 65 | #include <linux/usb.h> | 65 | #include <linux/usb.h> |
| 66 | #include <linux/usb_isp116x.h> | 66 | #include <linux/usb/isp116x.h> |
| 67 | #include <linux/platform_device.h> | 67 | #include <linux/platform_device.h> |
| 68 | 68 | ||
| 69 | #include <asm/io.h> | 69 | #include <asm/io.h> |
| @@ -781,7 +781,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, | |||
| 781 | if (ep->branch < PERIODIC_SIZE) | 781 | if (ep->branch < PERIODIC_SIZE) |
| 782 | break; | 782 | break; |
| 783 | 783 | ||
| 784 | ret = ep->branch = balance(isp116x, ep->period, ep->load); | 784 | ep->branch = ret = balance(isp116x, ep->period, ep->load); |
| 785 | if (ret < 0) | 785 | if (ret < 0) |
| 786 | goto fail; | 786 | goto fail; |
| 787 | ret = 0; | 787 | ret = 0; |
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index a92343052751..6b4bc3f2bd86 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c | |||
| @@ -46,7 +46,7 @@ | |||
| 46 | #include <linux/list.h> | 46 | #include <linux/list.h> |
| 47 | #include <linux/interrupt.h> | 47 | #include <linux/interrupt.h> |
| 48 | #include <linux/usb.h> | 48 | #include <linux/usb.h> |
| 49 | #include <linux/usb_sl811.h> | 49 | #include <linux/usb/sl811.h> |
| 50 | #include <linux/platform_device.h> | 50 | #include <linux/platform_device.h> |
| 51 | 51 | ||
| 52 | #include <asm/io.h> | 52 | #include <asm/io.h> |
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 302aa1ec312f..54f554e0f0ad 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | #include <pcmcia/cisreg.h> | 27 | #include <pcmcia/cisreg.h> |
| 28 | #include <pcmcia/ds.h> | 28 | #include <pcmcia/ds.h> |
| 29 | 29 | ||
| 30 | #include <linux/usb_sl811.h> | 30 | #include <linux/usb/sl811.h> |
| 31 | 31 | ||
| 32 | MODULE_AUTHOR("Botond Botyanszki"); | 32 | MODULE_AUTHOR("Botond Botyanszki"); |
| 33 | MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6"); | 33 | MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6"); |
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index e1239319655c..6637a0e49978 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c | |||
| @@ -98,6 +98,7 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) | |||
| 98 | char *out = buf; | 98 | char *out = buf; |
| 99 | struct uhci_td *td; | 99 | struct uhci_td *td; |
| 100 | int i, nactive, ninactive; | 100 | int i, nactive, ninactive; |
| 101 | char *ptype; | ||
| 101 | 102 | ||
| 102 | if (len < 200) | 103 | if (len < 200) |
| 103 | return 0; | 104 | return 0; |
| @@ -110,13 +111,15 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) | |||
| 110 | (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT")); | 111 | (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT")); |
| 111 | 112 | ||
| 112 | switch (usb_pipetype(urbp->urb->pipe)) { | 113 | switch (usb_pipetype(urbp->urb->pipe)) { |
| 113 | case PIPE_ISOCHRONOUS: out += sprintf(out, "ISO"); break; | 114 | case PIPE_ISOCHRONOUS: ptype = "ISO"; break; |
| 114 | case PIPE_INTERRUPT: out += sprintf(out, "INT"); break; | 115 | case PIPE_INTERRUPT: ptype = "INT"; break; |
| 115 | case PIPE_BULK: out += sprintf(out, "BLK"); break; | 116 | case PIPE_BULK: ptype = "BLK"; break; |
| 116 | case PIPE_CONTROL: out += sprintf(out, "CTL"); break; | 117 | default: |
| 118 | case PIPE_CONTROL: ptype = "CTL"; break; | ||
| 117 | } | 119 | } |
| 118 | 120 | ||
| 119 | out += sprintf(out, "%s", (urbp->fsbr ? " FSBR" : "")); | 121 | out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : "")); |
| 122 | out += sprintf(out, " Actlen=%d", urbp->urb->actual_length); | ||
| 120 | 123 | ||
| 121 | if (urbp->urb->status != -EINPROGRESS) | 124 | if (urbp->urb->status != -EINPROGRESS) |
| 122 | out += sprintf(out, " Status=%d", urbp->urb->status); | 125 | out += sprintf(out, " Status=%d", urbp->urb->status); |
| @@ -124,7 +127,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space) | |||
| 124 | 127 | ||
| 125 | i = nactive = ninactive = 0; | 128 | i = nactive = ninactive = 0; |
| 126 | list_for_each_entry(td, &urbp->td_list, list) { | 129 | list_for_each_entry(td, &urbp->td_list, list) { |
| 127 | if (++i <= 10 || debug > 2) { | 130 | if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC && |
| 131 | (++i <= 10 || debug > 2)) { | ||
| 128 | out += sprintf(out, "%*s%d: ", space + 2, "", i); | 132 | out += sprintf(out, "%*s%d: ", space + 2, "", i); |
| 129 | out += uhci_show_td(td, out, len - (out - buf), 0); | 133 | out += uhci_show_td(td, out, len - (out - buf), 0); |
| 130 | } else { | 134 | } else { |
| @@ -147,13 +151,27 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) | |||
| 147 | char *out = buf; | 151 | char *out = buf; |
| 148 | int i, nurbs; | 152 | int i, nurbs; |
| 149 | __le32 element = qh_element(qh); | 153 | __le32 element = qh_element(qh); |
| 154 | char *qtype; | ||
| 150 | 155 | ||
| 151 | /* Try to make sure there's enough memory */ | 156 | /* Try to make sure there's enough memory */ |
| 152 | if (len < 80 * 6) | 157 | if (len < 80 * 7) |
| 153 | return 0; | 158 | return 0; |
| 154 | 159 | ||
| 155 | out += sprintf(out, "%*s[%p] link (%08x) element (%08x)\n", space, "", | 160 | switch (qh->type) { |
| 156 | qh, le32_to_cpu(qh->link), le32_to_cpu(element)); | 161 | case USB_ENDPOINT_XFER_ISOC: qtype = "ISO"; break; |
| 162 | case USB_ENDPOINT_XFER_INT: qtype = "INT"; break; | ||
| 163 | case USB_ENDPOINT_XFER_BULK: qtype = "BLK"; break; | ||
| 164 | case USB_ENDPOINT_XFER_CONTROL: qtype = "CTL"; break; | ||
| 165 | default: qtype = "Skel" ; break; | ||
| 166 | } | ||
| 167 | |||
| 168 | out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n", | ||
| 169 | space, "", qh, qtype, | ||
| 170 | le32_to_cpu(qh->link), le32_to_cpu(element)); | ||
| 171 | if (qh->type == USB_ENDPOINT_XFER_ISOC) | ||
| 172 | out += sprintf(out, "%*s period %d frame %x desc [%p]\n", | ||
| 173 | space, "", qh->period, qh->iso_frame, | ||
| 174 | qh->iso_packet_desc); | ||
| 157 | 175 | ||
| 158 | if (element & UHCI_PTR_QH) | 176 | if (element & UHCI_PTR_QH) |
| 159 | out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); | 177 | out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); |
| @@ -261,7 +279,8 @@ static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len) | |||
| 261 | default: | 279 | default: |
| 262 | rh_state = "?"; break; | 280 | rh_state = "?"; break; |
| 263 | } | 281 | } |
| 264 | out += sprintf(out, "Root-hub state: %s\n", rh_state); | 282 | out += sprintf(out, "Root-hub state: %s FSBR: %d\n", |
| 283 | rh_state, uhci->fsbr_is_on); | ||
| 265 | return out - buf; | 284 | return out - buf; |
| 266 | } | 285 | } |
| 267 | 286 | ||
| @@ -275,7 +294,7 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) | |||
| 275 | unsigned short portsc1, portsc2; | 294 | unsigned short portsc1, portsc2; |
| 276 | 295 | ||
| 277 | /* Try to make sure there's enough memory */ | 296 | /* Try to make sure there's enough memory */ |
| 278 | if (len < 80 * 6) | 297 | if (len < 80 * 9) |
| 279 | return 0; | 298 | return 0; |
| 280 | 299 | ||
| 281 | usbcmd = inw(io_addr + 0); | 300 | usbcmd = inw(io_addr + 0); |
| @@ -314,6 +333,10 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) | |||
| 314 | out += sprintf(out, " sof = %02x\n", sof); | 333 | out += sprintf(out, " sof = %02x\n", sof); |
| 315 | out += uhci_show_sc(1, portsc1, out, len - (out - buf)); | 334 | out += uhci_show_sc(1, portsc1, out, len - (out - buf)); |
| 316 | out += uhci_show_sc(2, portsc2, out, len - (out - buf)); | 335 | out += uhci_show_sc(2, portsc2, out, len - (out - buf)); |
| 336 | out += sprintf(out, "Most recent frame: %x (%d) " | ||
| 337 | "Last ISO frame: %x (%d)\n", | ||
| 338 | uhci->frame_number, uhci->frame_number & 1023, | ||
| 339 | uhci->last_iso_frame, uhci->last_iso_frame & 1023); | ||
| 317 | 340 | ||
| 318 | return out - buf; | 341 | return out - buf; |
| 319 | } | 342 | } |
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index d225e11f4055..7b48567622ef 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface | 13 | * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface |
| 14 | * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). | 14 | * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). |
| 15 | * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) | 15 | * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) |
| 16 | * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu | 16 | * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu |
| 17 | * | 17 | * |
| 18 | * Intel documents this fairly well, and as far as I know there | 18 | * Intel documents this fairly well, and as far as I know there |
| 19 | * are no royalties or anything like that, but even so there are | 19 | * are no royalties or anything like that, but even so there are |
| @@ -31,7 +31,6 @@ | |||
| 31 | #include <linux/ioport.h> | 31 | #include <linux/ioport.h> |
| 32 | #include <linux/sched.h> | 32 | #include <linux/sched.h> |
| 33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
| 34 | #include <linux/smp_lock.h> | ||
| 35 | #include <linux/errno.h> | 34 | #include <linux/errno.h> |
| 36 | #include <linux/unistd.h> | 35 | #include <linux/unistd.h> |
| 37 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
| @@ -88,15 +87,6 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state); | |||
| 88 | static void wakeup_rh(struct uhci_hcd *uhci); | 87 | static void wakeup_rh(struct uhci_hcd *uhci); |
| 89 | static void uhci_get_current_frame_number(struct uhci_hcd *uhci); | 88 | static void uhci_get_current_frame_number(struct uhci_hcd *uhci); |
| 90 | 89 | ||
| 91 | /* If a transfer is still active after this much time, turn off FSBR */ | ||
| 92 | #define IDLE_TIMEOUT msecs_to_jiffies(50) | ||
| 93 | #define FSBR_DELAY msecs_to_jiffies(50) | ||
| 94 | |||
| 95 | /* When we timeout an idle transfer for FSBR, we'll switch it over to */ | ||
| 96 | /* depth first traversal. We'll do it in groups of this number of TDs */ | ||
| 97 | /* to make sure it doesn't hog all of the bandwidth */ | ||
| 98 | #define DEPTH_INTERVAL 5 | ||
| 99 | |||
| 100 | #include "uhci-debug.c" | 90 | #include "uhci-debug.c" |
| 101 | #include "uhci-q.c" | 91 | #include "uhci-q.c" |
| 102 | #include "uhci-hub.c" | 92 | #include "uhci-hub.c" |
| @@ -120,22 +110,29 @@ static void finish_reset(struct uhci_hcd *uhci) | |||
| 120 | uhci->is_stopped = UHCI_IS_STOPPED; | 110 | uhci->is_stopped = UHCI_IS_STOPPED; |
| 121 | uhci_to_hcd(uhci)->state = HC_STATE_HALT; | 111 | uhci_to_hcd(uhci)->state = HC_STATE_HALT; |
| 122 | uhci_to_hcd(uhci)->poll_rh = 0; | 112 | uhci_to_hcd(uhci)->poll_rh = 0; |
| 113 | |||
| 114 | uhci->dead = 0; /* Full reset resurrects the controller */ | ||
| 123 | } | 115 | } |
| 124 | 116 | ||
| 125 | /* | 117 | /* |
| 126 | * Last rites for a defunct/nonfunctional controller | 118 | * Last rites for a defunct/nonfunctional controller |
| 127 | * or one we don't want to use any more. | 119 | * or one we don't want to use any more. |
| 128 | */ | 120 | */ |
| 129 | static void hc_died(struct uhci_hcd *uhci) | 121 | static void uhci_hc_died(struct uhci_hcd *uhci) |
| 130 | { | 122 | { |
| 123 | uhci_get_current_frame_number(uhci); | ||
| 131 | uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); | 124 | uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); |
| 132 | finish_reset(uhci); | 125 | finish_reset(uhci); |
| 133 | uhci->hc_inaccessible = 1; | 126 | uhci->dead = 1; |
| 127 | |||
| 128 | /* The current frame may already be partway finished */ | ||
| 129 | ++uhci->frame_number; | ||
| 134 | } | 130 | } |
| 135 | 131 | ||
| 136 | /* | 132 | /* |
| 137 | * Initialize a controller that was newly discovered or has just been | 133 | * Initialize a controller that was newly discovered or has lost power |
| 138 | * resumed. In either case we can't be sure of its previous state. | 134 | * or otherwise been reset while it was suspended. In none of these cases |
| 135 | * can we be sure of its previous state. | ||
| 139 | */ | 136 | */ |
| 140 | static void check_and_reset_hc(struct uhci_hcd *uhci) | 137 | static void check_and_reset_hc(struct uhci_hcd *uhci) |
| 141 | { | 138 | { |
| @@ -155,7 +152,8 @@ static void configure_hc(struct uhci_hcd *uhci) | |||
| 155 | outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD); | 152 | outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD); |
| 156 | 153 | ||
| 157 | /* Set the current frame number */ | 154 | /* Set the current frame number */ |
| 158 | outw(uhci->frame_number, uhci->io_addr + USBFRNUM); | 155 | outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER, |
| 156 | uhci->io_addr + USBFRNUM); | ||
| 159 | 157 | ||
| 160 | /* Mark controller as not halted before we enable interrupts */ | 158 | /* Mark controller as not halted before we enable interrupts */ |
| 161 | uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED; | 159 | uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED; |
| @@ -207,7 +205,8 @@ __acquires(uhci->lock) | |||
| 207 | int int_enable; | 205 | int int_enable; |
| 208 | 206 | ||
| 209 | auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); | 207 | auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); |
| 210 | dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__, | 208 | dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev, |
| 209 | "%s%s\n", __FUNCTION__, | ||
| 211 | (auto_stop ? " (auto-stop)" : "")); | 210 | (auto_stop ? " (auto-stop)" : "")); |
| 212 | 211 | ||
| 213 | /* If we get a suspend request when we're already auto-stopped | 212 | /* If we get a suspend request when we're already auto-stopped |
| @@ -241,27 +240,27 @@ __acquires(uhci->lock) | |||
| 241 | spin_unlock_irq(&uhci->lock); | 240 | spin_unlock_irq(&uhci->lock); |
| 242 | msleep(1); | 241 | msleep(1); |
| 243 | spin_lock_irq(&uhci->lock); | 242 | spin_lock_irq(&uhci->lock); |
| 244 | if (uhci->hc_inaccessible) /* Died */ | 243 | if (uhci->dead) |
| 245 | return; | 244 | return; |
| 246 | } | 245 | } |
| 247 | if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) | 246 | if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) |
| 248 | dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); | 247 | dev_warn(&uhci_to_hcd(uhci)->self.root_hub->dev, |
| 248 | "Controller not stopped yet!\n"); | ||
| 249 | 249 | ||
| 250 | uhci_get_current_frame_number(uhci); | 250 | uhci_get_current_frame_number(uhci); |
| 251 | smp_wmb(); | ||
| 252 | 251 | ||
| 253 | uhci->rh_state = new_state; | 252 | uhci->rh_state = new_state; |
| 254 | uhci->is_stopped = UHCI_IS_STOPPED; | 253 | uhci->is_stopped = UHCI_IS_STOPPED; |
| 255 | uhci_to_hcd(uhci)->poll_rh = !int_enable; | 254 | uhci_to_hcd(uhci)->poll_rh = !int_enable; |
| 256 | 255 | ||
| 257 | uhci_scan_schedule(uhci, NULL); | 256 | uhci_scan_schedule(uhci, NULL); |
| 257 | uhci_fsbr_off(uhci); | ||
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | static void start_rh(struct uhci_hcd *uhci) | 260 | static void start_rh(struct uhci_hcd *uhci) |
| 261 | { | 261 | { |
| 262 | uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; | 262 | uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; |
| 263 | uhci->is_stopped = 0; | 263 | uhci->is_stopped = 0; |
| 264 | smp_wmb(); | ||
| 265 | 264 | ||
| 266 | /* Mark it configured and running with a 64-byte max packet. | 265 | /* Mark it configured and running with a 64-byte max packet. |
| 267 | * All interrupts are enabled, even though RESUME won't do anything. | 266 | * All interrupts are enabled, even though RESUME won't do anything. |
| @@ -278,7 +277,8 @@ static void wakeup_rh(struct uhci_hcd *uhci) | |||
| 278 | __releases(uhci->lock) | 277 | __releases(uhci->lock) |
| 279 | __acquires(uhci->lock) | 278 | __acquires(uhci->lock) |
| 280 | { | 279 | { |
| 281 | dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__, | 280 | dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev, |
| 281 | "%s%s\n", __FUNCTION__, | ||
| 282 | uhci->rh_state == UHCI_RH_AUTO_STOPPED ? | 282 | uhci->rh_state == UHCI_RH_AUTO_STOPPED ? |
| 283 | " (auto-start)" : ""); | 283 | " (auto-start)" : ""); |
| 284 | 284 | ||
| @@ -293,7 +293,7 @@ __acquires(uhci->lock) | |||
| 293 | spin_unlock_irq(&uhci->lock); | 293 | spin_unlock_irq(&uhci->lock); |
| 294 | msleep(20); | 294 | msleep(20); |
| 295 | spin_lock_irq(&uhci->lock); | 295 | spin_lock_irq(&uhci->lock); |
| 296 | if (uhci->hc_inaccessible) /* Died */ | 296 | if (uhci->dead) |
| 297 | return; | 297 | return; |
| 298 | 298 | ||
| 299 | /* End Global Resume and wait for EOP to be sent */ | 299 | /* End Global Resume and wait for EOP to be sent */ |
| @@ -345,7 +345,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
| 345 | errbuf, ERRBUF_LEN); | 345 | errbuf, ERRBUF_LEN); |
| 346 | lprintk(errbuf); | 346 | lprintk(errbuf); |
| 347 | } | 347 | } |
| 348 | hc_died(uhci); | 348 | uhci_hc_died(uhci); |
| 349 | 349 | ||
| 350 | /* Force a callback in case there are | 350 | /* Force a callback in case there are |
| 351 | * pending unlinks */ | 351 | * pending unlinks */ |
| @@ -368,12 +368,21 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
| 368 | 368 | ||
| 369 | /* | 369 | /* |
| 370 | * Store the current frame number in uhci->frame_number if the controller | 370 | * Store the current frame number in uhci->frame_number if the controller |
| 371 | * is runnning | 371 | * is runnning. Expand from 11 bits (of which we use only 10) to a |
| 372 | * full-sized integer. | ||
| 373 | * | ||
| 374 | * Like many other parts of the driver, this code relies on being polled | ||
| 375 | * more than once per second as long as the controller is running. | ||
| 372 | */ | 376 | */ |
| 373 | static void uhci_get_current_frame_number(struct uhci_hcd *uhci) | 377 | static void uhci_get_current_frame_number(struct uhci_hcd *uhci) |
| 374 | { | 378 | { |
| 375 | if (!uhci->is_stopped) | 379 | if (!uhci->is_stopped) { |
| 376 | uhci->frame_number = inw(uhci->io_addr + USBFRNUM); | 380 | unsigned delta; |
| 381 | |||
| 382 | delta = (inw(uhci->io_addr + USBFRNUM) - uhci->frame_number) & | ||
| 383 | (UHCI_NUMFRAMES - 1); | ||
| 384 | uhci->frame_number += delta; | ||
| 385 | } | ||
| 377 | } | 386 | } |
| 378 | 387 | ||
| 379 | /* | 388 | /* |
| @@ -407,7 +416,7 @@ static void release_uhci(struct uhci_hcd *uhci) | |||
| 407 | uhci->frame, uhci->frame_dma_handle); | 416 | uhci->frame, uhci->frame_dma_handle); |
| 408 | } | 417 | } |
| 409 | 418 | ||
| 410 | static int uhci_reset(struct usb_hcd *hcd) | 419 | static int uhci_init(struct usb_hcd *hcd) |
| 411 | { | 420 | { |
| 412 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 421 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
| 413 | unsigned io_size = (unsigned) hcd->rsrc_len; | 422 | unsigned io_size = (unsigned) hcd->rsrc_len; |
| @@ -459,7 +468,7 @@ static void uhci_shutdown(struct pci_dev *pdev) | |||
| 459 | { | 468 | { |
| 460 | struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev); | 469 | struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev); |
| 461 | 470 | ||
| 462 | hc_died(hcd_to_uhci(hcd)); | 471 | uhci_hc_died(hcd_to_uhci(hcd)); |
| 463 | } | 472 | } |
| 464 | 473 | ||
| 465 | /* | 474 | /* |
| @@ -487,14 +496,10 @@ static int uhci_start(struct usb_hcd *hcd) | |||
| 487 | 496 | ||
| 488 | hcd->uses_new_polling = 1; | 497 | hcd->uses_new_polling = 1; |
| 489 | 498 | ||
| 490 | uhci->fsbr = 0; | ||
| 491 | uhci->fsbrtimeout = 0; | ||
| 492 | |||
| 493 | spin_lock_init(&uhci->lock); | 499 | spin_lock_init(&uhci->lock); |
| 494 | 500 | setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout, | |
| 495 | INIT_LIST_HEAD(&uhci->td_remove_list); | 501 | (unsigned long) uhci); |
| 496 | INIT_LIST_HEAD(&uhci->idle_qh_list); | 502 | INIT_LIST_HEAD(&uhci->idle_qh_list); |
| 497 | |||
| 498 | init_waitqueue_head(&uhci->waitqh); | 503 | init_waitqueue_head(&uhci->waitqh); |
| 499 | 504 | ||
| 500 | if (DEBUG_CONFIGURED) { | 505 | if (DEBUG_CONFIGURED) { |
| @@ -665,11 +670,12 @@ static void uhci_stop(struct usb_hcd *hcd) | |||
| 665 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 670 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
| 666 | 671 | ||
| 667 | spin_lock_irq(&uhci->lock); | 672 | spin_lock_irq(&uhci->lock); |
| 668 | if (!uhci->hc_inaccessible) | 673 | if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && !uhci->dead) |
| 669 | hc_died(uhci); | 674 | uhci_hc_died(uhci); |
| 670 | uhci_scan_schedule(uhci, NULL); | 675 | uhci_scan_schedule(uhci, NULL); |
| 671 | spin_unlock_irq(&uhci->lock); | 676 | spin_unlock_irq(&uhci->lock); |
| 672 | 677 | ||
| 678 | del_timer_sync(&uhci->fsbr_timer); | ||
| 673 | release_uhci(uhci); | 679 | release_uhci(uhci); |
| 674 | } | 680 | } |
| 675 | 681 | ||
| @@ -677,12 +683,15 @@ static void uhci_stop(struct usb_hcd *hcd) | |||
| 677 | static int uhci_rh_suspend(struct usb_hcd *hcd) | 683 | static int uhci_rh_suspend(struct usb_hcd *hcd) |
| 678 | { | 684 | { |
| 679 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 685 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
| 686 | int rc = 0; | ||
| 680 | 687 | ||
| 681 | spin_lock_irq(&uhci->lock); | 688 | spin_lock_irq(&uhci->lock); |
| 682 | if (!uhci->hc_inaccessible) /* Not dead */ | 689 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) |
| 690 | rc = -ESHUTDOWN; | ||
| 691 | else if (!uhci->dead) | ||
| 683 | suspend_rh(uhci, UHCI_RH_SUSPENDED); | 692 | suspend_rh(uhci, UHCI_RH_SUSPENDED); |
| 684 | spin_unlock_irq(&uhci->lock); | 693 | spin_unlock_irq(&uhci->lock); |
| 685 | return 0; | 694 | return rc; |
| 686 | } | 695 | } |
| 687 | 696 | ||
| 688 | static int uhci_rh_resume(struct usb_hcd *hcd) | 697 | static int uhci_rh_resume(struct usb_hcd *hcd) |
| @@ -691,13 +700,10 @@ static int uhci_rh_resume(struct usb_hcd *hcd) | |||
| 691 | int rc = 0; | 700 | int rc = 0; |
| 692 | 701 | ||
| 693 | spin_lock_irq(&uhci->lock); | 702 | spin_lock_irq(&uhci->lock); |
| 694 | if (uhci->hc_inaccessible) { | 703 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { |
| 695 | if (uhci->rh_state == UHCI_RH_SUSPENDED) { | 704 | dev_warn(&hcd->self.root_hub->dev, "HC isn't running!\n"); |
| 696 | dev_warn(uhci_dev(uhci), "HC isn't running!\n"); | 705 | rc = -ESHUTDOWN; |
| 697 | rc = -ENODEV; | 706 | } else if (!uhci->dead) |
| 698 | } | ||
| 699 | /* Otherwise the HC is dead */ | ||
| 700 | } else | ||
| 701 | wakeup_rh(uhci); | 707 | wakeup_rh(uhci); |
| 702 | spin_unlock_irq(&uhci->lock); | 708 | spin_unlock_irq(&uhci->lock); |
| 703 | return rc; | 709 | return rc; |
| @@ -711,8 +717,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) | |||
| 711 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); | 717 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); |
| 712 | 718 | ||
| 713 | spin_lock_irq(&uhci->lock); | 719 | spin_lock_irq(&uhci->lock); |
| 714 | if (uhci->hc_inaccessible) /* Dead or already suspended */ | 720 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) |
| 715 | goto done; | 721 | goto done_okay; /* Already suspended or dead */ |
| 716 | 722 | ||
| 717 | if (uhci->rh_state > UHCI_RH_SUSPENDED) { | 723 | if (uhci->rh_state > UHCI_RH_SUSPENDED) { |
| 718 | dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); | 724 | dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); |
| @@ -725,12 +731,12 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) | |||
| 725 | */ | 731 | */ |
| 726 | pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); | 732 | pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); |
| 727 | mb(); | 733 | mb(); |
| 728 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
| 729 | uhci->hc_inaccessible = 1; | ||
| 730 | hcd->poll_rh = 0; | 734 | hcd->poll_rh = 0; |
| 731 | 735 | ||
| 732 | /* FIXME: Enable non-PME# remote wakeup? */ | 736 | /* FIXME: Enable non-PME# remote wakeup? */ |
| 733 | 737 | ||
| 738 | done_okay: | ||
| 739 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
| 734 | done: | 740 | done: |
| 735 | spin_unlock_irq(&uhci->lock); | 741 | spin_unlock_irq(&uhci->lock); |
| 736 | return rc; | 742 | return rc; |
| @@ -743,24 +749,22 @@ static int uhci_resume(struct usb_hcd *hcd) | |||
| 743 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); | 749 | dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); |
| 744 | 750 | ||
| 745 | /* Since we aren't in D3 any more, it's safe to set this flag | 751 | /* Since we aren't in D3 any more, it's safe to set this flag |
| 746 | * even if the controller was dead. It might not even be dead | 752 | * even if the controller was dead. |
| 747 | * any more, if the firmware or quirks code has reset it. | ||
| 748 | */ | 753 | */ |
| 749 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 754 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
| 750 | mb(); | 755 | mb(); |
| 751 | 756 | ||
| 752 | if (uhci->rh_state == UHCI_RH_RESET) /* Dead */ | ||
| 753 | return 0; | ||
| 754 | spin_lock_irq(&uhci->lock); | 757 | spin_lock_irq(&uhci->lock); |
| 755 | 758 | ||
| 756 | /* FIXME: Disable non-PME# remote wakeup? */ | 759 | /* FIXME: Disable non-PME# remote wakeup? */ |
| 757 | 760 | ||
| 758 | uhci->hc_inaccessible = 0; | 761 | /* The firmware or a boot kernel may have changed the controller |
| 759 | 762 | * settings during a system wakeup. Check it and reconfigure | |
| 760 | /* The BIOS may have changed the controller settings during a | 763 | * to avoid problems. |
| 761 | * system wakeup. Check it and reconfigure to avoid problems. | ||
| 762 | */ | 764 | */ |
| 763 | check_and_reset_hc(uhci); | 765 | check_and_reset_hc(uhci); |
| 766 | |||
| 767 | /* If the controller was dead before, it's back alive now */ | ||
| 764 | configure_hc(uhci); | 768 | configure_hc(uhci); |
| 765 | 769 | ||
| 766 | if (uhci->rh_state == UHCI_RH_RESET) { | 770 | if (uhci->rh_state == UHCI_RH_RESET) { |
| @@ -810,18 +814,15 @@ done: | |||
| 810 | static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) | 814 | static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) |
| 811 | { | 815 | { |
| 812 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 816 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
| 813 | unsigned long flags; | 817 | unsigned frame_number; |
| 814 | int is_stopped; | 818 | unsigned delta; |
| 815 | int frame_number; | ||
| 816 | 819 | ||
| 817 | /* Minimize latency by avoiding the spinlock */ | 820 | /* Minimize latency by avoiding the spinlock */ |
| 818 | local_irq_save(flags); | 821 | frame_number = uhci->frame_number; |
| 819 | is_stopped = uhci->is_stopped; | 822 | barrier(); |
| 820 | smp_rmb(); | 823 | delta = (inw(uhci->io_addr + USBFRNUM) - frame_number) & |
| 821 | frame_number = (is_stopped ? uhci->frame_number : | 824 | (UHCI_NUMFRAMES - 1); |
| 822 | inw(uhci->io_addr + USBFRNUM)); | 825 | return frame_number + delta; |
| 823 | local_irq_restore(flags); | ||
| 824 | return frame_number; | ||
| 825 | } | 826 | } |
| 826 | 827 | ||
| 827 | static const char hcd_name[] = "uhci_hcd"; | 828 | static const char hcd_name[] = "uhci_hcd"; |
| @@ -836,7 +837,7 @@ static const struct hc_driver uhci_driver = { | |||
| 836 | .flags = HCD_USB11, | 837 | .flags = HCD_USB11, |
| 837 | 838 | ||
| 838 | /* Basic lifecycle operations */ | 839 | /* Basic lifecycle operations */ |
| 839 | .reset = uhci_reset, | 840 | .reset = uhci_init, |
| 840 | .start = uhci_start, | 841 | .start = uhci_start, |
| 841 | #ifdef CONFIG_PM | 842 | #ifdef CONFIG_PM |
| 842 | .suspend = uhci_suspend, | 843 | .suspend = uhci_suspend, |
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index d5c8f4d92823..108e3de2dc26 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h | |||
| @@ -84,6 +84,13 @@ | |||
| 84 | #define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames | 84 | #define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames |
| 85 | * can be scheduled */ | 85 | * can be scheduled */ |
| 86 | 86 | ||
| 87 | /* When no queues need Full-Speed Bandwidth Reclamation, | ||
| 88 | * delay this long before turning FSBR off */ | ||
| 89 | #define FSBR_OFF_DELAY msecs_to_jiffies(10) | ||
| 90 | |||
| 91 | /* If a queue hasn't advanced after this much time, assume it is stuck */ | ||
| 92 | #define QH_WAIT_TIMEOUT msecs_to_jiffies(200) | ||
| 93 | |||
| 87 | 94 | ||
| 88 | /* | 95 | /* |
| 89 | * Queue Headers | 96 | * Queue Headers |
| @@ -121,21 +128,31 @@ struct uhci_qh { | |||
| 121 | __le32 element; /* Queue element (TD) pointer */ | 128 | __le32 element; /* Queue element (TD) pointer */ |
| 122 | 129 | ||
| 123 | /* Software fields */ | 130 | /* Software fields */ |
| 124 | dma_addr_t dma_handle; | ||
| 125 | |||
| 126 | struct list_head node; /* Node in the list of QHs */ | 131 | struct list_head node; /* Node in the list of QHs */ |
| 127 | struct usb_host_endpoint *hep; /* Endpoint information */ | 132 | struct usb_host_endpoint *hep; /* Endpoint information */ |
| 128 | struct usb_device *udev; | 133 | struct usb_device *udev; |
| 129 | struct list_head queue; /* Queue of urbps for this QH */ | 134 | struct list_head queue; /* Queue of urbps for this QH */ |
| 130 | struct uhci_qh *skel; /* Skeleton for this QH */ | 135 | struct uhci_qh *skel; /* Skeleton for this QH */ |
| 131 | struct uhci_td *dummy_td; /* Dummy TD to end the queue */ | 136 | struct uhci_td *dummy_td; /* Dummy TD to end the queue */ |
| 137 | struct uhci_td *post_td; /* Last TD completed */ | ||
| 132 | 138 | ||
| 139 | struct usb_iso_packet_descriptor *iso_packet_desc; | ||
| 140 | /* Next urb->iso_frame_desc entry */ | ||
| 141 | unsigned long advance_jiffies; /* Time of last queue advance */ | ||
| 133 | unsigned int unlink_frame; /* When the QH was unlinked */ | 142 | unsigned int unlink_frame; /* When the QH was unlinked */ |
| 143 | unsigned int period; /* For Interrupt and Isochronous QHs */ | ||
| 144 | unsigned int iso_frame; /* Frame # for iso_packet_desc */ | ||
| 145 | int iso_status; /* Status for Isochronous URBs */ | ||
| 146 | |||
| 134 | int state; /* QH_STATE_xxx; see above */ | 147 | int state; /* QH_STATE_xxx; see above */ |
| 148 | int type; /* Queue type (control, bulk, etc) */ | ||
| 149 | |||
| 150 | dma_addr_t dma_handle; | ||
| 135 | 151 | ||
| 136 | unsigned int initial_toggle:1; /* Endpoint's current toggle value */ | 152 | unsigned int initial_toggle:1; /* Endpoint's current toggle value */ |
| 137 | unsigned int needs_fixup:1; /* Must fix the TD toggle values */ | 153 | unsigned int needs_fixup:1; /* Must fix the TD toggle values */ |
| 138 | unsigned int is_stopped:1; /* Queue was stopped by an error */ | 154 | unsigned int is_stopped:1; /* Queue was stopped by error/unlink */ |
| 155 | unsigned int wait_expired:1; /* QH_WAIT_TIMEOUT has expired */ | ||
| 139 | } __attribute__((aligned(16))); | 156 | } __attribute__((aligned(16))); |
| 140 | 157 | ||
| 141 | /* | 158 | /* |
| @@ -226,7 +243,6 @@ struct uhci_td { | |||
| 226 | dma_addr_t dma_handle; | 243 | dma_addr_t dma_handle; |
| 227 | 244 | ||
| 228 | struct list_head list; | 245 | struct list_head list; |
| 229 | struct list_head remove_list; | ||
| 230 | 246 | ||
| 231 | int frame; /* for iso: what frame? */ | 247 | int frame; /* for iso: what frame? */ |
| 232 | struct list_head fl_list; | 248 | struct list_head fl_list; |
| @@ -305,38 +321,8 @@ static inline u32 td_status(struct uhci_td *td) { | |||
| 305 | #define skel_bulk_qh skelqh[12] | 321 | #define skel_bulk_qh skelqh[12] |
| 306 | #define skel_term_qh skelqh[13] | 322 | #define skel_term_qh skelqh[13] |
| 307 | 323 | ||
| 308 | /* | 324 | /* Find the skelqh entry corresponding to an interval exponent */ |
| 309 | * Search tree for determining where <interval> fits in the skelqh[] | 325 | #define UHCI_SKEL_INDEX(exponent) (9 - exponent) |
| 310 | * skeleton. | ||
| 311 | * | ||
| 312 | * An interrupt request should be placed into the slowest skelqh[] | ||
| 313 | * which meets the interval/period/frequency requirement. | ||
| 314 | * An interrupt request is allowed to be faster than <interval> but not slower. | ||
| 315 | * | ||
| 316 | * For a given <interval>, this function returns the appropriate/matching | ||
| 317 | * skelqh[] index value. | ||
| 318 | */ | ||
| 319 | static inline int __interval_to_skel(int interval) | ||
| 320 | { | ||
| 321 | if (interval < 16) { | ||
| 322 | if (interval < 4) { | ||
| 323 | if (interval < 2) | ||
| 324 | return 9; /* int1 for 0-1 ms */ | ||
| 325 | return 8; /* int2 for 2-3 ms */ | ||
| 326 | } | ||
| 327 | if (interval < 8) | ||
| 328 | return 7; /* int4 for 4-7 ms */ | ||
| 329 | return 6; /* int8 for 8-15 ms */ | ||
| 330 | } | ||
| 331 | if (interval < 64) { | ||
| 332 | if (interval < 32) | ||
| 333 | return 5; /* int16 for 16-31 ms */ | ||
| 334 | return 4; /* int32 for 32-63 ms */ | ||
| 335 | } | ||
| 336 | if (interval < 128) | ||
| 337 | return 3; /* int64 for 64-127 ms */ | ||
| 338 | return 2; /* int128 for 128-255 ms (Max.) */ | ||
| 339 | } | ||
| 340 | 326 | ||
| 341 | 327 | ||
| 342 | /* | 328 | /* |
| @@ -396,32 +382,32 @@ struct uhci_hcd { | |||
| 396 | __le32 *frame; | 382 | __le32 *frame; |
| 397 | void **frame_cpu; /* CPU's frame list */ | 383 | void **frame_cpu; /* CPU's frame list */ |
| 398 | 384 | ||
| 399 | int fsbr; /* Full-speed bandwidth reclamation */ | ||
| 400 | unsigned long fsbrtimeout; /* FSBR delay */ | ||
| 401 | |||
| 402 | enum uhci_rh_state rh_state; | 385 | enum uhci_rh_state rh_state; |
| 403 | unsigned long auto_stop_time; /* When to AUTO_STOP */ | 386 | unsigned long auto_stop_time; /* When to AUTO_STOP */ |
| 404 | 387 | ||
| 405 | unsigned int frame_number; /* As of last check */ | 388 | unsigned int frame_number; /* As of last check */ |
| 406 | unsigned int is_stopped; | 389 | unsigned int is_stopped; |
| 407 | #define UHCI_IS_STOPPED 9999 /* Larger than a frame # */ | 390 | #define UHCI_IS_STOPPED 9999 /* Larger than a frame # */ |
| 391 | unsigned int last_iso_frame; /* Frame of last scan */ | ||
| 392 | unsigned int cur_iso_frame; /* Frame for current scan */ | ||
| 408 | 393 | ||
| 409 | unsigned int scan_in_progress:1; /* Schedule scan is running */ | 394 | unsigned int scan_in_progress:1; /* Schedule scan is running */ |
| 410 | unsigned int need_rescan:1; /* Redo the schedule scan */ | 395 | unsigned int need_rescan:1; /* Redo the schedule scan */ |
| 411 | unsigned int hc_inaccessible:1; /* HC is suspended or dead */ | 396 | unsigned int dead:1; /* Controller has died */ |
| 412 | unsigned int working_RD:1; /* Suspended root hub doesn't | 397 | unsigned int working_RD:1; /* Suspended root hub doesn't |
| 413 | need to be polled */ | 398 | need to be polled */ |
| 414 | unsigned int is_initialized:1; /* Data structure is usable */ | 399 | unsigned int is_initialized:1; /* Data structure is usable */ |
| 400 | unsigned int fsbr_is_on:1; /* FSBR is turned on */ | ||
| 401 | unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */ | ||
| 402 | unsigned int fsbr_expiring:1; /* FSBR is timing out */ | ||
| 403 | |||
| 404 | struct timer_list fsbr_timer; /* For turning off FBSR */ | ||
| 415 | 405 | ||
| 416 | /* Support for port suspend/resume/reset */ | 406 | /* Support for port suspend/resume/reset */ |
| 417 | unsigned long port_c_suspend; /* Bit-arrays of ports */ | 407 | unsigned long port_c_suspend; /* Bit-arrays of ports */ |
| 418 | unsigned long resuming_ports; | 408 | unsigned long resuming_ports; |
| 419 | unsigned long ports_timeout; /* Time to stop signalling */ | 409 | unsigned long ports_timeout; /* Time to stop signalling */ |
| 420 | 410 | ||
| 421 | /* List of TDs that are done, but waiting to be freed (race) */ | ||
| 422 | struct list_head td_remove_list; | ||
| 423 | unsigned int td_remove_age; /* Age in frames */ | ||
| 424 | |||
| 425 | struct list_head idle_qh_list; /* Where the idle QHs live */ | 411 | struct list_head idle_qh_list; /* Where the idle QHs live */ |
| 426 | 412 | ||
| 427 | int rh_numports; /* Number of root-hub ports */ | 413 | int rh_numports; /* Number of root-hub ports */ |
| @@ -442,6 +428,9 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci) | |||
| 442 | 428 | ||
| 443 | #define uhci_dev(u) (uhci_to_hcd(u)->self.controller) | 429 | #define uhci_dev(u) (uhci_to_hcd(u)->self.controller) |
| 444 | 430 | ||
| 431 | /* Utility macro for comparing frame numbers */ | ||
| 432 | #define uhci_frame_before_eq(f1, f2) (0 <= (int) ((f2) - (f1))) | ||
| 433 | |||
| 445 | 434 | ||
| 446 | /* | 435 | /* |
| 447 | * Private per-URB data | 436 | * Private per-URB data |
| @@ -454,9 +443,7 @@ struct urb_priv { | |||
| 454 | struct uhci_qh *qh; /* QH for this URB */ | 443 | struct uhci_qh *qh; /* QH for this URB */ |
| 455 | struct list_head td_list; | 444 | struct list_head td_list; |
| 456 | 445 | ||
| 457 | unsigned fsbr : 1; /* URB turned on FSBR */ | 446 | unsigned fsbr:1; /* URB wants FSBR */ |
| 458 | unsigned short_transfer : 1; /* URB got a short transfer, no | ||
| 459 | * need to rescan */ | ||
| 460 | }; | 447 | }; |
| 461 | 448 | ||
| 462 | 449 | ||
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index c8451d9578f1..c545ef92fe29 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c | |||
| @@ -171,9 +171,8 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) | |||
| 171 | spin_lock_irqsave(&uhci->lock, flags); | 171 | spin_lock_irqsave(&uhci->lock, flags); |
| 172 | 172 | ||
| 173 | uhci_scan_schedule(uhci, NULL); | 173 | uhci_scan_schedule(uhci, NULL); |
| 174 | if (uhci->hc_inaccessible) | 174 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) |
| 175 | goto done; | 175 | goto done; |
| 176 | check_fsbr(uhci); | ||
| 177 | uhci_check_ports(uhci); | 176 | uhci_check_ports(uhci); |
| 178 | 177 | ||
| 179 | status = get_hub_status_data(uhci, buf); | 178 | status = get_hub_status_data(uhci, buf); |
| @@ -228,7 +227,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
| 228 | u16 wPortChange, wPortStatus; | 227 | u16 wPortChange, wPortStatus; |
| 229 | unsigned long flags; | 228 | unsigned long flags; |
| 230 | 229 | ||
| 231 | if (uhci->hc_inaccessible) | 230 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) |
| 232 | return -ETIMEDOUT; | 231 | return -ETIMEDOUT; |
| 233 | 232 | ||
| 234 | spin_lock_irqsave(&uhci->lock, flags); | 233 | spin_lock_irqsave(&uhci->lock, flags); |
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index a06d84c19e13..c9d72ac0a1d7 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c | |||
| @@ -13,10 +13,9 @@ | |||
| 13 | * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface | 13 | * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface |
| 14 | * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). | 14 | * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). |
| 15 | * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) | 15 | * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) |
| 16 | * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu | 16 | * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu |
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | static void uhci_free_pending_tds(struct uhci_hcd *uhci); | ||
| 20 | 19 | ||
| 21 | /* | 20 | /* |
| 22 | * Technically, updating td->status here is a race, but it's not really a | 21 | * Technically, updating td->status here is a race, but it's not really a |
| @@ -38,6 +37,60 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) | |||
| 38 | uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); | 37 | uhci->term_td->status &= ~cpu_to_le32(TD_CTRL_IOC); |
| 39 | } | 38 | } |
| 40 | 39 | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Full-Speed Bandwidth Reclamation (FSBR). | ||
| 43 | * We turn on FSBR whenever a queue that wants it is advancing, | ||
| 44 | * and leave it on for a short time thereafter. | ||
| 45 | */ | ||
| 46 | static void uhci_fsbr_on(struct uhci_hcd *uhci) | ||
| 47 | { | ||
| 48 | uhci->fsbr_is_on = 1; | ||
| 49 | uhci->skel_term_qh->link = cpu_to_le32( | ||
| 50 | uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH; | ||
| 51 | } | ||
| 52 | |||
| 53 | static void uhci_fsbr_off(struct uhci_hcd *uhci) | ||
| 54 | { | ||
| 55 | uhci->fsbr_is_on = 0; | ||
| 56 | uhci->skel_term_qh->link = UHCI_PTR_TERM; | ||
| 57 | } | ||
| 58 | |||
| 59 | static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb) | ||
| 60 | { | ||
| 61 | struct urb_priv *urbp = urb->hcpriv; | ||
| 62 | |||
| 63 | if (!(urb->transfer_flags & URB_NO_FSBR)) | ||
| 64 | urbp->fsbr = 1; | ||
| 65 | } | ||
| 66 | |||
| 67 | static void uhci_urbp_wants_fsbr(struct uhci_hcd *uhci, struct urb_priv *urbp) | ||
| 68 | { | ||
| 69 | if (urbp->fsbr) { | ||
| 70 | uhci->fsbr_is_wanted = 1; | ||
| 71 | if (!uhci->fsbr_is_on) | ||
| 72 | uhci_fsbr_on(uhci); | ||
| 73 | else if (uhci->fsbr_expiring) { | ||
| 74 | uhci->fsbr_expiring = 0; | ||
| 75 | del_timer(&uhci->fsbr_timer); | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | static void uhci_fsbr_timeout(unsigned long _uhci) | ||
| 81 | { | ||
| 82 | struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci; | ||
| 83 | unsigned long flags; | ||
| 84 | |||
| 85 | spin_lock_irqsave(&uhci->lock, flags); | ||
| 86 | if (uhci->fsbr_expiring) { | ||
| 87 | uhci->fsbr_expiring = 0; | ||
| 88 | uhci_fsbr_off(uhci); | ||
| 89 | } | ||
| 90 | spin_unlock_irqrestore(&uhci->lock, flags); | ||
| 91 | } | ||
| 92 | |||
| 93 | |||
| 41 | static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) | 94 | static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) |
| 42 | { | 95 | { |
| 43 | dma_addr_t dma_handle; | 96 | dma_addr_t dma_handle; |
| @@ -51,7 +104,6 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) | |||
| 51 | td->frame = -1; | 104 | td->frame = -1; |
| 52 | 105 | ||
| 53 | INIT_LIST_HEAD(&td->list); | 106 | INIT_LIST_HEAD(&td->list); |
| 54 | INIT_LIST_HEAD(&td->remove_list); | ||
| 55 | INIT_LIST_HEAD(&td->fl_list); | 107 | INIT_LIST_HEAD(&td->fl_list); |
| 56 | 108 | ||
| 57 | return td; | 109 | return td; |
| @@ -61,8 +113,6 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) | |||
| 61 | { | 113 | { |
| 62 | if (!list_empty(&td->list)) | 114 | if (!list_empty(&td->list)) |
| 63 | dev_warn(uhci_dev(uhci), "td %p still in list!\n", td); | 115 | dev_warn(uhci_dev(uhci), "td %p still in list!\n", td); |
| 64 | if (!list_empty(&td->remove_list)) | ||
| 65 | dev_warn(uhci_dev(uhci), "td %p still in remove_list!\n", td); | ||
| 66 | if (!list_empty(&td->fl_list)) | 116 | if (!list_empty(&td->fl_list)) |
| 67 | dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td); | 117 | dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td); |
| 68 | 118 | ||
| @@ -77,6 +127,16 @@ static inline void uhci_fill_td(struct uhci_td *td, u32 status, | |||
| 77 | td->buffer = cpu_to_le32(buffer); | 127 | td->buffer = cpu_to_le32(buffer); |
| 78 | } | 128 | } |
| 79 | 129 | ||
| 130 | static void uhci_add_td_to_urbp(struct uhci_td *td, struct urb_priv *urbp) | ||
| 131 | { | ||
| 132 | list_add_tail(&td->list, &urbp->td_list); | ||
| 133 | } | ||
| 134 | |||
| 135 | static void uhci_remove_td_from_urbp(struct uhci_td *td) | ||
| 136 | { | ||
| 137 | list_del_init(&td->list); | ||
| 138 | } | ||
| 139 | |||
| 80 | /* | 140 | /* |
| 81 | * We insert Isochronous URBs directly into the frame list at the beginning | 141 | * We insert Isochronous URBs directly into the frame list at the beginning |
| 82 | */ | 142 | */ |
| @@ -138,6 +198,24 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci, | |||
| 138 | td->frame = -1; | 198 | td->frame = -1; |
| 139 | } | 199 | } |
| 140 | 200 | ||
| 201 | static inline void uhci_remove_tds_from_frame(struct uhci_hcd *uhci, | ||
| 202 | unsigned int framenum) | ||
| 203 | { | ||
| 204 | struct uhci_td *ftd, *ltd; | ||
| 205 | |||
| 206 | framenum &= (UHCI_NUMFRAMES - 1); | ||
| 207 | |||
| 208 | ftd = uhci->frame_cpu[framenum]; | ||
| 209 | if (ftd) { | ||
| 210 | ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); | ||
| 211 | uhci->frame[framenum] = ltd->link; | ||
| 212 | uhci->frame_cpu[framenum] = NULL; | ||
| 213 | |||
| 214 | while (!list_empty(&ftd->fl_list)) | ||
| 215 | list_del_init(ftd->fl_list.prev); | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 141 | /* | 219 | /* |
| 142 | * Remove all the TDs for an Isochronous URB from the frame list | 220 | * Remove all the TDs for an Isochronous URB from the frame list |
| 143 | */ | 221 | */ |
| @@ -148,7 +226,6 @@ static void uhci_unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) | |||
| 148 | 226 | ||
| 149 | list_for_each_entry(td, &urbp->td_list, list) | 227 | list_for_each_entry(td, &urbp->td_list, list) |
| 150 | uhci_remove_td_from_frame_list(uhci, td); | 228 | uhci_remove_td_from_frame_list(uhci, td); |
| 151 | wmb(); | ||
| 152 | } | 229 | } |
| 153 | 230 | ||
| 154 | static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, | 231 | static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, |
| @@ -161,6 +238,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, | |||
| 161 | if (!qh) | 238 | if (!qh) |
| 162 | return NULL; | 239 | return NULL; |
| 163 | 240 | ||
| 241 | memset(qh, 0, sizeof(*qh)); | ||
| 164 | qh->dma_handle = dma_handle; | 242 | qh->dma_handle = dma_handle; |
| 165 | 243 | ||
| 166 | qh->element = UHCI_PTR_TERM; | 244 | qh->element = UHCI_PTR_TERM; |
| @@ -179,10 +257,11 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, | |||
| 179 | qh->hep = hep; | 257 | qh->hep = hep; |
| 180 | qh->udev = udev; | 258 | qh->udev = udev; |
| 181 | hep->hcpriv = qh; | 259 | hep->hcpriv = qh; |
| 260 | qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; | ||
| 182 | 261 | ||
| 183 | } else { /* Skeleton QH */ | 262 | } else { /* Skeleton QH */ |
| 184 | qh->state = QH_STATE_ACTIVE; | 263 | qh->state = QH_STATE_ACTIVE; |
| 185 | qh->udev = NULL; | 264 | qh->type = -1; |
| 186 | } | 265 | } |
| 187 | return qh; | 266 | return qh; |
| 188 | } | 267 | } |
| @@ -202,35 +281,64 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) | |||
| 202 | } | 281 | } |
| 203 | 282 | ||
| 204 | /* | 283 | /* |
| 205 | * When the currently executing URB is dequeued, save its current toggle value | 284 | * When a queue is stopped and a dequeued URB is given back, adjust |
| 285 | * the previous TD link (if the URB isn't first on the queue) or | ||
| 286 | * save its toggle value (if it is first and is currently executing). | ||
| 287 | * | ||
| 288 | * Returns 0 if the URB should not yet be given back, 1 otherwise. | ||
| 206 | */ | 289 | */ |
| 207 | static void uhci_save_toggle(struct uhci_qh *qh, struct urb *urb) | 290 | static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh, |
| 291 | struct urb *urb) | ||
| 208 | { | 292 | { |
| 209 | struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; | 293 | struct urb_priv *urbp = urb->hcpriv; |
| 210 | struct uhci_td *td; | 294 | struct uhci_td *td; |
| 295 | int ret = 1; | ||
| 296 | |||
| 297 | /* Isochronous pipes don't use toggles and their TD link pointers | ||
| 298 | * get adjusted during uhci_urb_dequeue(). But since their queues | ||
| 299 | * cannot truly be stopped, we have to watch out for dequeues | ||
| 300 | * occurring after the nominal unlink frame. */ | ||
| 301 | if (qh->type == USB_ENDPOINT_XFER_ISOC) { | ||
| 302 | ret = (uhci->frame_number + uhci->is_stopped != | ||
| 303 | qh->unlink_frame); | ||
| 304 | goto done; | ||
| 305 | } | ||
| 306 | |||
| 307 | /* If the URB isn't first on its queue, adjust the link pointer | ||
| 308 | * of the last TD in the previous URB. The toggle doesn't need | ||
| 309 | * to be saved since this URB can't be executing yet. */ | ||
| 310 | if (qh->queue.next != &urbp->node) { | ||
| 311 | struct urb_priv *purbp; | ||
| 312 | struct uhci_td *ptd; | ||
| 313 | |||
| 314 | purbp = list_entry(urbp->node.prev, struct urb_priv, node); | ||
| 315 | WARN_ON(list_empty(&purbp->td_list)); | ||
| 316 | ptd = list_entry(purbp->td_list.prev, struct uhci_td, | ||
| 317 | list); | ||
| 318 | td = list_entry(urbp->td_list.prev, struct uhci_td, | ||
| 319 | list); | ||
| 320 | ptd->link = td->link; | ||
| 321 | goto done; | ||
| 322 | } | ||
| 211 | 323 | ||
| 212 | /* If the QH element pointer is UHCI_PTR_TERM then then currently | 324 | /* If the QH element pointer is UHCI_PTR_TERM then then currently |
| 213 | * executing URB has already been unlinked, so this one isn't it. */ | 325 | * executing URB has already been unlinked, so this one isn't it. */ |
| 214 | if (qh_element(qh) == UHCI_PTR_TERM || | 326 | if (qh_element(qh) == UHCI_PTR_TERM) |
| 215 | qh->queue.next != &urbp->node) | 327 | goto done; |
| 216 | return; | ||
| 217 | qh->element = UHCI_PTR_TERM; | 328 | qh->element = UHCI_PTR_TERM; |
| 218 | 329 | ||
| 219 | /* Only bulk and interrupt pipes have to worry about toggles */ | 330 | /* Control pipes have to worry about toggles */ |
| 220 | if (!(usb_pipetype(urb->pipe) == PIPE_BULK || | 331 | if (qh->type == USB_ENDPOINT_XFER_CONTROL) |
| 221 | usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) | 332 | goto done; |
| 222 | return; | ||
| 223 | 333 | ||
| 224 | /* Find the first active TD; that's the device's toggle state */ | 334 | /* Save the next toggle value */ |
| 225 | list_for_each_entry(td, &urbp->td_list, list) { | 335 | WARN_ON(list_empty(&urbp->td_list)); |
| 226 | if (td_status(td) & TD_CTRL_ACTIVE) { | 336 | td = list_entry(urbp->td_list.next, struct uhci_td, list); |
| 227 | qh->needs_fixup = 1; | 337 | qh->needs_fixup = 1; |
| 228 | qh->initial_toggle = uhci_toggle(td_token(td)); | 338 | qh->initial_toggle = uhci_toggle(td_token(td)); |
| 229 | return; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | 339 | ||
| 233 | WARN_ON(1); | 340 | done: |
| 341 | return ret; | ||
| 234 | } | 342 | } |
| 235 | 343 | ||
| 236 | /* | 344 | /* |
| @@ -305,6 +413,10 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) | |||
| 305 | qh->element = cpu_to_le32(td->dma_handle); | 413 | qh->element = cpu_to_le32(td->dma_handle); |
| 306 | } | 414 | } |
| 307 | 415 | ||
| 416 | /* Treat the queue as if it has just advanced */ | ||
| 417 | qh->wait_expired = 0; | ||
| 418 | qh->advance_jiffies = jiffies; | ||
| 419 | |||
| 308 | if (qh->state == QH_STATE_ACTIVE) | 420 | if (qh->state == QH_STATE_ACTIVE) |
| 309 | return; | 421 | return; |
| 310 | qh->state = QH_STATE_ACTIVE; | 422 | qh->state = QH_STATE_ACTIVE; |
| @@ -370,6 +482,12 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh) | |||
| 370 | list_move(&qh->node, &uhci->idle_qh_list); | 482 | list_move(&qh->node, &uhci->idle_qh_list); |
| 371 | qh->state = QH_STATE_IDLE; | 483 | qh->state = QH_STATE_IDLE; |
| 372 | 484 | ||
| 485 | /* Now that the QH is idle, its post_td isn't being used */ | ||
| 486 | if (qh->post_td) { | ||
| 487 | uhci_free_td(uhci, qh->post_td); | ||
| 488 | qh->post_td = NULL; | ||
| 489 | } | ||
| 490 | |||
| 373 | /* If anyone is waiting for a QH to become idle, wake them up */ | 491 | /* If anyone is waiting for a QH to become idle, wake them up */ |
| 374 | if (uhci->num_waiting) | 492 | if (uhci->num_waiting) |
| 375 | wake_up_all(&uhci->waitqh); | 493 | wake_up_all(&uhci->waitqh); |
| @@ -395,21 +513,6 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, | |||
| 395 | return urbp; | 513 | return urbp; |
| 396 | } | 514 | } |
| 397 | 515 | ||
| 398 | static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td) | ||
| 399 | { | ||
| 400 | struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; | ||
| 401 | |||
| 402 | list_add_tail(&td->list, &urbp->td_list); | ||
| 403 | } | ||
| 404 | |||
| 405 | static void uhci_remove_td_from_urb(struct uhci_td *td) | ||
| 406 | { | ||
| 407 | if (list_empty(&td->list)) | ||
| 408 | return; | ||
| 409 | |||
| 410 | list_del_init(&td->list); | ||
| 411 | } | ||
| 412 | |||
| 413 | static void uhci_free_urb_priv(struct uhci_hcd *uhci, | 516 | static void uhci_free_urb_priv(struct uhci_hcd *uhci, |
| 414 | struct urb_priv *urbp) | 517 | struct urb_priv *urbp) |
| 415 | { | 518 | { |
| @@ -419,48 +522,15 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci, | |||
| 419 | dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n", | 522 | dev_warn(uhci_dev(uhci), "urb %p still on QH's list!\n", |
| 420 | urbp->urb); | 523 | urbp->urb); |
| 421 | 524 | ||
| 422 | uhci_get_current_frame_number(uhci); | ||
| 423 | if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) { | ||
| 424 | uhci_free_pending_tds(uhci); | ||
| 425 | uhci->td_remove_age = uhci->frame_number; | ||
| 426 | } | ||
| 427 | |||
| 428 | /* Check to see if the remove list is empty. Set the IOC bit */ | ||
| 429 | /* to force an interrupt so we can remove the TDs. */ | ||
| 430 | if (list_empty(&uhci->td_remove_list)) | ||
| 431 | uhci_set_next_interrupt(uhci); | ||
| 432 | |||
| 433 | list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { | 525 | list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { |
| 434 | uhci_remove_td_from_urb(td); | 526 | uhci_remove_td_from_urbp(td); |
| 435 | list_add(&td->remove_list, &uhci->td_remove_list); | 527 | uhci_free_td(uhci, td); |
| 436 | } | 528 | } |
| 437 | 529 | ||
| 438 | urbp->urb->hcpriv = NULL; | 530 | urbp->urb->hcpriv = NULL; |
| 439 | kmem_cache_free(uhci_up_cachep, urbp); | 531 | kmem_cache_free(uhci_up_cachep, urbp); |
| 440 | } | 532 | } |
| 441 | 533 | ||
| 442 | static void uhci_inc_fsbr(struct uhci_hcd *uhci, struct urb *urb) | ||
| 443 | { | ||
| 444 | struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; | ||
| 445 | |||
| 446 | if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) { | ||
| 447 | urbp->fsbr = 1; | ||
| 448 | if (!uhci->fsbr++ && !uhci->fsbrtimeout) | ||
| 449 | uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH; | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb) | ||
| 454 | { | ||
| 455 | struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; | ||
| 456 | |||
| 457 | if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) { | ||
| 458 | urbp->fsbr = 0; | ||
| 459 | if (!--uhci->fsbr) | ||
| 460 | uhci->fsbrtimeout = jiffies + FSBR_DELAY; | ||
| 461 | } | ||
| 462 | } | ||
| 463 | |||
| 464 | /* | 534 | /* |
| 465 | * Map status to standard result codes | 535 | * Map status to standard result codes |
| 466 | * | 536 | * |
| @@ -487,7 +557,6 @@ static int uhci_map_status(int status, int dir_out) | |||
| 487 | return -ENOSR; | 557 | return -ENOSR; |
| 488 | if (status & TD_CTRL_STALLED) /* Stalled */ | 558 | if (status & TD_CTRL_STALLED) /* Stalled */ |
| 489 | return -EPIPE; | 559 | return -EPIPE; |
| 490 | WARN_ON(status & TD_CTRL_ACTIVE); /* Active */ | ||
| 491 | return 0; | 560 | return 0; |
| 492 | } | 561 | } |
| 493 | 562 | ||
| @@ -503,6 +572,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, | |||
| 503 | int len = urb->transfer_buffer_length; | 572 | int len = urb->transfer_buffer_length; |
| 504 | dma_addr_t data = urb->transfer_dma; | 573 | dma_addr_t data = urb->transfer_dma; |
| 505 | __le32 *plink; | 574 | __le32 *plink; |
| 575 | struct urb_priv *urbp = urb->hcpriv; | ||
| 506 | 576 | ||
| 507 | /* The "pipe" thing contains the destination in bits 8--18 */ | 577 | /* The "pipe" thing contains the destination in bits 8--18 */ |
| 508 | destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; | 578 | destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; |
| @@ -516,7 +586,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, | |||
| 516 | * Build the TD for the control request setup packet | 586 | * Build the TD for the control request setup packet |
| 517 | */ | 587 | */ |
| 518 | td = qh->dummy_td; | 588 | td = qh->dummy_td; |
| 519 | uhci_add_td_to_urb(urb, td); | 589 | uhci_add_td_to_urbp(td, urbp); |
| 520 | uhci_fill_td(td, status, destination | uhci_explen(8), | 590 | uhci_fill_td(td, status, destination | uhci_explen(8), |
| 521 | urb->setup_dma); | 591 | urb->setup_dma); |
| 522 | plink = &td->link; | 592 | plink = &td->link; |
| @@ -548,7 +618,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, | |||
| 548 | /* Alternate Data0/1 (start with Data1) */ | 618 | /* Alternate Data0/1 (start with Data1) */ |
| 549 | destination ^= TD_TOKEN_TOGGLE; | 619 | destination ^= TD_TOKEN_TOGGLE; |
| 550 | 620 | ||
| 551 | uhci_add_td_to_urb(urb, td); | 621 | uhci_add_td_to_urbp(td, urbp); |
| 552 | uhci_fill_td(td, status, destination | uhci_explen(pktsze), | 622 | uhci_fill_td(td, status, destination | uhci_explen(pktsze), |
| 553 | data); | 623 | data); |
| 554 | plink = &td->link; | 624 | plink = &td->link; |
| @@ -579,7 +649,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, | |||
| 579 | 649 | ||
| 580 | status &= ~TD_CTRL_SPD; | 650 | status &= ~TD_CTRL_SPD; |
| 581 | 651 | ||
| 582 | uhci_add_td_to_urb(urb, td); | 652 | uhci_add_td_to_urbp(td, urbp); |
| 583 | uhci_fill_td(td, status | TD_CTRL_IOC, | 653 | uhci_fill_td(td, status | TD_CTRL_IOC, |
| 584 | destination | uhci_explen(0), 0); | 654 | destination | uhci_explen(0), 0); |
| 585 | plink = &td->link; | 655 | plink = &td->link; |
| @@ -606,145 +676,19 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, | |||
| 606 | qh->skel = uhci->skel_ls_control_qh; | 676 | qh->skel = uhci->skel_ls_control_qh; |
| 607 | else { | 677 | else { |
| 608 | qh->skel = uhci->skel_fs_control_qh; | 678 | qh->skel = uhci->skel_fs_control_qh; |
| 609 | uhci_inc_fsbr(uhci, urb); | 679 | uhci_add_fsbr(uhci, urb); |
| 610 | } | 680 | } |
| 681 | |||
| 682 | urb->actual_length = -8; /* Account for the SETUP packet */ | ||
| 611 | return 0; | 683 | return 0; |
| 612 | 684 | ||
| 613 | nomem: | 685 | nomem: |
| 614 | /* Remove the dummy TD from the td_list so it doesn't get freed */ | 686 | /* Remove the dummy TD from the td_list so it doesn't get freed */ |
| 615 | uhci_remove_td_from_urb(qh->dummy_td); | 687 | uhci_remove_td_from_urbp(qh->dummy_td); |
| 616 | return -ENOMEM; | 688 | return -ENOMEM; |
| 617 | } | 689 | } |
| 618 | 690 | ||
| 619 | /* | 691 | /* |
| 620 | * If control-IN transfer was short, the status packet wasn't sent. | ||
| 621 | * This routine changes the element pointer in the QH to point at the | ||
| 622 | * status TD. It's safe to do this even while the QH is live, because | ||
| 623 | * the hardware only updates the element pointer following a successful | ||
| 624 | * transfer. The inactive TD for the short packet won't cause an update, | ||
| 625 | * so the pointer won't get overwritten. The next time the controller | ||
| 626 | * sees this QH, it will send the status packet. | ||
| 627 | */ | ||
| 628 | static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb) | ||
| 629 | { | ||
| 630 | struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; | ||
| 631 | struct uhci_td *td; | ||
| 632 | |||
| 633 | urbp->short_transfer = 1; | ||
| 634 | |||
| 635 | td = list_entry(urbp->td_list.prev, struct uhci_td, list); | ||
| 636 | urbp->qh->element = cpu_to_le32(td->dma_handle); | ||
| 637 | |||
| 638 | return -EINPROGRESS; | ||
| 639 | } | ||
| 640 | |||
| 641 | |||
| 642 | static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb) | ||
| 643 | { | ||
| 644 | struct list_head *tmp, *head; | ||
| 645 | struct urb_priv *urbp = urb->hcpriv; | ||
| 646 | struct uhci_td *td; | ||
| 647 | unsigned int status; | ||
| 648 | int ret = 0; | ||
| 649 | |||
| 650 | head = &urbp->td_list; | ||
| 651 | if (urbp->short_transfer) { | ||
| 652 | tmp = head->prev; | ||
| 653 | goto status_stage; | ||
| 654 | } | ||
| 655 | |||
| 656 | urb->actual_length = 0; | ||
| 657 | |||
| 658 | tmp = head->next; | ||
| 659 | td = list_entry(tmp, struct uhci_td, list); | ||
| 660 | |||
| 661 | /* The first TD is the SETUP stage, check the status, but skip */ | ||
| 662 | /* the count */ | ||
| 663 | status = uhci_status_bits(td_status(td)); | ||
| 664 | if (status & TD_CTRL_ACTIVE) | ||
| 665 | return -EINPROGRESS; | ||
| 666 | |||
| 667 | if (status) | ||
| 668 | goto td_error; | ||
| 669 | |||
| 670 | /* The rest of the TDs (but the last) are data */ | ||
| 671 | tmp = tmp->next; | ||
| 672 | while (tmp != head && tmp->next != head) { | ||
| 673 | unsigned int ctrlstat; | ||
| 674 | |||
| 675 | td = list_entry(tmp, struct uhci_td, list); | ||
| 676 | tmp = tmp->next; | ||
| 677 | |||
| 678 | ctrlstat = td_status(td); | ||
| 679 | status = uhci_status_bits(ctrlstat); | ||
| 680 | if (status & TD_CTRL_ACTIVE) | ||
| 681 | return -EINPROGRESS; | ||
| 682 | |||
| 683 | urb->actual_length += uhci_actual_length(ctrlstat); | ||
| 684 | |||
| 685 | if (status) | ||
| 686 | goto td_error; | ||
| 687 | |||
| 688 | /* Check to see if we received a short packet */ | ||
| 689 | if (uhci_actual_length(ctrlstat) < | ||
| 690 | uhci_expected_length(td_token(td))) { | ||
| 691 | if (urb->transfer_flags & URB_SHORT_NOT_OK) { | ||
| 692 | ret = -EREMOTEIO; | ||
| 693 | goto err; | ||
| 694 | } | ||
| 695 | |||
| 696 | return usb_control_retrigger_status(uhci, urb); | ||
| 697 | } | ||
| 698 | } | ||
| 699 | |||
| 700 | status_stage: | ||
| 701 | td = list_entry(tmp, struct uhci_td, list); | ||
| 702 | |||
| 703 | /* Control status stage */ | ||
| 704 | status = td_status(td); | ||
| 705 | |||
| 706 | #ifdef I_HAVE_BUGGY_APC_BACKUPS | ||
| 707 | /* APC BackUPS Pro kludge */ | ||
| 708 | /* It tries to send all of the descriptor instead of the amount */ | ||
| 709 | /* we requested */ | ||
| 710 | if (status & TD_CTRL_IOC && /* IOC is masked out by uhci_status_bits */ | ||
| 711 | status & TD_CTRL_ACTIVE && | ||
| 712 | status & TD_CTRL_NAK) | ||
| 713 | return 0; | ||
| 714 | #endif | ||
| 715 | |||
| 716 | status = uhci_status_bits(status); | ||
| 717 | if (status & TD_CTRL_ACTIVE) | ||
| 718 | return -EINPROGRESS; | ||
| 719 | |||
| 720 | if (status) | ||
| 721 | goto td_error; | ||
| 722 | |||
| 723 | return 0; | ||
| 724 | |||
| 725 | td_error: | ||
| 726 | ret = uhci_map_status(status, uhci_packetout(td_token(td))); | ||
| 727 | |||
| 728 | err: | ||
| 729 | if ((debug == 1 && ret != -EPIPE) || debug > 1) { | ||
| 730 | /* Some debugging code */ | ||
| 731 | dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n", | ||
| 732 | __FUNCTION__, status); | ||
| 733 | |||
| 734 | if (errbuf) { | ||
| 735 | /* Print the chain for debugging purposes */ | ||
| 736 | uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0); | ||
| 737 | lprintk(errbuf); | ||
| 738 | } | ||
| 739 | } | ||
| 740 | |||
| 741 | /* Note that the queue has stopped */ | ||
| 742 | urbp->qh->element = UHCI_PTR_TERM; | ||
| 743 | urbp->qh->is_stopped = 1; | ||
| 744 | return ret; | ||
| 745 | } | ||
| 746 | |||
| 747 | /* | ||
| 748 | * Common submit for bulk and interrupt | 692 | * Common submit for bulk and interrupt |
| 749 | */ | 693 | */ |
| 750 | static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, | 694 | static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, |
| @@ -756,6 +700,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, | |||
| 756 | int len = urb->transfer_buffer_length; | 700 | int len = urb->transfer_buffer_length; |
| 757 | dma_addr_t data = urb->transfer_dma; | 701 | dma_addr_t data = urb->transfer_dma; |
| 758 | __le32 *plink; | 702 | __le32 *plink; |
| 703 | struct urb_priv *urbp = urb->hcpriv; | ||
| 759 | unsigned int toggle; | 704 | unsigned int toggle; |
| 760 | 705 | ||
| 761 | if (len < 0) | 706 | if (len < 0) |
| @@ -793,7 +738,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, | |||
| 793 | goto nomem; | 738 | goto nomem; |
| 794 | *plink = cpu_to_le32(td->dma_handle); | 739 | *plink = cpu_to_le32(td->dma_handle); |
| 795 | } | 740 | } |
| 796 | uhci_add_td_to_urb(urb, td); | 741 | uhci_add_td_to_urbp(td, urbp); |
| 797 | uhci_fill_td(td, status, | 742 | uhci_fill_td(td, status, |
| 798 | destination | uhci_explen(pktsze) | | 743 | destination | uhci_explen(pktsze) | |
| 799 | (toggle << TD_TOKEN_TOGGLE_SHIFT), | 744 | (toggle << TD_TOKEN_TOGGLE_SHIFT), |
| @@ -821,7 +766,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, | |||
| 821 | goto nomem; | 766 | goto nomem; |
| 822 | *plink = cpu_to_le32(td->dma_handle); | 767 | *plink = cpu_to_le32(td->dma_handle); |
| 823 | 768 | ||
| 824 | uhci_add_td_to_urb(urb, td); | 769 | uhci_add_td_to_urbp(td, urbp); |
| 825 | uhci_fill_td(td, status, | 770 | uhci_fill_td(td, status, |
| 826 | destination | uhci_explen(0) | | 771 | destination | uhci_explen(0) | |
| 827 | (toggle << TD_TOKEN_TOGGLE_SHIFT), | 772 | (toggle << TD_TOKEN_TOGGLE_SHIFT), |
| @@ -851,6 +796,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, | |||
| 851 | wmb(); | 796 | wmb(); |
| 852 | qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE); | 797 | qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE); |
| 853 | qh->dummy_td = td; | 798 | qh->dummy_td = td; |
| 799 | qh->period = urb->interval; | ||
| 854 | 800 | ||
| 855 | usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), | 801 | usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), |
| 856 | usb_pipeout(urb->pipe), toggle); | 802 | usb_pipeout(urb->pipe), toggle); |
| @@ -858,90 +804,10 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, | |||
| 858 | 804 | ||
| 859 | nomem: | 805 | nomem: |
| 860 | /* Remove the dummy TD from the td_list so it doesn't get freed */ | 806 | /* Remove the dummy TD from the td_list so it doesn't get freed */ |
| 861 | uhci_remove_td_from_urb(qh->dummy_td); | 807 | uhci_remove_td_from_urbp(qh->dummy_td); |
| 862 | return -ENOMEM; | 808 | return -ENOMEM; |
| 863 | } | 809 | } |
| 864 | 810 | ||
| 865 | /* | ||
| 866 | * Common result for bulk and interrupt | ||
| 867 | */ | ||
| 868 | static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) | ||
| 869 | { | ||
| 870 | struct urb_priv *urbp = urb->hcpriv; | ||
| 871 | struct uhci_td *td; | ||
| 872 | unsigned int status = 0; | ||
| 873 | int ret = 0; | ||
| 874 | |||
| 875 | urb->actual_length = 0; | ||
| 876 | |||
| 877 | list_for_each_entry(td, &urbp->td_list, list) { | ||
| 878 | unsigned int ctrlstat = td_status(td); | ||
| 879 | |||
| 880 | status = uhci_status_bits(ctrlstat); | ||
| 881 | if (status & TD_CTRL_ACTIVE) | ||
| 882 | return -EINPROGRESS; | ||
| 883 | |||
| 884 | urb->actual_length += uhci_actual_length(ctrlstat); | ||
| 885 | |||
| 886 | if (status) | ||
| 887 | goto td_error; | ||
| 888 | |||
| 889 | if (uhci_actual_length(ctrlstat) < | ||
| 890 | uhci_expected_length(td_token(td))) { | ||
| 891 | if (urb->transfer_flags & URB_SHORT_NOT_OK) { | ||
| 892 | ret = -EREMOTEIO; | ||
| 893 | goto err; | ||
| 894 | } | ||
| 895 | |||
| 896 | /* | ||
| 897 | * This URB stopped short of its end. We have to | ||
| 898 | * fix up the toggles of the following URBs on the | ||
| 899 | * queue and restart the queue. | ||
| 900 | * | ||
| 901 | * Do this only the first time we encounter the | ||
| 902 | * short URB. | ||
| 903 | */ | ||
| 904 | if (!urbp->short_transfer) { | ||
| 905 | urbp->short_transfer = 1; | ||
| 906 | urbp->qh->initial_toggle = | ||
| 907 | uhci_toggle(td_token(td)) ^ 1; | ||
| 908 | uhci_fixup_toggles(urbp->qh, 1); | ||
| 909 | |||
| 910 | td = list_entry(urbp->td_list.prev, | ||
| 911 | struct uhci_td, list); | ||
| 912 | urbp->qh->element = td->link; | ||
| 913 | } | ||
| 914 | break; | ||
| 915 | } | ||
| 916 | } | ||
| 917 | |||
| 918 | return 0; | ||
| 919 | |||
| 920 | td_error: | ||
| 921 | ret = uhci_map_status(status, uhci_packetout(td_token(td))); | ||
| 922 | |||
| 923 | if ((debug == 1 && ret != -EPIPE) || debug > 1) { | ||
| 924 | /* Some debugging code */ | ||
| 925 | dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n", | ||
| 926 | __FUNCTION__, status); | ||
| 927 | |||
| 928 | if (debug > 1 && errbuf) { | ||
| 929 | /* Print the chain for debugging purposes */ | ||
| 930 | uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0); | ||
| 931 | lprintk(errbuf); | ||
| 932 | } | ||
| 933 | } | ||
| 934 | err: | ||
| 935 | |||
| 936 | /* Note that the queue has stopped and save the next toggle value */ | ||
| 937 | urbp->qh->element = UHCI_PTR_TERM; | ||
| 938 | urbp->qh->is_stopped = 1; | ||
| 939 | urbp->qh->needs_fixup = 1; | ||
| 940 | urbp->qh->initial_toggle = uhci_toggle(td_token(td)) ^ | ||
| 941 | (ret == -EREMOTEIO); | ||
| 942 | return ret; | ||
| 943 | } | ||
| 944 | |||
| 945 | static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, | 811 | static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, |
| 946 | struct uhci_qh *qh) | 812 | struct uhci_qh *qh) |
| 947 | { | 813 | { |
| @@ -954,22 +820,163 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, | |||
| 954 | qh->skel = uhci->skel_bulk_qh; | 820 | qh->skel = uhci->skel_bulk_qh; |
| 955 | ret = uhci_submit_common(uhci, urb, qh); | 821 | ret = uhci_submit_common(uhci, urb, qh); |
| 956 | if (ret == 0) | 822 | if (ret == 0) |
| 957 | uhci_inc_fsbr(uhci, urb); | 823 | uhci_add_fsbr(uhci, urb); |
| 958 | return ret; | 824 | return ret; |
| 959 | } | 825 | } |
| 960 | 826 | ||
| 961 | static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, | 827 | static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, |
| 962 | struct uhci_qh *qh) | 828 | struct uhci_qh *qh) |
| 963 | { | 829 | { |
| 830 | int exponent; | ||
| 831 | |||
| 964 | /* USB 1.1 interrupt transfers only involve one packet per interval. | 832 | /* USB 1.1 interrupt transfers only involve one packet per interval. |
| 965 | * Drivers can submit URBs of any length, but longer ones will need | 833 | * Drivers can submit URBs of any length, but longer ones will need |
| 966 | * multiple intervals to complete. | 834 | * multiple intervals to complete. |
| 967 | */ | 835 | */ |
| 968 | qh->skel = uhci->skelqh[__interval_to_skel(urb->interval)]; | 836 | |
| 837 | /* Figure out which power-of-two queue to use */ | ||
| 838 | for (exponent = 7; exponent >= 0; --exponent) { | ||
| 839 | if ((1 << exponent) <= urb->interval) | ||
| 840 | break; | ||
| 841 | } | ||
| 842 | if (exponent < 0) | ||
| 843 | return -EINVAL; | ||
| 844 | urb->interval = 1 << exponent; | ||
| 845 | |||
| 846 | if (qh->period == 0) | ||
| 847 | qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)]; | ||
| 848 | else if (qh->period != urb->interval) | ||
| 849 | return -EINVAL; /* Can't change the period */ | ||
| 850 | |||
| 969 | return uhci_submit_common(uhci, urb, qh); | 851 | return uhci_submit_common(uhci, urb, qh); |
| 970 | } | 852 | } |
| 971 | 853 | ||
| 972 | /* | 854 | /* |
| 855 | * Fix up the data structures following a short transfer | ||
| 856 | */ | ||
| 857 | static int uhci_fixup_short_transfer(struct uhci_hcd *uhci, | ||
| 858 | struct uhci_qh *qh, struct urb_priv *urbp) | ||
| 859 | { | ||
| 860 | struct uhci_td *td; | ||
| 861 | struct list_head *tmp; | ||
| 862 | int ret; | ||
| 863 | |||
| 864 | td = list_entry(urbp->td_list.prev, struct uhci_td, list); | ||
| 865 | if (qh->type == USB_ENDPOINT_XFER_CONTROL) { | ||
| 866 | |||
| 867 | /* When a control transfer is short, we have to restart | ||
| 868 | * the queue at the status stage transaction, which is | ||
| 869 | * the last TD. */ | ||
| 870 | WARN_ON(list_empty(&urbp->td_list)); | ||
| 871 | qh->element = cpu_to_le32(td->dma_handle); | ||
| 872 | tmp = td->list.prev; | ||
| 873 | ret = -EINPROGRESS; | ||
| 874 | |||
| 875 | } else { | ||
| 876 | |||
| 877 | /* When a bulk/interrupt transfer is short, we have to | ||
| 878 | * fix up the toggles of the following URBs on the queue | ||
| 879 | * before restarting the queue at the next URB. */ | ||
| 880 | qh->initial_toggle = uhci_toggle(td_token(qh->post_td)) ^ 1; | ||
| 881 | uhci_fixup_toggles(qh, 1); | ||
| 882 | |||
| 883 | if (list_empty(&urbp->td_list)) | ||
| 884 | td = qh->post_td; | ||
| 885 | qh->element = td->link; | ||
| 886 | tmp = urbp->td_list.prev; | ||
| 887 | ret = 0; | ||
| 888 | } | ||
| 889 | |||
| 890 | /* Remove all the TDs we skipped over, from tmp back to the start */ | ||
| 891 | while (tmp != &urbp->td_list) { | ||
| 892 | td = list_entry(tmp, struct uhci_td, list); | ||
| 893 | tmp = tmp->prev; | ||
| 894 | |||
| 895 | uhci_remove_td_from_urbp(td); | ||
| 896 | uhci_free_td(uhci, td); | ||
| 897 | } | ||
| 898 | return ret; | ||
| 899 | } | ||
| 900 | |||
| 901 | /* | ||
| 902 | * Common result for control, bulk, and interrupt | ||
| 903 | */ | ||
| 904 | static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) | ||
| 905 | { | ||
| 906 | struct urb_priv *urbp = urb->hcpriv; | ||
| 907 | struct uhci_qh *qh = urbp->qh; | ||
| 908 | struct uhci_td *td, *tmp; | ||
| 909 | unsigned status; | ||
| 910 | int ret = 0; | ||
| 911 | |||
| 912 | list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { | ||
| 913 | unsigned int ctrlstat; | ||
| 914 | int len; | ||
| 915 | |||
| 916 | ctrlstat = td_status(td); | ||
| 917 | status = uhci_status_bits(ctrlstat); | ||
| 918 | if (status & TD_CTRL_ACTIVE) | ||
| 919 | return -EINPROGRESS; | ||
| 920 | |||
| 921 | len = uhci_actual_length(ctrlstat); | ||
| 922 | urb->actual_length += len; | ||
| 923 | |||
| 924 | if (status) { | ||
| 925 | ret = uhci_map_status(status, | ||
| 926 | uhci_packetout(td_token(td))); | ||
| 927 | if ((debug == 1 && ret != -EPIPE) || debug > 1) { | ||
| 928 | /* Some debugging code */ | ||
| 929 | dev_dbg(&urb->dev->dev, | ||
| 930 | "%s: failed with status %x\n", | ||
| 931 | __FUNCTION__, status); | ||
| 932 | |||
| 933 | if (debug > 1 && errbuf) { | ||
| 934 | /* Print the chain for debugging */ | ||
| 935 | uhci_show_qh(urbp->qh, errbuf, | ||
| 936 | ERRBUF_LEN, 0); | ||
| 937 | lprintk(errbuf); | ||
| 938 | } | ||
| 939 | } | ||
| 940 | |||
| 941 | } else if (len < uhci_expected_length(td_token(td))) { | ||
| 942 | |||
| 943 | /* We received a short packet */ | ||
| 944 | if (urb->transfer_flags & URB_SHORT_NOT_OK) | ||
| 945 | ret = -EREMOTEIO; | ||
| 946 | else if (ctrlstat & TD_CTRL_SPD) | ||
| 947 | ret = 1; | ||
| 948 | } | ||
| 949 | |||
| 950 | uhci_remove_td_from_urbp(td); | ||
| 951 | if (qh->post_td) | ||
| 952 | uhci_free_td(uhci, qh->post_td); | ||
| 953 | qh->post_td = td; | ||
| 954 | |||
| 955 | if (ret != 0) | ||
| 956 | goto err; | ||
| 957 | } | ||
| 958 | return ret; | ||
| 959 | |||
| 960 | err: | ||
| 961 | if (ret < 0) { | ||
| 962 | /* In case a control transfer gets an error | ||
| 963 | * during the setup stage */ | ||
| 964 | urb->actual_length = max(urb->actual_length, 0); | ||
| 965 | |||
| 966 | /* Note that the queue has stopped and save | ||
| 967 | * the next toggle value */ | ||
| 968 | qh->element = UHCI_PTR_TERM; | ||
| 969 | qh->is_stopped = 1; | ||
| 970 | qh->needs_fixup = (qh->type != USB_ENDPOINT_XFER_CONTROL); | ||
| 971 | qh->initial_toggle = uhci_toggle(td_token(td)) ^ | ||
| 972 | (ret == -EREMOTEIO); | ||
| 973 | |||
| 974 | } else /* Short packet received */ | ||
| 975 | ret = uhci_fixup_short_transfer(uhci, qh, urbp); | ||
| 976 | return ret; | ||
| 977 | } | ||
| 978 | |||
| 979 | /* | ||
| 973 | * Isochronous transfers | 980 | * Isochronous transfers |
| 974 | */ | 981 | */ |
| 975 | static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, | 982 | static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, |
| @@ -980,38 +987,57 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, | |||
| 980 | unsigned long destination, status; | 987 | unsigned long destination, status; |
| 981 | struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; | 988 | struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; |
| 982 | 989 | ||
| 983 | if (urb->number_of_packets > 900) /* 900? Why? */ | 990 | /* Values must not be too big (could overflow below) */ |
| 991 | if (urb->interval >= UHCI_NUMFRAMES || | ||
| 992 | urb->number_of_packets >= UHCI_NUMFRAMES) | ||
| 984 | return -EFBIG; | 993 | return -EFBIG; |
| 985 | 994 | ||
| 986 | status = TD_CTRL_ACTIVE | TD_CTRL_IOS; | 995 | /* Check the period and figure out the starting frame number */ |
| 987 | destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); | 996 | if (qh->period == 0) { |
| 988 | 997 | if (urb->transfer_flags & URB_ISO_ASAP) { | |
| 989 | /* Figure out the starting frame number */ | ||
| 990 | if (urb->transfer_flags & URB_ISO_ASAP) { | ||
| 991 | if (list_empty(&qh->queue)) { | ||
| 992 | uhci_get_current_frame_number(uhci); | 998 | uhci_get_current_frame_number(uhci); |
| 993 | urb->start_frame = (uhci->frame_number + 10); | 999 | urb->start_frame = uhci->frame_number + 10; |
| 1000 | } else { | ||
| 1001 | i = urb->start_frame - uhci->last_iso_frame; | ||
| 1002 | if (i <= 0 || i >= UHCI_NUMFRAMES) | ||
| 1003 | return -EINVAL; | ||
| 1004 | } | ||
| 1005 | } else if (qh->period != urb->interval) { | ||
| 1006 | return -EINVAL; /* Can't change the period */ | ||
| 994 | 1007 | ||
| 995 | } else { /* Go right after the last one */ | 1008 | } else { /* Pick up where the last URB leaves off */ |
| 996 | struct urb *last_urb; | 1009 | if (list_empty(&qh->queue)) { |
| 1010 | frame = qh->iso_frame; | ||
| 1011 | } else { | ||
| 1012 | struct urb *lurb; | ||
| 997 | 1013 | ||
| 998 | last_urb = list_entry(qh->queue.prev, | 1014 | lurb = list_entry(qh->queue.prev, |
| 999 | struct urb_priv, node)->urb; | 1015 | struct urb_priv, node)->urb; |
| 1000 | urb->start_frame = (last_urb->start_frame + | 1016 | frame = lurb->start_frame + |
| 1001 | last_urb->number_of_packets * | 1017 | lurb->number_of_packets * |
| 1002 | last_urb->interval); | 1018 | lurb->interval; |
| 1003 | } | 1019 | } |
| 1004 | } else { | 1020 | if (urb->transfer_flags & URB_ISO_ASAP) |
| 1005 | /* FIXME: Sanity check */ | 1021 | urb->start_frame = frame; |
| 1022 | else if (urb->start_frame != frame) | ||
| 1023 | return -EINVAL; | ||
| 1006 | } | 1024 | } |
| 1007 | urb->start_frame &= (UHCI_NUMFRAMES - 1); | 1025 | |
| 1026 | /* Make sure we won't have to go too far into the future */ | ||
| 1027 | if (uhci_frame_before_eq(uhci->last_iso_frame + UHCI_NUMFRAMES, | ||
| 1028 | urb->start_frame + urb->number_of_packets * | ||
| 1029 | urb->interval)) | ||
| 1030 | return -EFBIG; | ||
| 1031 | |||
| 1032 | status = TD_CTRL_ACTIVE | TD_CTRL_IOS; | ||
| 1033 | destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); | ||
| 1008 | 1034 | ||
| 1009 | for (i = 0; i < urb->number_of_packets; i++) { | 1035 | for (i = 0; i < urb->number_of_packets; i++) { |
| 1010 | td = uhci_alloc_td(uhci); | 1036 | td = uhci_alloc_td(uhci); |
| 1011 | if (!td) | 1037 | if (!td) |
| 1012 | return -ENOMEM; | 1038 | return -ENOMEM; |
| 1013 | 1039 | ||
| 1014 | uhci_add_td_to_urb(urb, td); | 1040 | uhci_add_td_to_urbp(td, urbp); |
| 1015 | uhci_fill_td(td, status, destination | | 1041 | uhci_fill_td(td, status, destination | |
| 1016 | uhci_explen(urb->iso_frame_desc[i].length), | 1042 | uhci_explen(urb->iso_frame_desc[i].length), |
| 1017 | urb->transfer_dma + | 1043 | urb->transfer_dma + |
| @@ -1022,12 +1048,19 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, | |||
| 1022 | td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); | 1048 | td->status |= __constant_cpu_to_le32(TD_CTRL_IOC); |
| 1023 | 1049 | ||
| 1024 | qh->skel = uhci->skel_iso_qh; | 1050 | qh->skel = uhci->skel_iso_qh; |
| 1051 | qh->period = urb->interval; | ||
| 1025 | 1052 | ||
| 1026 | /* Add the TDs to the frame list */ | 1053 | /* Add the TDs to the frame list */ |
| 1027 | frame = urb->start_frame; | 1054 | frame = urb->start_frame; |
| 1028 | list_for_each_entry(td, &urbp->td_list, list) { | 1055 | list_for_each_entry(td, &urbp->td_list, list) { |
| 1029 | uhci_insert_td_in_frame_list(uhci, td, frame); | 1056 | uhci_insert_td_in_frame_list(uhci, td, frame); |
| 1030 | frame += urb->interval; | 1057 | frame += qh->period; |
| 1058 | } | ||
| 1059 | |||
| 1060 | if (list_empty(&qh->queue)) { | ||
| 1061 | qh->iso_packet_desc = &urb->iso_frame_desc[0]; | ||
| 1062 | qh->iso_frame = urb->start_frame; | ||
| 1063 | qh->iso_status = 0; | ||
| 1031 | } | 1064 | } |
| 1032 | 1065 | ||
| 1033 | return 0; | 1066 | return 0; |
| @@ -1035,37 +1068,44 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, | |||
| 1035 | 1068 | ||
| 1036 | static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) | 1069 | static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) |
| 1037 | { | 1070 | { |
| 1038 | struct uhci_td *td; | 1071 | struct uhci_td *td, *tmp; |
| 1039 | struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv; | 1072 | struct urb_priv *urbp = urb->hcpriv; |
| 1040 | int status; | 1073 | struct uhci_qh *qh = urbp->qh; |
| 1041 | int i, ret = 0; | ||
| 1042 | |||
| 1043 | urb->actual_length = urb->error_count = 0; | ||
| 1044 | 1074 | ||
| 1045 | i = 0; | 1075 | list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { |
| 1046 | list_for_each_entry(td, &urbp->td_list, list) { | 1076 | unsigned int ctrlstat; |
| 1077 | int status; | ||
| 1047 | int actlength; | 1078 | int actlength; |
| 1048 | unsigned int ctrlstat = td_status(td); | ||
| 1049 | 1079 | ||
| 1050 | if (ctrlstat & TD_CTRL_ACTIVE) | 1080 | if (uhci_frame_before_eq(uhci->cur_iso_frame, qh->iso_frame)) |
| 1051 | return -EINPROGRESS; | 1081 | return -EINPROGRESS; |
| 1052 | 1082 | ||
| 1053 | actlength = uhci_actual_length(ctrlstat); | 1083 | uhci_remove_tds_from_frame(uhci, qh->iso_frame); |
| 1054 | urb->iso_frame_desc[i].actual_length = actlength; | 1084 | |
| 1055 | urb->actual_length += actlength; | 1085 | ctrlstat = td_status(td); |
| 1086 | if (ctrlstat & TD_CTRL_ACTIVE) { | ||
| 1087 | status = -EXDEV; /* TD was added too late? */ | ||
| 1088 | } else { | ||
| 1089 | status = uhci_map_status(uhci_status_bits(ctrlstat), | ||
| 1090 | usb_pipeout(urb->pipe)); | ||
| 1091 | actlength = uhci_actual_length(ctrlstat); | ||
| 1092 | |||
| 1093 | urb->actual_length += actlength; | ||
| 1094 | qh->iso_packet_desc->actual_length = actlength; | ||
| 1095 | qh->iso_packet_desc->status = status; | ||
| 1096 | } | ||
| 1056 | 1097 | ||
| 1057 | status = uhci_map_status(uhci_status_bits(ctrlstat), | ||
| 1058 | usb_pipeout(urb->pipe)); | ||
| 1059 | urb->iso_frame_desc[i].status = status; | ||
| 1060 | if (status) { | 1098 | if (status) { |
| 1061 | urb->error_count++; | 1099 | urb->error_count++; |
| 1062 | ret = status; | 1100 | qh->iso_status = status; |
| 1063 | } | 1101 | } |
| 1064 | 1102 | ||
| 1065 | i++; | 1103 | uhci_remove_td_from_urbp(td); |
| 1104 | uhci_free_td(uhci, td); | ||
| 1105 | qh->iso_frame += qh->period; | ||
| 1106 | ++qh->iso_packet_desc; | ||
| 1066 | } | 1107 | } |
| 1067 | 1108 | return qh->iso_status; | |
| 1068 | return ret; | ||
| 1069 | } | 1109 | } |
| 1070 | 1110 | ||
| 1071 | static int uhci_urb_enqueue(struct usb_hcd *hcd, | 1111 | static int uhci_urb_enqueue(struct usb_hcd *hcd, |
| @@ -1099,14 +1139,14 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, | |||
| 1099 | } | 1139 | } |
| 1100 | urbp->qh = qh; | 1140 | urbp->qh = qh; |
| 1101 | 1141 | ||
| 1102 | switch (usb_pipetype(urb->pipe)) { | 1142 | switch (qh->type) { |
| 1103 | case PIPE_CONTROL: | 1143 | case USB_ENDPOINT_XFER_CONTROL: |
| 1104 | ret = uhci_submit_control(uhci, urb, qh); | 1144 | ret = uhci_submit_control(uhci, urb, qh); |
| 1105 | break; | 1145 | break; |
| 1106 | case PIPE_BULK: | 1146 | case USB_ENDPOINT_XFER_BULK: |
| 1107 | ret = uhci_submit_bulk(uhci, urb, qh); | 1147 | ret = uhci_submit_bulk(uhci, urb, qh); |
| 1108 | break; | 1148 | break; |
| 1109 | case PIPE_INTERRUPT: | 1149 | case USB_ENDPOINT_XFER_INT: |
| 1110 | if (list_empty(&qh->queue)) { | 1150 | if (list_empty(&qh->queue)) { |
| 1111 | bustime = usb_check_bandwidth(urb->dev, urb); | 1151 | bustime = usb_check_bandwidth(urb->dev, urb); |
| 1112 | if (bustime < 0) | 1152 | if (bustime < 0) |
| @@ -1125,7 +1165,8 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, | |||
| 1125 | ret = uhci_submit_interrupt(uhci, urb, qh); | 1165 | ret = uhci_submit_interrupt(uhci, urb, qh); |
| 1126 | } | 1166 | } |
| 1127 | break; | 1167 | break; |
| 1128 | case PIPE_ISOCHRONOUS: | 1168 | case USB_ENDPOINT_XFER_ISOC: |
| 1169 | urb->error_count = 0; | ||
| 1129 | bustime = usb_check_bandwidth(urb->dev, urb); | 1170 | bustime = usb_check_bandwidth(urb->dev, urb); |
| 1130 | if (bustime < 0) { | 1171 | if (bustime < 0) { |
| 1131 | ret = bustime; | 1172 | ret = bustime; |
| @@ -1146,9 +1187,12 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, | |||
| 1146 | 1187 | ||
| 1147 | /* If the new URB is the first and only one on this QH then either | 1188 | /* If the new URB is the first and only one on this QH then either |
| 1148 | * the QH is new and idle or else it's unlinked and waiting to | 1189 | * the QH is new and idle or else it's unlinked and waiting to |
| 1149 | * become idle, so we can activate it right away. */ | 1190 | * become idle, so we can activate it right away. But only if the |
| 1150 | if (qh->queue.next == &urbp->node) | 1191 | * queue isn't stopped. */ |
| 1192 | if (qh->queue.next == &urbp->node && !qh->is_stopped) { | ||
| 1151 | uhci_activate_qh(uhci, qh); | 1193 | uhci_activate_qh(uhci, qh); |
| 1194 | uhci_urbp_wants_fsbr(uhci, urbp); | ||
| 1195 | } | ||
| 1152 | goto done; | 1196 | goto done; |
| 1153 | 1197 | ||
| 1154 | err_submit_failed: | 1198 | err_submit_failed: |
| @@ -1168,16 +1212,26 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) | |||
| 1168 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); | 1212 | struct uhci_hcd *uhci = hcd_to_uhci(hcd); |
| 1169 | unsigned long flags; | 1213 | unsigned long flags; |
| 1170 | struct urb_priv *urbp; | 1214 | struct urb_priv *urbp; |
| 1215 | struct uhci_qh *qh; | ||
| 1171 | 1216 | ||
| 1172 | spin_lock_irqsave(&uhci->lock, flags); | 1217 | spin_lock_irqsave(&uhci->lock, flags); |
| 1173 | urbp = urb->hcpriv; | 1218 | urbp = urb->hcpriv; |
| 1174 | if (!urbp) /* URB was never linked! */ | 1219 | if (!urbp) /* URB was never linked! */ |
| 1175 | goto done; | 1220 | goto done; |
| 1221 | qh = urbp->qh; | ||
| 1176 | 1222 | ||
| 1177 | /* Remove Isochronous TDs from the frame list ASAP */ | 1223 | /* Remove Isochronous TDs from the frame list ASAP */ |
| 1178 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) | 1224 | if (qh->type == USB_ENDPOINT_XFER_ISOC) { |
| 1179 | uhci_unlink_isochronous_tds(uhci, urb); | 1225 | uhci_unlink_isochronous_tds(uhci, urb); |
| 1180 | uhci_unlink_qh(uhci, urbp->qh); | 1226 | mb(); |
| 1227 | |||
| 1228 | /* If the URB has already started, update the QH unlink time */ | ||
| 1229 | uhci_get_current_frame_number(uhci); | ||
| 1230 | if (uhci_frame_before_eq(urb->start_frame, uhci->frame_number)) | ||
| 1231 | qh->unlink_frame = uhci->frame_number; | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | uhci_unlink_qh(uhci, qh); | ||
| 1181 | 1235 | ||
| 1182 | done: | 1236 | done: |
| 1183 | spin_unlock_irqrestore(&uhci->lock, flags); | 1237 | spin_unlock_irqrestore(&uhci->lock, flags); |
| @@ -1194,22 +1248,17 @@ __acquires(uhci->lock) | |||
| 1194 | { | 1248 | { |
| 1195 | struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; | 1249 | struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; |
| 1196 | 1250 | ||
| 1197 | /* Isochronous TDs get unlinked directly from the frame list */ | 1251 | /* When giving back the first URB in an Isochronous queue, |
| 1198 | if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) | 1252 | * reinitialize the QH's iso-related members for the next URB. */ |
| 1199 | uhci_unlink_isochronous_tds(uhci, urb); | 1253 | if (qh->type == USB_ENDPOINT_XFER_ISOC && |
| 1200 | 1254 | urbp->node.prev == &qh->queue && | |
| 1201 | /* If the URB isn't first on its queue, adjust the link pointer | 1255 | urbp->node.next != &qh->queue) { |
| 1202 | * of the last TD in the previous URB. */ | 1256 | struct urb *nurb = list_entry(urbp->node.next, |
| 1203 | else if (qh->queue.next != &urbp->node) { | 1257 | struct urb_priv, node)->urb; |
| 1204 | struct urb_priv *purbp; | 1258 | |
| 1205 | struct uhci_td *ptd, *ltd; | 1259 | qh->iso_packet_desc = &nurb->iso_frame_desc[0]; |
| 1206 | 1260 | qh->iso_frame = nurb->start_frame; | |
| 1207 | purbp = list_entry(urbp->node.prev, struct urb_priv, node); | 1261 | qh->iso_status = 0; |
| 1208 | ptd = list_entry(purbp->td_list.prev, struct uhci_td, | ||
| 1209 | list); | ||
| 1210 | ltd = list_entry(urbp->td_list.prev, struct uhci_td, | ||
| 1211 | list); | ||
| 1212 | ptd->link = ltd->link; | ||
| 1213 | } | 1262 | } |
| 1214 | 1263 | ||
| 1215 | /* Take the URB off the QH's queue. If the queue is now empty, | 1264 | /* Take the URB off the QH's queue. If the queue is now empty, |
| @@ -1221,16 +1270,15 @@ __acquires(uhci->lock) | |||
| 1221 | qh->needs_fixup = 0; | 1270 | qh->needs_fixup = 0; |
| 1222 | } | 1271 | } |
| 1223 | 1272 | ||
| 1224 | uhci_dec_fsbr(uhci, urb); /* Safe since it checks */ | ||
| 1225 | uhci_free_urb_priv(uhci, urbp); | 1273 | uhci_free_urb_priv(uhci, urbp); |
| 1226 | 1274 | ||
| 1227 | switch (usb_pipetype(urb->pipe)) { | 1275 | switch (qh->type) { |
| 1228 | case PIPE_ISOCHRONOUS: | 1276 | case USB_ENDPOINT_XFER_ISOC: |
| 1229 | /* Release bandwidth for Interrupt or Isoc. transfers */ | 1277 | /* Release bandwidth for Interrupt or Isoc. transfers */ |
| 1230 | if (urb->bandwidth) | 1278 | if (urb->bandwidth) |
| 1231 | usb_release_bandwidth(urb->dev, urb, 1); | 1279 | usb_release_bandwidth(urb->dev, urb, 1); |
| 1232 | break; | 1280 | break; |
| 1233 | case PIPE_INTERRUPT: | 1281 | case USB_ENDPOINT_XFER_INT: |
| 1234 | /* Release bandwidth for Interrupt or Isoc. transfers */ | 1282 | /* Release bandwidth for Interrupt or Isoc. transfers */ |
| 1235 | /* Make sure we don't release if we have a queued URB */ | 1283 | /* Make sure we don't release if we have a queued URB */ |
| 1236 | if (list_empty(&qh->queue) && urb->bandwidth) | 1284 | if (list_empty(&qh->queue) && urb->bandwidth) |
| @@ -1252,6 +1300,7 @@ __acquires(uhci->lock) | |||
| 1252 | uhci_unlink_qh(uhci, qh); | 1300 | uhci_unlink_qh(uhci, qh); |
| 1253 | 1301 | ||
| 1254 | /* Bandwidth stuff not yet implemented */ | 1302 | /* Bandwidth stuff not yet implemented */ |
| 1303 | qh->period = 0; | ||
| 1255 | } | 1304 | } |
| 1256 | } | 1305 | } |
| 1257 | 1306 | ||
| @@ -1273,17 +1322,10 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh, | |||
| 1273 | urbp = list_entry(qh->queue.next, struct urb_priv, node); | 1322 | urbp = list_entry(qh->queue.next, struct urb_priv, node); |
| 1274 | urb = urbp->urb; | 1323 | urb = urbp->urb; |
| 1275 | 1324 | ||
| 1276 | switch (usb_pipetype(urb->pipe)) { | 1325 | if (qh->type == USB_ENDPOINT_XFER_ISOC) |
| 1277 | case PIPE_CONTROL: | ||
| 1278 | status = uhci_result_control(uhci, urb); | ||
| 1279 | break; | ||
| 1280 | case PIPE_ISOCHRONOUS: | ||
| 1281 | status = uhci_result_isochronous(uhci, urb); | 1326 | status = uhci_result_isochronous(uhci, urb); |
| 1282 | break; | 1327 | else |
| 1283 | default: /* PIPE_BULK or PIPE_INTERRUPT */ | ||
| 1284 | status = uhci_result_common(uhci, urb); | 1328 | status = uhci_result_common(uhci, urb); |
| 1285 | break; | ||
| 1286 | } | ||
| 1287 | if (status == -EINPROGRESS) | 1329 | if (status == -EINPROGRESS) |
| 1288 | break; | 1330 | break; |
| 1289 | 1331 | ||
| @@ -1291,31 +1333,43 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh, | |||
| 1291 | if (urb->status == -EINPROGRESS) /* Not dequeued */ | 1333 | if (urb->status == -EINPROGRESS) /* Not dequeued */ |
| 1292 | urb->status = status; | 1334 | urb->status = status; |
| 1293 | else | 1335 | else |
| 1294 | status = -ECONNRESET; | 1336 | status = ECONNRESET; /* Not -ECONNRESET */ |
| 1295 | spin_unlock(&urb->lock); | 1337 | spin_unlock(&urb->lock); |
| 1296 | 1338 | ||
| 1297 | /* Dequeued but completed URBs can't be given back unless | 1339 | /* Dequeued but completed URBs can't be given back unless |
| 1298 | * the QH is stopped or has finished unlinking. */ | 1340 | * the QH is stopped or has finished unlinking. */ |
| 1299 | if (status == -ECONNRESET && | 1341 | if (status == ECONNRESET) { |
| 1300 | !(qh->is_stopped || QH_FINISHED_UNLINKING(qh))) | 1342 | if (QH_FINISHED_UNLINKING(qh)) |
| 1301 | return; | 1343 | qh->is_stopped = 1; |
| 1344 | else if (!qh->is_stopped) | ||
| 1345 | return; | ||
| 1346 | } | ||
| 1302 | 1347 | ||
| 1303 | uhci_giveback_urb(uhci, qh, urb, regs); | 1348 | uhci_giveback_urb(uhci, qh, urb, regs); |
| 1304 | if (qh->is_stopped) | 1349 | if (status < 0) |
| 1305 | break; | 1350 | break; |
| 1306 | } | 1351 | } |
| 1307 | 1352 | ||
| 1308 | /* If the QH is neither stopped nor finished unlinking (normal case), | 1353 | /* If the QH is neither stopped nor finished unlinking (normal case), |
| 1309 | * our work here is done. */ | 1354 | * our work here is done. */ |
| 1310 | restart: | 1355 | if (QH_FINISHED_UNLINKING(qh)) |
| 1311 | if (!(qh->is_stopped || QH_FINISHED_UNLINKING(qh))) | 1356 | qh->is_stopped = 1; |
| 1357 | else if (!qh->is_stopped) | ||
| 1312 | return; | 1358 | return; |
| 1313 | 1359 | ||
| 1314 | /* Otherwise give back each of the dequeued URBs */ | 1360 | /* Otherwise give back each of the dequeued URBs */ |
| 1361 | restart: | ||
| 1315 | list_for_each_entry(urbp, &qh->queue, node) { | 1362 | list_for_each_entry(urbp, &qh->queue, node) { |
| 1316 | urb = urbp->urb; | 1363 | urb = urbp->urb; |
| 1317 | if (urb->status != -EINPROGRESS) { | 1364 | if (urb->status != -EINPROGRESS) { |
| 1318 | uhci_save_toggle(qh, urb); | 1365 | |
| 1366 | /* Fix up the TD links and save the toggles for | ||
| 1367 | * non-Isochronous queues. For Isochronous queues, | ||
| 1368 | * test for too-recent dequeues. */ | ||
| 1369 | if (!uhci_cleanup_queue(uhci, qh, urb)) { | ||
| 1370 | qh->is_stopped = 0; | ||
| 1371 | return; | ||
| 1372 | } | ||
| 1319 | uhci_giveback_urb(uhci, qh, urb, regs); | 1373 | uhci_giveback_urb(uhci, qh, urb, regs); |
| 1320 | goto restart; | 1374 | goto restart; |
| 1321 | } | 1375 | } |
| @@ -1327,6 +1381,18 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh, | |||
| 1327 | if (!list_empty(&qh->queue)) { | 1381 | if (!list_empty(&qh->queue)) { |
| 1328 | if (qh->needs_fixup) | 1382 | if (qh->needs_fixup) |
| 1329 | uhci_fixup_toggles(qh, 0); | 1383 | uhci_fixup_toggles(qh, 0); |
| 1384 | |||
| 1385 | /* If the first URB on the queue wants FSBR but its time | ||
| 1386 | * limit has expired, set the next TD to interrupt on | ||
| 1387 | * completion before reactivating the QH. */ | ||
| 1388 | urbp = list_entry(qh->queue.next, struct urb_priv, node); | ||
| 1389 | if (urbp->fsbr && qh->wait_expired) { | ||
| 1390 | struct uhci_td *td = list_entry(urbp->td_list.next, | ||
| 1391 | struct uhci_td, list); | ||
| 1392 | |||
| 1393 | td->status |= __cpu_to_le32(TD_CTRL_IOC); | ||
| 1394 | } | ||
| 1395 | |||
| 1330 | uhci_activate_qh(uhci, qh); | 1396 | uhci_activate_qh(uhci, qh); |
| 1331 | } | 1397 | } |
| 1332 | 1398 | ||
| @@ -1336,15 +1402,84 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh, | |||
| 1336 | uhci_make_qh_idle(uhci, qh); | 1402 | uhci_make_qh_idle(uhci, qh); |
| 1337 | } | 1403 | } |
| 1338 | 1404 | ||
| 1339 | static void uhci_free_pending_tds(struct uhci_hcd *uhci) | 1405 | /* |
| 1406 | * Check for queues that have made some forward progress. | ||
| 1407 | * Returns 0 if the queue is not Isochronous, is ACTIVE, and | ||
| 1408 | * has not advanced since last examined; 1 otherwise. | ||
| 1409 | * | ||
| 1410 | * Early Intel controllers have a bug which causes qh->element sometimes | ||
| 1411 | * not to advance when a TD completes successfully. The queue remains | ||
| 1412 | * stuck on the inactive completed TD. We detect such cases and advance | ||
| 1413 | * the element pointer by hand. | ||
| 1414 | */ | ||
| 1415 | static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh) | ||
| 1340 | { | 1416 | { |
| 1341 | struct uhci_td *td, *tmp; | 1417 | struct urb_priv *urbp = NULL; |
| 1418 | struct uhci_td *td; | ||
| 1419 | int ret = 1; | ||
| 1420 | unsigned status; | ||
| 1342 | 1421 | ||
| 1343 | list_for_each_entry_safe(td, tmp, &uhci->td_remove_list, remove_list) { | 1422 | if (qh->type == USB_ENDPOINT_XFER_ISOC) |
| 1344 | list_del_init(&td->remove_list); | 1423 | goto done; |
| 1345 | 1424 | ||
| 1346 | uhci_free_td(uhci, td); | 1425 | /* Treat an UNLINKING queue as though it hasn't advanced. |
| 1426 | * This is okay because reactivation will treat it as though | ||
| 1427 | * it has advanced, and if it is going to become IDLE then | ||
| 1428 | * this doesn't matter anyway. Furthermore it's possible | ||
| 1429 | * for an UNLINKING queue not to have any URBs at all, or | ||
| 1430 | * for its first URB not to have any TDs (if it was dequeued | ||
| 1431 | * just as it completed). So it's not easy in any case to | ||
| 1432 | * test whether such queues have advanced. */ | ||
| 1433 | if (qh->state != QH_STATE_ACTIVE) { | ||
| 1434 | urbp = NULL; | ||
| 1435 | status = 0; | ||
| 1436 | |||
| 1437 | } else { | ||
| 1438 | urbp = list_entry(qh->queue.next, struct urb_priv, node); | ||
| 1439 | td = list_entry(urbp->td_list.next, struct uhci_td, list); | ||
| 1440 | status = td_status(td); | ||
| 1441 | if (!(status & TD_CTRL_ACTIVE)) { | ||
| 1442 | |||
| 1443 | /* We're okay, the queue has advanced */ | ||
| 1444 | qh->wait_expired = 0; | ||
| 1445 | qh->advance_jiffies = jiffies; | ||
| 1446 | goto done; | ||
| 1447 | } | ||
| 1448 | ret = 0; | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | /* The queue hasn't advanced; check for timeout */ | ||
| 1452 | if (qh->wait_expired) | ||
| 1453 | goto done; | ||
| 1454 | |||
| 1455 | if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) { | ||
| 1456 | |||
| 1457 | /* Detect the Intel bug and work around it */ | ||
| 1458 | if (qh->post_td && qh_element(qh) == | ||
| 1459 | cpu_to_le32(qh->post_td->dma_handle)) { | ||
| 1460 | qh->element = qh->post_td->link; | ||
| 1461 | qh->advance_jiffies = jiffies; | ||
| 1462 | ret = 1; | ||
| 1463 | goto done; | ||
| 1464 | } | ||
| 1465 | |||
| 1466 | qh->wait_expired = 1; | ||
| 1467 | |||
| 1468 | /* If the current URB wants FSBR, unlink it temporarily | ||
| 1469 | * so that we can safely set the next TD to interrupt on | ||
| 1470 | * completion. That way we'll know as soon as the queue | ||
| 1471 | * starts moving again. */ | ||
| 1472 | if (urbp && urbp->fsbr && !(status & TD_CTRL_IOC)) | ||
| 1473 | uhci_unlink_qh(uhci, qh); | ||
| 1474 | |||
| 1475 | } else { | ||
| 1476 | /* Unmoving but not-yet-expired queues keep FSBR alive */ | ||
| 1477 | if (urbp) | ||
| 1478 | uhci_urbp_wants_fsbr(uhci, urbp); | ||
| 1347 | } | 1479 | } |
| 1480 | |||
| 1481 | done: | ||
| 1482 | return ret; | ||
| 1348 | } | 1483 | } |
| 1349 | 1484 | ||
| 1350 | /* | 1485 | /* |
| @@ -1361,14 +1496,13 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) | |||
| 1361 | return; | 1496 | return; |
| 1362 | } | 1497 | } |
| 1363 | uhci->scan_in_progress = 1; | 1498 | uhci->scan_in_progress = 1; |
| 1364 | rescan: | 1499 | rescan: |
| 1365 | uhci->need_rescan = 0; | 1500 | uhci->need_rescan = 0; |
| 1501 | uhci->fsbr_is_wanted = 0; | ||
| 1366 | 1502 | ||
| 1367 | uhci_clear_next_interrupt(uhci); | 1503 | uhci_clear_next_interrupt(uhci); |
| 1368 | uhci_get_current_frame_number(uhci); | 1504 | uhci_get_current_frame_number(uhci); |
| 1369 | 1505 | uhci->cur_iso_frame = uhci->frame_number; | |
| 1370 | if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) | ||
| 1371 | uhci_free_pending_tds(uhci); | ||
| 1372 | 1506 | ||
| 1373 | /* Go through all the QH queues and process the URBs in each one */ | 1507 | /* Go through all the QH queues and process the URBs in each one */ |
| 1374 | for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) { | 1508 | for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) { |
| @@ -1377,33 +1511,30 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) | |||
| 1377 | while ((qh = uhci->next_qh) != uhci->skelqh[i]) { | 1511 | while ((qh = uhci->next_qh) != uhci->skelqh[i]) { |
| 1378 | uhci->next_qh = list_entry(qh->node.next, | 1512 | uhci->next_qh = list_entry(qh->node.next, |
| 1379 | struct uhci_qh, node); | 1513 | struct uhci_qh, node); |
| 1380 | uhci_scan_qh(uhci, qh, regs); | 1514 | |
| 1515 | if (uhci_advance_check(uhci, qh)) { | ||
| 1516 | uhci_scan_qh(uhci, qh, regs); | ||
| 1517 | if (qh->state == QH_STATE_ACTIVE) { | ||
| 1518 | uhci_urbp_wants_fsbr(uhci, | ||
| 1519 | list_entry(qh->queue.next, struct urb_priv, node)); | ||
| 1520 | } | ||
| 1521 | } | ||
| 1381 | } | 1522 | } |
| 1382 | } | 1523 | } |
| 1383 | 1524 | ||
| 1525 | uhci->last_iso_frame = uhci->cur_iso_frame; | ||
| 1384 | if (uhci->need_rescan) | 1526 | if (uhci->need_rescan) |
| 1385 | goto rescan; | 1527 | goto rescan; |
| 1386 | uhci->scan_in_progress = 0; | 1528 | uhci->scan_in_progress = 0; |
| 1387 | 1529 | ||
| 1388 | /* If the controller is stopped, we can finish these off right now */ | 1530 | if (uhci->fsbr_is_on && !uhci->fsbr_is_wanted && |
| 1389 | if (uhci->is_stopped) | 1531 | !uhci->fsbr_expiring) { |
| 1390 | uhci_free_pending_tds(uhci); | 1532 | uhci->fsbr_expiring = 1; |
| 1533 | mod_timer(&uhci->fsbr_timer, jiffies + FSBR_OFF_DELAY); | ||
| 1534 | } | ||
| 1391 | 1535 | ||
| 1392 | if (list_empty(&uhci->td_remove_list) && | 1536 | if (list_empty(&uhci->skel_unlink_qh->node)) |
| 1393 | list_empty(&uhci->skel_unlink_qh->node)) | ||
| 1394 | uhci_clear_next_interrupt(uhci); | 1537 | uhci_clear_next_interrupt(uhci); |
| 1395 | else | 1538 | else |
| 1396 | uhci_set_next_interrupt(uhci); | 1539 | uhci_set_next_interrupt(uhci); |
| 1397 | } | 1540 | } |
| 1398 | |||
| 1399 | static void check_fsbr(struct uhci_hcd *uhci) | ||
| 1400 | { | ||
| 1401 | /* For now, don't scan URBs for FSBR timeouts. | ||
| 1402 | * Add it back in later... */ | ||
| 1403 | |||
| 1404 | /* Really disable FSBR */ | ||
| 1405 | if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { | ||
| 1406 | uhci->fsbrtimeout = 0; | ||
| 1407 | uhci->skel_term_qh->link = UHCI_PTR_TERM; | ||
| 1408 | } | ||
| 1409 | } | ||
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c index df29b8078b54..18c10e150ef3 100644 --- a/drivers/usb/input/acecad.c +++ b/drivers/usb/input/acecad.c | |||
| @@ -27,11 +27,9 @@ | |||
| 27 | 27 | ||
| 28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
| 29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
| 30 | #include <linux/input.h> | ||
| 31 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 32 | #include <linux/init.h> | 31 | #include <linux/init.h> |
| 33 | #include <linux/usb.h> | 32 | #include <linux/usb/input.h> |
| 34 | #include <linux/usb_input.h> | ||
| 35 | 33 | ||
| 36 | /* | 34 | /* |
| 37 | * Version Information | 35 | * Version Information |
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index a6693b0d1c4c..b138dae2b055 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c | |||
| @@ -73,11 +73,9 @@ | |||
| 73 | #include <linux/jiffies.h> | 73 | #include <linux/jiffies.h> |
| 74 | #include <linux/kernel.h> | 74 | #include <linux/kernel.h> |
| 75 | #include <linux/slab.h> | 75 | #include <linux/slab.h> |
| 76 | #include <linux/input.h> | ||
| 77 | #include <linux/module.h> | 76 | #include <linux/module.h> |
| 78 | #include <linux/init.h> | 77 | #include <linux/init.h> |
| 79 | #include <linux/usb.h> | 78 | #include <linux/usb/input.h> |
| 80 | #include <linux/usb_input.h> | ||
| 81 | #include <linux/sched.h> | 79 | #include <linux/sched.h> |
| 82 | #include <asm/uaccess.h> | 80 | #include <asm/uaccess.h> |
| 83 | #include <asm/unaligned.h> | 81 | #include <asm/unaligned.h> |
diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c index c222ed13deab..36855062eacc 100644 --- a/drivers/usb/input/appletouch.c +++ b/drivers/usb/input/appletouch.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Apple USB Touchpad (for post-February 2005 PowerBooks) driver | 2 | * Apple USB Touchpad (for post-February 2005 PowerBooks and MacBooks) driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) | 4 | * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) |
| 5 | * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) | 5 | * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) |
| @@ -7,6 +7,7 @@ | |||
| 7 | * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) | 7 | * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) |
| 8 | * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) | 8 | * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) |
| 9 | * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) | 9 | * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) |
| 10 | * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch) | ||
| 10 | * | 11 | * |
| 11 | * Thanks to Alex Harper <basilisk@foobox.net> for his inputs. | 12 | * Thanks to Alex Harper <basilisk@foobox.net> for his inputs. |
| 12 | * | 13 | * |
| @@ -32,9 +33,7 @@ | |||
| 32 | #include <linux/init.h> | 33 | #include <linux/init.h> |
| 33 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
| 34 | #include <linux/module.h> | 35 | #include <linux/module.h> |
| 35 | #include <linux/usb.h> | 36 | #include <linux/usb/input.h> |
| 36 | #include <linux/input.h> | ||
| 37 | #include <linux/usb_input.h> | ||
| 38 | 37 | ||
| 39 | /* Apple has powerbooks which have the keyboard with different Product IDs */ | 38 | /* Apple has powerbooks which have the keyboard with different Product IDs */ |
| 40 | #define APPLE_VENDOR_ID 0x05AC | 39 | #define APPLE_VENDOR_ID 0x05AC |
| @@ -44,6 +43,11 @@ | |||
| 44 | #define GEYSER_ISO_PRODUCT_ID 0x0215 | 43 | #define GEYSER_ISO_PRODUCT_ID 0x0215 |
| 45 | #define GEYSER_JIS_PRODUCT_ID 0x0216 | 44 | #define GEYSER_JIS_PRODUCT_ID 0x0216 |
| 46 | 45 | ||
| 46 | /* MacBook devices */ | ||
| 47 | #define GEYSER3_ANSI_PRODUCT_ID 0x0217 | ||
| 48 | #define GEYSER3_ISO_PRODUCT_ID 0x0218 | ||
| 49 | #define GEYSER3_JIS_PRODUCT_ID 0x0219 | ||
| 50 | |||
| 47 | #define ATP_DEVICE(prod) \ | 51 | #define ATP_DEVICE(prod) \ |
| 48 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ | 52 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ |
| 49 | USB_DEVICE_ID_MATCH_INT_CLASS | \ | 53 | USB_DEVICE_ID_MATCH_INT_CLASS | \ |
| @@ -65,6 +69,10 @@ static struct usb_device_id atp_table [] = { | |||
| 65 | { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) }, | 69 | { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) }, |
| 66 | { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) }, | 70 | { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) }, |
| 67 | 71 | ||
| 72 | { ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) }, | ||
| 73 | { ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) }, | ||
| 74 | { ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) }, | ||
| 75 | |||
| 68 | /* Terminating entry */ | 76 | /* Terminating entry */ |
| 69 | { } | 77 | { } |
| 70 | }; | 78 | }; |
| @@ -101,6 +109,13 @@ MODULE_DEVICE_TABLE (usb, atp_table); | |||
| 101 | */ | 109 | */ |
| 102 | #define ATP_THRESHOLD 5 | 110 | #define ATP_THRESHOLD 5 |
| 103 | 111 | ||
| 112 | /* MacBook Pro (Geyser 3) initialization constants */ | ||
| 113 | #define ATP_GEYSER3_MODE_READ_REQUEST_ID 1 | ||
| 114 | #define ATP_GEYSER3_MODE_WRITE_REQUEST_ID 9 | ||
| 115 | #define ATP_GEYSER3_MODE_REQUEST_VALUE 0x300 | ||
| 116 | #define ATP_GEYSER3_MODE_REQUEST_INDEX 0 | ||
| 117 | #define ATP_GEYSER3_MODE_VENDOR_VALUE 0x04 | ||
| 118 | |||
| 104 | /* Structure to hold all of our device specific stuff */ | 119 | /* Structure to hold all of our device specific stuff */ |
| 105 | struct atp { | 120 | struct atp { |
| 106 | char phys[64]; | 121 | char phys[64]; |
| @@ -147,13 +162,22 @@ MODULE_PARM_DESC(debug, "Activate debugging output"); | |||
| 147 | /* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */ | 162 | /* Checks if the device a Geyser 2 (ANSI, ISO, JIS) */ |
| 148 | static inline int atp_is_geyser_2(struct atp *dev) | 163 | static inline int atp_is_geyser_2(struct atp *dev) |
| 149 | { | 164 | { |
| 150 | int16_t productId = le16_to_cpu(dev->udev->descriptor.idProduct); | 165 | u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); |
| 151 | 166 | ||
| 152 | return (productId == GEYSER_ANSI_PRODUCT_ID) || | 167 | return (productId == GEYSER_ANSI_PRODUCT_ID) || |
| 153 | (productId == GEYSER_ISO_PRODUCT_ID) || | 168 | (productId == GEYSER_ISO_PRODUCT_ID) || |
| 154 | (productId == GEYSER_JIS_PRODUCT_ID); | 169 | (productId == GEYSER_JIS_PRODUCT_ID); |
| 155 | } | 170 | } |
| 156 | 171 | ||
| 172 | static inline int atp_is_geyser_3(struct atp *dev) | ||
| 173 | { | ||
| 174 | u16 productId = le16_to_cpu(dev->udev->descriptor.idProduct); | ||
| 175 | |||
| 176 | return (productId == GEYSER3_ANSI_PRODUCT_ID) || | ||
| 177 | (productId == GEYSER3_ISO_PRODUCT_ID) || | ||
| 178 | (productId == GEYSER3_JIS_PRODUCT_ID); | ||
| 179 | } | ||
| 180 | |||
| 157 | static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, | 181 | static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, |
| 158 | int *z, int *fingers) | 182 | int *z, int *fingers) |
| 159 | { | 183 | { |
| @@ -219,12 +243,33 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) | |||
| 219 | 243 | ||
| 220 | /* drop incomplete datasets */ | 244 | /* drop incomplete datasets */ |
| 221 | if (dev->urb->actual_length != dev->datalen) { | 245 | if (dev->urb->actual_length != dev->datalen) { |
| 222 | dprintk("appletouch: incomplete data package.\n"); | 246 | dprintk("appletouch: incomplete data package" |
| 247 | " (first byte: %d, length: %d).\n", | ||
| 248 | dev->data[0], dev->urb->actual_length); | ||
| 223 | goto exit; | 249 | goto exit; |
| 224 | } | 250 | } |
| 225 | 251 | ||
| 226 | /* reorder the sensors values */ | 252 | /* reorder the sensors values */ |
| 227 | if (atp_is_geyser_2(dev)) { | 253 | if (atp_is_geyser_3(dev)) { |
| 254 | memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); | ||
| 255 | |||
| 256 | /* | ||
| 257 | * The values are laid out like this: | ||
| 258 | * -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ... | ||
| 259 | * '-' is an unused value. | ||
| 260 | */ | ||
| 261 | |||
| 262 | /* read X values */ | ||
| 263 | for (i = 0, j = 19; i < 20; i += 2, j += 3) { | ||
| 264 | dev->xy_cur[i] = dev->data[j + 1]; | ||
| 265 | dev->xy_cur[i + 1] = dev->data[j + 2]; | ||
| 266 | } | ||
| 267 | /* read Y values */ | ||
| 268 | for (i = 0, j = 1; i < 9; i += 2, j += 3) { | ||
| 269 | dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1]; | ||
| 270 | dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2]; | ||
| 271 | } | ||
| 272 | } else if (atp_is_geyser_2(dev)) { | ||
| 228 | memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); | 273 | memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); |
| 229 | 274 | ||
| 230 | /* | 275 | /* |
| @@ -267,6 +312,9 @@ static void atp_complete(struct urb* urb, struct pt_regs* regs) | |||
| 267 | dev->x_old = dev->y_old = -1; | 312 | dev->x_old = dev->y_old = -1; |
| 268 | memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); | 313 | memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); |
| 269 | 314 | ||
| 315 | if (atp_is_geyser_3(dev)) /* No 17" Macbooks (yet) */ | ||
| 316 | goto exit; | ||
| 317 | |||
| 270 | /* 17" Powerbooks have extra X sensors */ | 318 | /* 17" Powerbooks have extra X sensors */ |
| 271 | for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) { | 319 | for (i = (atp_is_geyser_2(dev)?15:16); i < ATP_XSENSORS; i++) { |
| 272 | if (!dev->xy_cur[i]) continue; | 320 | if (!dev->xy_cur[i]) continue; |
| @@ -414,7 +462,50 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id | |||
| 414 | dev->udev = udev; | 462 | dev->udev = udev; |
| 415 | dev->input = input_dev; | 463 | dev->input = input_dev; |
| 416 | dev->overflowwarn = 0; | 464 | dev->overflowwarn = 0; |
| 417 | dev->datalen = (atp_is_geyser_2(dev)?64:81); | 465 | if (atp_is_geyser_3(dev)) |
| 466 | dev->datalen = 64; | ||
| 467 | else if (atp_is_geyser_2(dev)) | ||
| 468 | dev->datalen = 64; | ||
| 469 | else | ||
| 470 | dev->datalen = 81; | ||
| 471 | |||
| 472 | if (atp_is_geyser_3(dev)) { | ||
| 473 | /* | ||
| 474 | * By default Geyser 3 device sends standard USB HID mouse | ||
| 475 | * packets (Report ID 2). This code changes device mode, so it | ||
| 476 | * sends raw sensor reports (Report ID 5). | ||
| 477 | */ | ||
| 478 | char data[8]; | ||
| 479 | int size; | ||
| 480 | |||
| 481 | size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), | ||
| 482 | ATP_GEYSER3_MODE_READ_REQUEST_ID, | ||
| 483 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
| 484 | ATP_GEYSER3_MODE_REQUEST_VALUE, | ||
| 485 | ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000); | ||
| 486 | |||
| 487 | if (size != 8) { | ||
| 488 | err("Could not do mode read request from device" | ||
| 489 | " (Geyser 3 mode)"); | ||
| 490 | goto err_free_devs; | ||
| 491 | } | ||
| 492 | |||
| 493 | /* Apply the mode switch */ | ||
| 494 | data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE; | ||
| 495 | |||
| 496 | size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), | ||
| 497 | ATP_GEYSER3_MODE_WRITE_REQUEST_ID, | ||
| 498 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
| 499 | ATP_GEYSER3_MODE_REQUEST_VALUE, | ||
| 500 | ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000); | ||
| 501 | |||
| 502 | if (size != 8) { | ||
| 503 | err("Could not do mode write request to device" | ||
| 504 | " (Geyser 3 mode)"); | ||
| 505 | goto err_free_devs; | ||
| 506 | } | ||
| 507 | printk("appletouch Geyser 3 inited.\n"); | ||
| 508 | } | ||
| 418 | 509 | ||
| 419 | dev->urb = usb_alloc_urb(0, GFP_KERNEL); | 510 | dev->urb = usb_alloc_urb(0, GFP_KERNEL); |
| 420 | if (!dev->urb) { | 511 | if (!dev->urb) { |
| @@ -447,7 +538,15 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id | |||
| 447 | 538 | ||
| 448 | set_bit(EV_ABS, input_dev->evbit); | 539 | set_bit(EV_ABS, input_dev->evbit); |
| 449 | 540 | ||
| 450 | if (atp_is_geyser_2(dev)) { | 541 | if (atp_is_geyser_3(dev)) { |
| 542 | /* | ||
| 543 | * MacBook have 20 X sensors, 10 Y sensors | ||
| 544 | */ | ||
| 545 | input_set_abs_params(input_dev, ABS_X, 0, | ||
| 546 | ((20 - 1) * ATP_XFACT) - 1, ATP_FUZZ, 0); | ||
| 547 | input_set_abs_params(input_dev, ABS_Y, 0, | ||
| 548 | ((10 - 1) * ATP_YFACT) - 1, ATP_FUZZ, 0); | ||
| 549 | } else if (atp_is_geyser_2(dev)) { | ||
| 451 | /* | 550 | /* |
| 452 | * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected | 551 | * Oct 2005 15" PowerBooks have 15 X sensors, 17" are detected |
| 453 | * later. | 552 | * later. |
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index 99f986cb6e95..07c8c0e665dd 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c | |||
| @@ -92,9 +92,7 @@ | |||
| 92 | #include <linux/slab.h> | 92 | #include <linux/slab.h> |
| 93 | #include <linux/module.h> | 93 | #include <linux/module.h> |
| 94 | #include <linux/moduleparam.h> | 94 | #include <linux/moduleparam.h> |
| 95 | #include <linux/input.h> | 95 | #include <linux/usb/input.h> |
| 96 | #include <linux/usb.h> | ||
| 97 | #include <linux/usb_input.h> | ||
| 98 | #include <linux/wait.h> | 96 | #include <linux/wait.h> |
| 99 | #include <linux/jiffies.h> | 97 | #include <linux/jiffies.h> |
| 100 | 98 | ||
diff --git a/drivers/usb/input/ati_remote2.c b/drivers/usb/input/ati_remote2.c index ab1a1ae24be9..ea71de81ca6b 100644 --- a/drivers/usb/input/ati_remote2.c +++ b/drivers/usb/input/ati_remote2.c | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | * as published by the Free Software Foundation. | 8 | * as published by the Free Software Foundation. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/usb_input.h> | 11 | #include <linux/usb/input.h> |
| 12 | 12 | ||
| 13 | #define DRIVER_DESC "ATI/Philips USB RF remote driver" | 13 | #define DRIVER_DESC "ATI/Philips USB RF remote driver" |
| 14 | #define DRIVER_VERSION "0.1" | 14 | #define DRIVER_VERSION "0.1" |
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 435273e7c85c..b9fb9687f926 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c | |||
| @@ -944,21 +944,28 @@ static void hid_reset(void *_hid) | |||
| 944 | dev_dbg(&hid->intf->dev, "resetting device\n"); | 944 | dev_dbg(&hid->intf->dev, "resetting device\n"); |
| 945 | rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); | 945 | rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); |
| 946 | if (rc_lock >= 0) { | 946 | if (rc_lock >= 0) { |
| 947 | rc = usb_reset_device(hid->dev); | 947 | rc = usb_reset_composite_device(hid->dev, hid->intf); |
| 948 | if (rc_lock) | 948 | if (rc_lock) |
| 949 | usb_unlock_device(hid->dev); | 949 | usb_unlock_device(hid->dev); |
| 950 | } | 950 | } |
| 951 | clear_bit(HID_RESET_PENDING, &hid->iofl); | 951 | clear_bit(HID_RESET_PENDING, &hid->iofl); |
| 952 | 952 | ||
| 953 | if (rc == 0) { | 953 | switch (rc) { |
| 954 | hid->retry_delay = 0; | 954 | case 0: |
| 955 | if (hid_start_in(hid)) | 955 | if (!test_bit(HID_IN_RUNNING, &hid->iofl)) |
| 956 | hid_io_error(hid); | 956 | hid_io_error(hid); |
| 957 | } else if (!(rc == -ENODEV || rc == -EHOSTUNREACH || rc == -EINTR)) | 957 | break; |
| 958 | default: | ||
| 958 | err("can't reset device, %s-%s/input%d, status %d", | 959 | err("can't reset device, %s-%s/input%d, status %d", |
| 959 | hid->dev->bus->bus_name, | 960 | hid->dev->bus->bus_name, |
| 960 | hid->dev->devpath, | 961 | hid->dev->devpath, |
| 961 | hid->ifnum, rc); | 962 | hid->ifnum, rc); |
| 963 | /* FALLTHROUGH */ | ||
| 964 | case -EHOSTUNREACH: | ||
| 965 | case -ENODEV: | ||
| 966 | case -EINTR: | ||
| 967 | break; | ||
| 968 | } | ||
| 962 | } | 969 | } |
| 963 | 970 | ||
| 964 | /* Main I/O error handler */ | 971 | /* Main I/O error handler */ |
| @@ -1374,9 +1381,6 @@ void hid_close(struct hid_device *hid) | |||
| 1374 | 1381 | ||
| 1375 | #define USB_VENDOR_ID_PANJIT 0x134c | 1382 | #define USB_VENDOR_ID_PANJIT 0x134c |
| 1376 | 1383 | ||
| 1377 | #define USB_VENDOR_ID_SILVERCREST 0x062a | ||
| 1378 | #define USB_DEVICE_ID_SILVERCREST_KB 0x0201 | ||
| 1379 | |||
| 1380 | /* | 1384 | /* |
| 1381 | * Initialize all reports | 1385 | * Initialize all reports |
| 1382 | */ | 1386 | */ |
| @@ -1461,9 +1465,6 @@ void hid_init_reports(struct hid_device *hid) | |||
| 1461 | #define USB_VENDOR_ID_ONTRAK 0x0a07 | 1465 | #define USB_VENDOR_ID_ONTRAK 0x0a07 |
| 1462 | #define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 | 1466 | #define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 |
| 1463 | 1467 | ||
| 1464 | #define USB_VENDOR_ID_TANGTOP 0x0d3d | ||
| 1465 | #define USB_DEVICE_ID_TANGTOP_USBPS2 0x0001 | ||
| 1466 | |||
| 1467 | #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f | 1468 | #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f |
| 1468 | #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 | 1469 | #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 |
| 1469 | 1470 | ||
| @@ -1520,12 +1521,6 @@ void hid_init_reports(struct hid_device *hid) | |||
| 1520 | #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 | 1521 | #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 |
| 1521 | #define USB_DEVICE_ID_MCC_PMD1208LS 0x007a | 1522 | #define USB_DEVICE_ID_MCC_PMD1208LS 0x007a |
| 1522 | 1523 | ||
| 1523 | #define USB_VENDOR_ID_CHICONY 0x04f2 | ||
| 1524 | #define USB_DEVICE_ID_CHICONY_USBHUB_KB 0x0100 | ||
| 1525 | |||
| 1526 | #define USB_VENDOR_ID_BTC 0x046e | ||
| 1527 | #define USB_DEVICE_ID_BTC_KEYBOARD 0x5303 | ||
| 1528 | |||
| 1529 | #define USB_VENDOR_ID_VERNIER 0x08f7 | 1524 | #define USB_VENDOR_ID_VERNIER 0x08f7 |
| 1530 | #define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 | 1525 | #define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 |
| 1531 | #define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 | 1526 | #define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 |
| @@ -1549,20 +1544,13 @@ void hid_init_reports(struct hid_device *hid) | |||
| 1549 | #define USB_DEVICE_ID_LD_MACHINETEST 0x2040 | 1544 | #define USB_DEVICE_ID_LD_MACHINETEST 0x2040 |
| 1550 | 1545 | ||
| 1551 | #define USB_VENDOR_ID_APPLE 0x05ac | 1546 | #define USB_VENDOR_ID_APPLE 0x05ac |
| 1552 | #define USB_DEVICE_ID_APPLE_POWERMOUSE 0x0304 | 1547 | #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 |
| 1553 | 1548 | ||
| 1554 | #define USB_VENDOR_ID_CHERRY 0x046a | 1549 | #define USB_VENDOR_ID_CHERRY 0x046a |
| 1555 | #define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 | 1550 | #define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 |
| 1556 | 1551 | ||
| 1557 | #define USB_VENDOR_ID_HP 0x03f0 | 1552 | #define USB_VENDOR_ID_YEALINK 0x6993 |
| 1558 | #define USB_DEVICE_ID_HP_USBHUB_KB 0x020c | 1553 | #define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001 |
| 1559 | |||
| 1560 | #define USB_VENDOR_ID_IBM 0x04b3 | ||
| 1561 | #define USB_DEVICE_ID_IBM_USBHUB_KB 0x3005 | ||
| 1562 | |||
| 1563 | #define USB_VENDOR_ID_CREATIVELABS 0x062a | ||
| 1564 | #define USB_DEVICE_ID_CREATIVELABS_SILVERCREST 0x0201 | ||
| 1565 | |||
| 1566 | /* | 1554 | /* |
| 1567 | * Alphabetically sorted blacklist by quirk type. | 1555 | * Alphabetically sorted blacklist by quirk type. |
| 1568 | */ | 1556 | */ |
| @@ -1671,6 +1659,7 @@ static const struct hid_blacklist { | |||
| 1671 | { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_DTF + 3, HID_QUIRK_IGNORE }, | 1659 | { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_DTF + 3, HID_QUIRK_IGNORE }, |
| 1672 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, | 1660 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, |
| 1673 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, | 1661 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, |
| 1662 | { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE }, | ||
| 1674 | 1663 | ||
| 1675 | { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, | 1664 | { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, |
| 1676 | { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, | 1665 | { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, |
| @@ -1680,16 +1669,9 @@ static const struct hid_blacklist { | |||
| 1680 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, | 1669 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, |
| 1681 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, | 1670 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, |
| 1682 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, | 1671 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, |
| 1683 | { USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_KEYBOARD, HID_QUIRK_NOGET}, | ||
| 1684 | { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_USBHUB_KB, HID_QUIRK_NOGET}, | ||
| 1685 | { USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVELABS_SILVERCREST, HID_QUIRK_NOGET }, | ||
| 1686 | { USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET }, | ||
| 1687 | { USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_USBHUB_KB, HID_QUIRK_NOGET }, | ||
| 1688 | { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, | ||
| 1689 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, | 1672 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, |
| 1690 | { USB_VENDOR_ID_SILVERCREST, USB_DEVICE_ID_SILVERCREST_KB, HID_QUIRK_NOGET }, | ||
| 1691 | 1673 | ||
| 1692 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_POWERMOUSE, HID_QUIRK_2WHEEL_POWERMOUSE }, | 1674 | { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, |
| 1693 | { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, | 1675 | { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, |
| 1694 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, | 1676 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, |
| 1695 | 1677 | ||
| @@ -1711,6 +1693,9 @@ static const struct hid_blacklist { | |||
| 1711 | { USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN }, | 1693 | { USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN }, |
| 1712 | { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN }, | 1694 | { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN }, |
| 1713 | { USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN }, | 1695 | { USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN }, |
| 1696 | { USB_VENDOR_ID_APPLE, 0x0217, HID_QUIRK_POWERBOOK_HAS_FN }, | ||
| 1697 | { USB_VENDOR_ID_APPLE, 0x0218, HID_QUIRK_POWERBOOK_HAS_FN }, | ||
| 1698 | { USB_VENDOR_ID_APPLE, 0x0219, HID_QUIRK_POWERBOOK_HAS_FN }, | ||
| 1714 | { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN }, | 1699 | { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN }, |
| 1715 | { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN }, | 1700 | { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN }, |
| 1716 | 1701 | ||
| @@ -1794,6 +1779,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) | |||
| 1794 | (hid_blacklist[n].idProduct == le16_to_cpu(dev->descriptor.idProduct))) | 1779 | (hid_blacklist[n].idProduct == le16_to_cpu(dev->descriptor.idProduct))) |
| 1795 | quirks = hid_blacklist[n].quirks; | 1780 | quirks = hid_blacklist[n].quirks; |
| 1796 | 1781 | ||
| 1782 | /* Many keyboards and mice don't like to be polled for reports, | ||
| 1783 | * so we will always set the HID_QUIRK_NOGET flag for them. */ | ||
| 1784 | if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) { | ||
| 1785 | if (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_KEYBOARD || | ||
| 1786 | interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE) | ||
| 1787 | quirks |= HID_QUIRK_NOGET; | ||
| 1788 | } | ||
| 1789 | |||
| 1797 | if (quirks & HID_QUIRK_IGNORE) | 1790 | if (quirks & HID_QUIRK_IGNORE) |
| 1798 | return NULL; | 1791 | return NULL; |
| 1799 | 1792 | ||
| @@ -2080,11 +2073,29 @@ static int hid_resume(struct usb_interface *intf) | |||
| 2080 | int status; | 2073 | int status; |
| 2081 | 2074 | ||
| 2082 | clear_bit(HID_SUSPENDED, &hid->iofl); | 2075 | clear_bit(HID_SUSPENDED, &hid->iofl); |
| 2076 | hid->retry_delay = 0; | ||
| 2083 | status = hid_start_in(hid); | 2077 | status = hid_start_in(hid); |
| 2084 | dev_dbg(&intf->dev, "resume status %d\n", status); | 2078 | dev_dbg(&intf->dev, "resume status %d\n", status); |
| 2085 | return status; | 2079 | return status; |
| 2086 | } | 2080 | } |
| 2087 | 2081 | ||
| 2082 | /* Treat USB reset pretty much the same as suspend/resume */ | ||
| 2083 | static void hid_pre_reset(struct usb_interface *intf) | ||
| 2084 | { | ||
| 2085 | /* FIXME: What if the interface is already suspended? */ | ||
| 2086 | hid_suspend(intf, PMSG_ON); | ||
| 2087 | } | ||
| 2088 | |||
| 2089 | static void hid_post_reset(struct usb_interface *intf) | ||
| 2090 | { | ||
| 2091 | struct usb_device *dev = interface_to_usbdev (intf); | ||
| 2092 | |||
| 2093 | hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0); | ||
| 2094 | /* FIXME: Any more reinitialization needed? */ | ||
| 2095 | |||
| 2096 | hid_resume(intf); | ||
| 2097 | } | ||
| 2098 | |||
| 2088 | static struct usb_device_id hid_usb_ids [] = { | 2099 | static struct usb_device_id hid_usb_ids [] = { |
| 2089 | { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, | 2100 | { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, |
| 2090 | .bInterfaceClass = USB_INTERFACE_CLASS_HID }, | 2101 | .bInterfaceClass = USB_INTERFACE_CLASS_HID }, |
| @@ -2099,6 +2110,8 @@ static struct usb_driver hid_driver = { | |||
| 2099 | .disconnect = hid_disconnect, | 2110 | .disconnect = hid_disconnect, |
| 2100 | .suspend = hid_suspend, | 2111 | .suspend = hid_suspend, |
| 2101 | .resume = hid_resume, | 2112 | .resume = hid_resume, |
| 2113 | .pre_reset = hid_pre_reset, | ||
| 2114 | .post_reset = hid_post_reset, | ||
| 2102 | .id_table = hid_usb_ids, | 2115 | .id_table = hid_usb_ids, |
| 2103 | }; | 2116 | }; |
| 2104 | 2117 | ||
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index 25bc85f8ce39..028e1ad89f5d 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c | |||
| @@ -29,9 +29,7 @@ | |||
| 29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
| 30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 31 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
| 32 | #include <linux/input.h> | 32 | #include <linux/usb/input.h> |
| 33 | #include <linux/usb.h> | ||
| 34 | #include <linux/usb_input.h> | ||
| 35 | 33 | ||
| 36 | #undef DEBUG | 34 | #undef DEBUG |
| 37 | 35 | ||
| @@ -567,16 +565,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
| 567 | break; | 565 | break; |
| 568 | } | 566 | } |
| 569 | 567 | ||
| 570 | set_bit(usage->type, input->evbit); | 568 | if (device->quirks & HID_QUIRK_MIGHTYMOUSE) { |
| 571 | 569 | if (usage->hid == HID_GD_Z) | |
| 572 | while (usage->code <= max && test_and_set_bit(usage->code, bit)) | 570 | map_rel(REL_HWHEEL); |
| 573 | usage->code = find_next_zero_bit(bit, max + 1, usage->code); | 571 | else if (usage->code == BTN_1) |
| 574 | 572 | map_key(BTN_2); | |
| 575 | if (usage->code > max) | 573 | else if (usage->code == BTN_2) |
| 576 | goto ignore; | 574 | map_key(BTN_1); |
| 577 | 575 | } | |
| 578 | if (((device->quirks & (HID_QUIRK_2WHEEL_POWERMOUSE)) && (usage->hid == 0x00010032))) | ||
| 579 | map_rel(REL_HWHEEL); | ||
| 580 | 576 | ||
| 581 | if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && | 577 | if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && |
| 582 | (usage->type == EV_REL) && (usage->code == REL_WHEEL)) | 578 | (usage->type == EV_REL) && (usage->code == REL_WHEEL)) |
| @@ -586,6 +582,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
| 586 | || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) | 582 | || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) |
| 587 | goto ignore; | 583 | goto ignore; |
| 588 | 584 | ||
| 585 | set_bit(usage->type, input->evbit); | ||
| 586 | |||
| 587 | while (usage->code <= max && test_and_set_bit(usage->code, bit)) | ||
| 588 | usage->code = find_next_zero_bit(bit, max + 1, usage->code); | ||
| 589 | |||
| 590 | if (usage->code > max) | ||
| 591 | goto ignore; | ||
| 592 | |||
| 593 | |||
| 589 | if (usage->type == EV_ABS) { | 594 | if (usage->type == EV_ABS) { |
| 590 | 595 | ||
| 591 | int a = field->logical_minimum; | 596 | int a = field->logical_minimum; |
| @@ -647,6 +652,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct | |||
| 647 | return; | 652 | return; |
| 648 | } | 653 | } |
| 649 | 654 | ||
| 655 | if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) { | ||
| 656 | input_event(input, usage->type, usage->code, -value); | ||
| 657 | return; | ||
| 658 | } | ||
| 659 | |||
| 650 | if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { | 660 | if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { |
| 651 | input_event(input, usage->type, REL_HWHEEL, value); | 661 | input_event(input, usage->type, REL_HWHEEL, value); |
| 652 | return; | 662 | return; |
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 9c62837b5b89..778e575de352 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h | |||
| @@ -41,6 +41,14 @@ | |||
| 41 | #define USB_INTERFACE_CLASS_HID 3 | 41 | #define USB_INTERFACE_CLASS_HID 3 |
| 42 | 42 | ||
| 43 | /* | 43 | /* |
| 44 | * USB HID interface subclass and protocol codes | ||
| 45 | */ | ||
| 46 | |||
| 47 | #define USB_INTERFACE_SUBCLASS_BOOT 1 | ||
| 48 | #define USB_INTERFACE_PROTOCOL_KEYBOARD 1 | ||
| 49 | #define USB_INTERFACE_PROTOCOL_MOUSE 2 | ||
| 50 | |||
| 51 | /* | ||
| 44 | * HID class requests | 52 | * HID class requests |
| 45 | */ | 53 | */ |
| 46 | 54 | ||
| @@ -247,10 +255,11 @@ struct hid_item { | |||
| 247 | #define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080 | 255 | #define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080 |
| 248 | #define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 | 256 | #define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 |
| 249 | #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 | 257 | #define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 |
| 250 | #define HID_QUIRK_2WHEEL_POWERMOUSE 0x00000400 | 258 | #define HID_QUIRK_MIGHTYMOUSE 0x00000400 |
| 251 | #define HID_QUIRK_CYMOTION 0x00000800 | 259 | #define HID_QUIRK_CYMOTION 0x00000800 |
| 252 | #define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000 | 260 | #define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000 |
| 253 | #define HID_QUIRK_POWERBOOK_FN_ON 0x00002000 | 261 | #define HID_QUIRK_POWERBOOK_FN_ON 0x00002000 |
| 262 | #define HID_QUIRK_INVERT_HWHEEL 0x00004000 | ||
| 254 | 263 | ||
| 255 | /* | 264 | /* |
| 256 | * This is the global environment of the parser. This information is | 265 | * This is the global environment of the parser. This information is |
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c index 7618ae5c104f..5c570cc703f3 100644 --- a/drivers/usb/input/itmtouch.c +++ b/drivers/usb/input/itmtouch.c | |||
| @@ -42,11 +42,9 @@ | |||
| 42 | #include <linux/config.h> | 42 | #include <linux/config.h> |
| 43 | #include <linux/kernel.h> | 43 | #include <linux/kernel.h> |
| 44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
| 45 | #include <linux/input.h> | ||
| 46 | #include <linux/module.h> | 45 | #include <linux/module.h> |
| 47 | #include <linux/init.h> | 46 | #include <linux/init.h> |
| 48 | #include <linux/usb.h> | 47 | #include <linux/usb/input.h> |
| 49 | #include <linux/usb_input.h> | ||
| 50 | 48 | ||
| 51 | /* only an 8 byte buffer necessary for a single packet */ | 49 | /* only an 8 byte buffer necessary for a single packet */ |
| 52 | #define ITM_BUFSIZE 8 | 50 | #define ITM_BUFSIZE 8 |
diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c index f6d5cead542b..604ade356ead 100644 --- a/drivers/usb/input/kbtab.c +++ b/drivers/usb/input/kbtab.c | |||
| @@ -1,12 +1,9 @@ | |||
| 1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
| 2 | #include <linux/slab.h> | 2 | #include <linux/slab.h> |
| 3 | #include <linux/input.h> | ||
| 4 | #include <linux/module.h> | 3 | #include <linux/module.h> |
| 5 | #include <linux/init.h> | 4 | #include <linux/init.h> |
| 6 | #include <linux/usb.h> | 5 | #include <linux/usb/input.h> |
| 7 | #include <linux/usb_input.h> | ||
| 8 | #include <asm/unaligned.h> | 6 | #include <asm/unaligned.h> |
| 9 | #include <asm/byteorder.h> | ||
| 10 | 7 | ||
| 11 | /* | 8 | /* |
| 12 | * Version Information | 9 | * Version Information |
diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c index 3d911976f378..70af985b5db9 100644 --- a/drivers/usb/input/keyspan_remote.c +++ b/drivers/usb/input/keyspan_remote.c | |||
| @@ -18,9 +18,7 @@ | |||
| 18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/moduleparam.h> | 20 | #include <linux/moduleparam.h> |
| 21 | #include <linux/input.h> | 21 | #include <linux/usb/input.h> |
| 22 | #include <linux/usb.h> | ||
| 23 | #include <linux/usb_input.h> | ||
| 24 | 22 | ||
| 25 | #define DRIVER_VERSION "v0.1" | 23 | #define DRIVER_VERSION "v0.1" |
| 26 | #define DRIVER_AUTHOR "Michael Downey <downey@zymeta.com>" | 24 | #define DRIVER_AUTHOR "Michael Downey <downey@zymeta.com>" |
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index f018953a5485..4fdee4db0729 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c | |||
| @@ -42,11 +42,9 @@ | |||
| 42 | #include <linux/config.h> | 42 | #include <linux/config.h> |
| 43 | #include <linux/kernel.h> | 43 | #include <linux/kernel.h> |
| 44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
| 45 | #include <linux/input.h> | ||
| 46 | #include <linux/module.h> | 45 | #include <linux/module.h> |
| 47 | #include <linux/init.h> | 46 | #include <linux/init.h> |
| 48 | #include <linux/usb.h> | 47 | #include <linux/usb/input.h> |
| 49 | #include <linux/usb_input.h> | ||
| 50 | 48 | ||
| 51 | #define MTOUCHUSB_MIN_XC 0x0 | 49 | #define MTOUCHUSB_MIN_XC 0x0 |
| 52 | #define MTOUCHUSB_MAX_RAW_XC 0x4000 | 50 | #define MTOUCHUSB_MAX_RAW_XC 0x4000 |
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index fdf0f788062c..b3c0d0c3eae9 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c | |||
| @@ -30,12 +30,10 @@ | |||
| 30 | 30 | ||
| 31 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
| 32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
| 33 | #include <linux/input.h> | ||
| 34 | #include <linux/module.h> | 33 | #include <linux/module.h> |
| 35 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| 36 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
| 37 | #include <linux/usb.h> | 36 | #include <linux/usb/input.h> |
| 38 | #include <linux/usb_input.h> | ||
| 39 | 37 | ||
| 40 | #define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ | 38 | #define POWERMATE_VENDOR 0x077d /* Griffin Technology, Inc. */ |
| 41 | #define POWERMATE_PRODUCT_NEW 0x0410 /* Griffin PowerMate */ | 39 | #define POWERMATE_PRODUCT_NEW 0x0410 /* Griffin PowerMate */ |
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index 697c5e573a11..da7b0bf51aff 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c | |||
| @@ -27,11 +27,9 @@ | |||
| 27 | #include <linux/config.h> | 27 | #include <linux/config.h> |
| 28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
| 29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
| 30 | #include <linux/input.h> | ||
| 31 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 32 | #include <linux/init.h> | 31 | #include <linux/init.h> |
| 33 | #include <linux/usb.h> | 32 | #include <linux/usb/input.h> |
| 34 | #include <linux/usb_input.h> | ||
| 35 | 33 | ||
| 36 | #define TOUCHKIT_MIN_XC 0x0 | 34 | #define TOUCHKIT_MIN_XC 0x0 |
| 37 | #define TOUCHKIT_MAX_XC 0x07ff | 35 | #define TOUCHKIT_MAX_XC 0x07ff |
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index 2f3edc26cb50..5067a6ae650f 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c | |||
| @@ -29,10 +29,8 @@ | |||
| 29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
| 30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 32 | #include <linux/input.h> | ||
| 33 | #include <linux/init.h> | 32 | #include <linux/init.h> |
| 34 | #include <linux/usb.h> | 33 | #include <linux/usb/input.h> |
| 35 | #include <linux/usb_input.h> | ||
| 36 | 34 | ||
| 37 | /* | 35 | /* |
| 38 | * Version Information | 36 | * Version Information |
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index af526135d210..446935b671d9 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c | |||
| @@ -28,11 +28,9 @@ | |||
| 28 | 28 | ||
| 29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
| 30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 31 | #include <linux/input.h> | ||
| 32 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 33 | #include <linux/init.h> | 32 | #include <linux/init.h> |
| 34 | #include <linux/usb.h> | 33 | #include <linux/usb/input.h> |
| 35 | #include <linux/usb_input.h> | ||
| 36 | 34 | ||
| 37 | /* | 35 | /* |
| 38 | * Version Information | 36 | * Version Information |
diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index e9a07c1e905b..3b175aa482cd 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c | |||
| @@ -39,7 +39,7 @@ | |||
| 39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
| 40 | #include <linux/init.h> | 40 | #include <linux/init.h> |
| 41 | #include <linux/usb.h> | 41 | #include <linux/usb.h> |
| 42 | #include <linux/usb_input.h> | 42 | #include <linux/usb/input.h> |
| 43 | 43 | ||
| 44 | 44 | ||
| 45 | #define DRIVER_VERSION "v0.3" | 45 | #define DRIVER_VERSION "v0.3" |
diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index cf84c6096f29..369461a70b72 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c | |||
| @@ -69,13 +69,10 @@ | |||
| 69 | 69 | ||
| 70 | #include <linux/kernel.h> | 70 | #include <linux/kernel.h> |
| 71 | #include <linux/slab.h> | 71 | #include <linux/slab.h> |
| 72 | #include <linux/input.h> | ||
| 73 | #include <linux/module.h> | 72 | #include <linux/module.h> |
| 74 | #include <linux/init.h> | 73 | #include <linux/init.h> |
| 75 | #include <linux/usb.h> | 74 | #include <linux/usb/input.h> |
| 76 | #include <linux/usb_input.h> | ||
| 77 | #include <asm/unaligned.h> | 75 | #include <asm/unaligned.h> |
| 78 | #include <asm/byteorder.h> | ||
| 79 | 76 | ||
| 80 | /* | 77 | /* |
| 81 | * Version Information | 78 | * Version Information |
diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index e278489a80c6..cfd4a4e04334 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c | |||
| @@ -56,13 +56,11 @@ | |||
| 56 | 56 | ||
| 57 | #include <linux/config.h> | 57 | #include <linux/config.h> |
| 58 | #include <linux/kernel.h> | 58 | #include <linux/kernel.h> |
| 59 | #include <linux/input.h> | ||
| 60 | #include <linux/init.h> | 59 | #include <linux/init.h> |
| 61 | #include <linux/slab.h> | 60 | #include <linux/slab.h> |
| 62 | #include <linux/module.h> | 61 | #include <linux/module.h> |
| 63 | #include <linux/smp_lock.h> | 62 | #include <linux/smp_lock.h> |
| 64 | #include <linux/usb.h> | 63 | #include <linux/usb/input.h> |
| 65 | #include <linux/usb_input.h> | ||
| 66 | 64 | ||
| 67 | #define DRIVER_VERSION "v0.0.5" | 65 | #define DRIVER_VERSION "v0.0.5" |
| 68 | #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" | 66 | #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" |
diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c index 37d2f0ba0319..24aedbb20f03 100644 --- a/drivers/usb/input/yealink.c +++ b/drivers/usb/input/yealink.c | |||
| @@ -48,13 +48,11 @@ | |||
| 48 | 48 | ||
| 49 | #include <linux/config.h> | 49 | #include <linux/config.h> |
| 50 | #include <linux/kernel.h> | 50 | #include <linux/kernel.h> |
| 51 | #include <linux/input.h> | ||
| 52 | #include <linux/init.h> | 51 | #include <linux/init.h> |
| 53 | #include <linux/slab.h> | 52 | #include <linux/slab.h> |
| 54 | #include <linux/module.h> | 53 | #include <linux/module.h> |
| 55 | #include <linux/rwsem.h> | 54 | #include <linux/rwsem.h> |
| 56 | #include <linux/usb.h> | 55 | #include <linux/usb/input.h> |
| 57 | #include <linux/usb_input.h> | ||
| 58 | 56 | ||
| 59 | #include "map_to_7segment.h" | 57 | #include "map_to_7segment.h" |
| 60 | #include "yealink.h" | 58 | #include "yealink.h" |
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 8ba6a701e9c1..daa486dde8cf 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig | |||
| @@ -88,6 +88,20 @@ config USB_LED | |||
| 88 | To compile this driver as a module, choose M here: the | 88 | To compile this driver as a module, choose M here: the |
| 89 | module will be called usbled. | 89 | module will be called usbled. |
| 90 | 90 | ||
| 91 | config USB_CY7C63 | ||
| 92 | tristate "Cypress CY7C63xxx USB driver support" | ||
| 93 | depends on USB | ||
| 94 | help | ||
| 95 | Say Y here if you want to connect a Cypress CY7C63xxx | ||
| 96 | micro controller to your computer's USB port. This driver | ||
| 97 | supports the pre-programmed devices (incl. firmware) by | ||
| 98 | AK Modul-Bus Computer GmbH. | ||
| 99 | |||
| 100 | Please see: http://www.ak-modul-bus.de/stat/mikrocontroller.html | ||
| 101 | |||
| 102 | To compile this driver as a module, choose M here: the | ||
| 103 | module will be called cy7c63. | ||
| 104 | |||
| 91 | config USB_CYTHERM | 105 | config USB_CYTHERM |
| 92 | tristate "Cypress USB thermometer driver support" | 106 | tristate "Cypress USB thermometer driver support" |
| 93 | depends on USB | 107 | depends on USB |
| @@ -137,6 +151,15 @@ config USB_IDMOUSE | |||
| 137 | 151 | ||
| 138 | See also <http://www.fs.tum.de/~echtler/idmouse/>. | 152 | See also <http://www.fs.tum.de/~echtler/idmouse/>. |
| 139 | 153 | ||
| 154 | config USB_APPLEDISPLAY | ||
| 155 | tristate "Apple Cinema Display support" | ||
| 156 | depends on USB | ||
| 157 | select BACKLIGHT_LCD_SUPPORT | ||
| 158 | select BACKLIGHT_CLASS_DEVICE | ||
| 159 | help | ||
| 160 | Say Y here if you want to control the backlight of Apple Cinema | ||
| 161 | Displays over USB. This driver provides a sysfs interface. | ||
| 162 | |||
| 140 | source "drivers/usb/misc/sisusbvga/Kconfig" | 163 | source "drivers/usb/misc/sisusbvga/Kconfig" |
| 141 | 164 | ||
| 142 | config USB_LD | 165 | config USB_LD |
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 6c693bc68e2e..f25a97227297 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | obj-$(CONFIG_USB_AUERSWALD) += auerswald.o | 6 | obj-$(CONFIG_USB_AUERSWALD) += auerswald.o |
| 7 | obj-$(CONFIG_USB_CY7C63) += cy7c63.o | ||
| 7 | obj-$(CONFIG_USB_CYTHERM) += cytherm.o | 8 | obj-$(CONFIG_USB_CYTHERM) += cytherm.o |
| 8 | obj-$(CONFIG_USB_EMI26) += emi26.o | 9 | obj-$(CONFIG_USB_EMI26) += emi26.o |
| 9 | obj-$(CONFIG_USB_EMI62) += emi62.o | 10 | obj-$(CONFIG_USB_EMI62) += emi62.o |
| @@ -17,6 +18,7 @@ obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o | |||
| 17 | obj-$(CONFIG_USB_RIO500) += rio500.o | 18 | obj-$(CONFIG_USB_RIO500) += rio500.o |
| 18 | obj-$(CONFIG_USB_TEST) += usbtest.o | 19 | obj-$(CONFIG_USB_TEST) += usbtest.o |
| 19 | obj-$(CONFIG_USB_USS720) += uss720.o | 20 | obj-$(CONFIG_USB_USS720) += uss720.o |
| 21 | obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o | ||
| 20 | 22 | ||
| 21 | obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ | 23 | obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ |
| 22 | 24 | ||
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c new file mode 100644 index 000000000000..bfde82f5d180 --- /dev/null +++ b/drivers/usb/misc/appledisplay.c | |||
| @@ -0,0 +1,383 @@ | |||
| 1 | /* | ||
| 2 | * Apple Cinema Display driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch) | ||
| 5 | * | ||
| 6 | * Thanks to Caskey L. Dickson for his work with acdctl. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/config.h> | ||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/errno.h> | ||
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/usb.h> | ||
| 29 | #include <linux/backlight.h> | ||
| 30 | #include <linux/timer.h> | ||
| 31 | #include <linux/workqueue.h> | ||
| 32 | #include <asm/atomic.h> | ||
| 33 | #include <asm/semaphore.h> | ||
| 34 | |||
| 35 | #define APPLE_VENDOR_ID 0x05AC | ||
| 36 | |||
| 37 | #define USB_REQ_GET_REPORT 0x01 | ||
| 38 | #define USB_REQ_SET_REPORT 0x09 | ||
| 39 | |||
| 40 | #define ACD_USB_TIMEOUT 250 | ||
| 41 | |||
| 42 | #define ACD_USB_EDID 0x0302 | ||
| 43 | #define ACD_USB_BRIGHTNESS 0x0310 | ||
| 44 | |||
| 45 | #define ACD_BTN_NONE 0 | ||
| 46 | #define ACD_BTN_BRIGHT_UP 3 | ||
| 47 | #define ACD_BTN_BRIGHT_DOWN 4 | ||
| 48 | |||
| 49 | #define ACD_URB_BUFFER_LEN 2 | ||
| 50 | #define ACD_MSG_BUFFER_LEN 2 | ||
| 51 | |||
| 52 | #define APPLEDISPLAY_DEVICE(prod) \ | ||
| 53 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ | ||
| 54 | USB_DEVICE_ID_MATCH_INT_CLASS | \ | ||
| 55 | USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ | ||
| 56 | .idVendor = APPLE_VENDOR_ID, \ | ||
| 57 | .idProduct = (prod), \ | ||
| 58 | .bInterfaceClass = USB_CLASS_HID, \ | ||
| 59 | .bInterfaceProtocol = 0x00 | ||
| 60 | |||
| 61 | /* table of devices that work with this driver */ | ||
| 62 | static struct usb_device_id appledisplay_table [] = { | ||
| 63 | { APPLEDISPLAY_DEVICE(0x9218) }, | ||
| 64 | { APPLEDISPLAY_DEVICE(0x9219) }, | ||
| 65 | { APPLEDISPLAY_DEVICE(0x921d) }, | ||
| 66 | |||
| 67 | /* Terminating entry */ | ||
| 68 | { } | ||
| 69 | }; | ||
| 70 | MODULE_DEVICE_TABLE(usb, appledisplay_table); | ||
| 71 | |||
| 72 | /* Structure to hold all of our device specific stuff */ | ||
| 73 | struct appledisplay { | ||
| 74 | struct usb_device *udev; /* usb device */ | ||
| 75 | struct urb *urb; /* usb request block */ | ||
| 76 | struct backlight_device *bd; /* backlight device */ | ||
| 77 | char *urbdata; /* interrupt URB data buffer */ | ||
| 78 | char *msgdata; /* control message data buffer */ | ||
| 79 | |||
| 80 | struct work_struct work; | ||
| 81 | int button_pressed; | ||
| 82 | spinlock_t lock; | ||
| 83 | }; | ||
| 84 | |||
| 85 | static atomic_t count_displays = ATOMIC_INIT(0); | ||
| 86 | static struct workqueue_struct *wq; | ||
| 87 | |||
| 88 | static void appledisplay_complete(struct urb *urb, struct pt_regs *regs) | ||
| 89 | { | ||
| 90 | struct appledisplay *pdata = urb->context; | ||
| 91 | unsigned long flags; | ||
| 92 | int retval; | ||
| 93 | |||
| 94 | switch (urb->status) { | ||
| 95 | case 0: | ||
| 96 | /* success */ | ||
| 97 | break; | ||
| 98 | case -EOVERFLOW: | ||
| 99 | printk(KERN_ERR "appletouch: OVERFLOW with data " | ||
| 100 | "length %d, actual length is %d\n", | ||
| 101 | ACD_URB_BUFFER_LEN, pdata->urb->actual_length); | ||
| 102 | case -ECONNRESET: | ||
| 103 | case -ENOENT: | ||
| 104 | case -ESHUTDOWN: | ||
| 105 | /* This urb is terminated, clean up */ | ||
| 106 | dbg("%s - urb shutting down with status: %d", | ||
| 107 | __FUNCTION__, urb->status); | ||
| 108 | return; | ||
| 109 | default: | ||
| 110 | dbg("%s - nonzero urb status received: %d", | ||
| 111 | __FUNCTION__, urb->status); | ||
| 112 | goto exit; | ||
| 113 | } | ||
| 114 | |||
| 115 | spin_lock_irqsave(&pdata->lock, flags); | ||
| 116 | |||
| 117 | switch(pdata->urbdata[1]) { | ||
| 118 | case ACD_BTN_BRIGHT_UP: | ||
| 119 | case ACD_BTN_BRIGHT_DOWN: | ||
| 120 | pdata->button_pressed = 1; | ||
| 121 | queue_work(wq, &pdata->work); | ||
| 122 | break; | ||
| 123 | case ACD_BTN_NONE: | ||
| 124 | default: | ||
| 125 | pdata->button_pressed = 0; | ||
| 126 | break; | ||
| 127 | } | ||
| 128 | |||
| 129 | spin_unlock_irqrestore(&pdata->lock, flags); | ||
| 130 | |||
| 131 | exit: | ||
| 132 | retval = usb_submit_urb(pdata->urb, GFP_ATOMIC); | ||
| 133 | if (retval) { | ||
| 134 | err("%s - usb_submit_urb failed with result %d", | ||
| 135 | __FUNCTION__, retval); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | static int appledisplay_bl_update_status(struct backlight_device *bd) | ||
| 140 | { | ||
| 141 | struct appledisplay *pdata = class_get_devdata(&bd->class_dev); | ||
| 142 | int retval; | ||
| 143 | |||
| 144 | pdata->msgdata[0] = 0x10; | ||
| 145 | pdata->msgdata[1] = bd->props->brightness; | ||
| 146 | |||
| 147 | retval = usb_control_msg( | ||
| 148 | pdata->udev, | ||
| 149 | usb_sndctrlpipe(pdata->udev, 0), | ||
| 150 | USB_REQ_SET_REPORT, | ||
| 151 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
| 152 | ACD_USB_BRIGHTNESS, | ||
| 153 | 0, | ||
| 154 | pdata->msgdata, 2, | ||
| 155 | ACD_USB_TIMEOUT); | ||
| 156 | |||
| 157 | return retval; | ||
| 158 | } | ||
| 159 | |||
| 160 | static int appledisplay_bl_get_brightness(struct backlight_device *bd) | ||
| 161 | { | ||
| 162 | struct appledisplay *pdata = class_get_devdata(&bd->class_dev); | ||
| 163 | int retval; | ||
| 164 | |||
| 165 | retval = usb_control_msg( | ||
| 166 | pdata->udev, | ||
| 167 | usb_rcvctrlpipe(pdata->udev, 0), | ||
| 168 | USB_REQ_GET_REPORT, | ||
| 169 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
| 170 | ACD_USB_BRIGHTNESS, | ||
| 171 | 0, | ||
| 172 | pdata->msgdata, 2, | ||
| 173 | ACD_USB_TIMEOUT); | ||
| 174 | |||
| 175 | if (retval < 0) | ||
| 176 | return retval; | ||
| 177 | else | ||
| 178 | return pdata->msgdata[1]; | ||
| 179 | } | ||
| 180 | |||
| 181 | static struct backlight_properties appledisplay_bl_data = { | ||
| 182 | .owner = THIS_MODULE, | ||
| 183 | .get_brightness = appledisplay_bl_get_brightness, | ||
| 184 | .update_status = appledisplay_bl_update_status, | ||
| 185 | .max_brightness = 0xFF | ||
| 186 | }; | ||
| 187 | |||
| 188 | static void appledisplay_work(void *private) | ||
| 189 | { | ||
| 190 | struct appledisplay *pdata = private; | ||
| 191 | int retval; | ||
| 192 | |||
| 193 | up(&pdata->bd->sem); | ||
| 194 | retval = appledisplay_bl_get_brightness(pdata->bd); | ||
| 195 | if (retval >= 0) | ||
| 196 | pdata->bd->props->brightness = retval; | ||
| 197 | down(&pdata->bd->sem); | ||
| 198 | |||
| 199 | /* Poll again in about 125ms if there's still a button pressed */ | ||
| 200 | if (pdata->button_pressed) | ||
| 201 | schedule_delayed_work(&pdata->work, HZ / 8); | ||
| 202 | } | ||
| 203 | |||
| 204 | static int appledisplay_probe(struct usb_interface *iface, | ||
| 205 | const struct usb_device_id *id) | ||
| 206 | { | ||
| 207 | struct appledisplay *pdata; | ||
| 208 | struct usb_device *udev = interface_to_usbdev(iface); | ||
| 209 | struct usb_host_interface *iface_desc; | ||
| 210 | struct usb_endpoint_descriptor *endpoint; | ||
| 211 | int int_in_endpointAddr = 0; | ||
| 212 | int i, retval = -ENOMEM, brightness; | ||
| 213 | char bl_name[20]; | ||
| 214 | |||
| 215 | /* set up the endpoint information */ | ||
| 216 | /* use only the first interrupt-in endpoint */ | ||
| 217 | iface_desc = iface->cur_altsetting; | ||
| 218 | for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { | ||
| 219 | endpoint = &iface_desc->endpoint[i].desc; | ||
| 220 | if (!int_in_endpointAddr && | ||
| 221 | (endpoint->bEndpointAddress & USB_DIR_IN) && | ||
| 222 | ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | ||
| 223 | USB_ENDPOINT_XFER_INT)) { | ||
| 224 | /* we found an interrupt in endpoint */ | ||
| 225 | int_in_endpointAddr = endpoint->bEndpointAddress; | ||
| 226 | break; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | if (!int_in_endpointAddr) { | ||
| 230 | err("Could not find int-in endpoint"); | ||
| 231 | return -EIO; | ||
| 232 | } | ||
| 233 | |||
| 234 | /* allocate memory for our device state and initialize it */ | ||
| 235 | pdata = kzalloc(sizeof(struct appledisplay), GFP_KERNEL); | ||
| 236 | if (!pdata) { | ||
| 237 | retval = -ENOMEM; | ||
| 238 | err("Out of memory"); | ||
| 239 | goto error; | ||
| 240 | } | ||
| 241 | |||
| 242 | pdata->udev = udev; | ||
| 243 | |||
| 244 | spin_lock_init(&pdata->lock); | ||
| 245 | INIT_WORK(&pdata->work, appledisplay_work, pdata); | ||
| 246 | |||
| 247 | /* Allocate buffer for control messages */ | ||
| 248 | pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL); | ||
| 249 | if (!pdata->msgdata) { | ||
| 250 | retval = -ENOMEM; | ||
| 251 | err("appledisplay: Allocating buffer for control messages " | ||
| 252 | "failed"); | ||
| 253 | goto error; | ||
| 254 | } | ||
| 255 | |||
| 256 | /* Allocate interrupt URB */ | ||
| 257 | pdata->urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 258 | if (!pdata->urb) { | ||
| 259 | retval = -ENOMEM; | ||
| 260 | err("appledisplay: Allocating URB failed"); | ||
| 261 | goto error; | ||
| 262 | } | ||
| 263 | |||
| 264 | /* Allocate buffer for interrupt data */ | ||
| 265 | pdata->urbdata = usb_buffer_alloc(pdata->udev, ACD_URB_BUFFER_LEN, | ||
| 266 | GFP_KERNEL, &pdata->urb->transfer_dma); | ||
| 267 | if (!pdata->urbdata) { | ||
| 268 | retval = -ENOMEM; | ||
| 269 | err("appledisplay: Allocating URB buffer failed"); | ||
| 270 | goto error; | ||
| 271 | } | ||
| 272 | |||
| 273 | /* Configure interrupt URB */ | ||
| 274 | usb_fill_int_urb(pdata->urb, udev, | ||
| 275 | usb_rcvintpipe(udev, int_in_endpointAddr), | ||
| 276 | pdata->urbdata, ACD_URB_BUFFER_LEN, appledisplay_complete, | ||
| 277 | pdata, 1); | ||
| 278 | if (usb_submit_urb(pdata->urb, GFP_KERNEL)) { | ||
| 279 | retval = -EIO; | ||
| 280 | err("appledisplay: Submitting URB failed"); | ||
| 281 | goto error; | ||
| 282 | } | ||
| 283 | |||
| 284 | /* Register backlight device */ | ||
| 285 | snprintf(bl_name, sizeof(bl_name), "appledisplay%d", | ||
| 286 | atomic_inc_return(&count_displays) - 1); | ||
| 287 | pdata->bd = backlight_device_register(bl_name, pdata, | ||
| 288 | &appledisplay_bl_data); | ||
| 289 | if (IS_ERR(pdata->bd)) { | ||
| 290 | err("appledisplay: Backlight registration failed"); | ||
| 291 | goto error; | ||
| 292 | } | ||
| 293 | |||
| 294 | /* Try to get brightness */ | ||
| 295 | up(&pdata->bd->sem); | ||
| 296 | brightness = appledisplay_bl_get_brightness(pdata->bd); | ||
| 297 | down(&pdata->bd->sem); | ||
| 298 | |||
| 299 | if (brightness < 0) { | ||
| 300 | retval = brightness; | ||
| 301 | err("appledisplay: Error while getting initial brightness: %d", retval); | ||
| 302 | goto error; | ||
| 303 | } | ||
| 304 | |||
| 305 | /* Set brightness in backlight device */ | ||
| 306 | up(&pdata->bd->sem); | ||
| 307 | pdata->bd->props->brightness = brightness; | ||
| 308 | down(&pdata->bd->sem); | ||
| 309 | |||
| 310 | /* save our data pointer in the interface device */ | ||
| 311 | usb_set_intfdata(iface, pdata); | ||
| 312 | |||
| 313 | printk(KERN_INFO "appledisplay: Apple Cinema Display connected\n"); | ||
| 314 | |||
| 315 | return 0; | ||
| 316 | |||
| 317 | error: | ||
| 318 | if (pdata) { | ||
| 319 | if (pdata->urb) { | ||
| 320 | usb_kill_urb(pdata->urb); | ||
| 321 | if (pdata->urbdata) | ||
| 322 | usb_buffer_free(pdata->udev, ACD_URB_BUFFER_LEN, | ||
| 323 | pdata->urbdata, pdata->urb->transfer_dma); | ||
| 324 | usb_free_urb(pdata->urb); | ||
| 325 | } | ||
| 326 | if (pdata->bd) | ||
| 327 | backlight_device_unregister(pdata->bd); | ||
| 328 | kfree(pdata->msgdata); | ||
| 329 | } | ||
| 330 | usb_set_intfdata(iface, NULL); | ||
| 331 | kfree(pdata); | ||
| 332 | return retval; | ||
| 333 | } | ||
| 334 | |||
| 335 | static void appledisplay_disconnect(struct usb_interface *iface) | ||
| 336 | { | ||
| 337 | struct appledisplay *pdata = usb_get_intfdata(iface); | ||
| 338 | |||
| 339 | if (pdata) { | ||
| 340 | usb_kill_urb(pdata->urb); | ||
| 341 | cancel_delayed_work(&pdata->work); | ||
| 342 | backlight_device_unregister(pdata->bd); | ||
| 343 | usb_buffer_free(pdata->udev, ACD_URB_BUFFER_LEN, | ||
| 344 | pdata->urbdata, pdata->urb->transfer_dma); | ||
| 345 | usb_free_urb(pdata->urb); | ||
| 346 | kfree(pdata->msgdata); | ||
| 347 | kfree(pdata); | ||
| 348 | } | ||
| 349 | |||
| 350 | printk(KERN_INFO "appledisplay: Apple Cinema Display disconnected\n"); | ||
| 351 | } | ||
| 352 | |||
| 353 | static struct usb_driver appledisplay_driver = { | ||
| 354 | .name = "appledisplay", | ||
| 355 | .probe = appledisplay_probe, | ||
| 356 | .disconnect = appledisplay_disconnect, | ||
| 357 | .id_table = appledisplay_table, | ||
| 358 | }; | ||
| 359 | |||
| 360 | static int __init appledisplay_init(void) | ||
| 361 | { | ||
| 362 | wq = create_singlethread_workqueue("appledisplay"); | ||
| 363 | if (!wq) { | ||
| 364 | err("Could not create work queue\n"); | ||
| 365 | return -ENOMEM; | ||
| 366 | } | ||
| 367 | |||
| 368 | return usb_register(&appledisplay_driver); | ||
| 369 | } | ||
| 370 | |||
| 371 | static void __exit appledisplay_exit(void) | ||
| 372 | { | ||
| 373 | flush_workqueue(wq); | ||
| 374 | destroy_workqueue(wq); | ||
| 375 | usb_deregister(&appledisplay_driver); | ||
| 376 | } | ||
| 377 | |||
| 378 | MODULE_AUTHOR("Michael Hanselmann"); | ||
| 379 | MODULE_DESCRIPTION("Apple Cinema Display driver"); | ||
| 380 | MODULE_LICENSE("GPL"); | ||
| 381 | |||
| 382 | module_init(appledisplay_init); | ||
| 383 | module_exit(appledisplay_exit); | ||
diff --git a/drivers/usb/misc/cy7c63.c b/drivers/usb/misc/cy7c63.c new file mode 100644 index 000000000000..8a1c10b89b76 --- /dev/null +++ b/drivers/usb/misc/cy7c63.c | |||
| @@ -0,0 +1,244 @@ | |||
| 1 | /* | ||
| 2 | * cy7c63.c | ||
| 3 | * | ||
| 4 | * Copyright (c) 2006 Oliver Bock (bock@fh-wolfenbuettel.de) | ||
| 5 | * | ||
| 6 | * This driver is based on the Cypress Thermometer USB Driver by | ||
| 7 | * Marcus Maul and the 2.0 version of Greg Kroah-Hartman's | ||
| 8 | * USB Skeleton driver. | ||
| 9 | * | ||
| 10 | * Is is a generic driver for the Cypress CY7C63000 family. | ||
| 11 | * For the time being it enables you to toggle the single I/O ports | ||
| 12 | * of the device. | ||
| 13 | * | ||
| 14 | * Supported vendors: AK Modul-Bus Computer GmbH | ||
| 15 | * Supported devices: CY7C63001A-PC (to be continued...) | ||
| 16 | * Supported functions: Read/Write Ports (to be continued...) | ||
| 17 | * | ||
| 18 | * Chipsets families: CY7C63000, CY7C63001, CY7C63100, CY7C63101 | ||
| 19 | * | ||
| 20 | * | ||
| 21 | * This program is free software; you can redistribute it and/or | ||
| 22 | * modify it under the terms of the GNU General Public License as | ||
| 23 | * published by the Free Software Foundation, version 2. | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/kernel.h> | ||
| 29 | #include <linux/usb.h> | ||
| 30 | |||
| 31 | #define DRIVER_AUTHOR "Oliver Bock (bock@fh-wolfenbuettel.de)" | ||
| 32 | #define DRIVER_DESC "Cypress CY7C63xxx USB driver" | ||
| 33 | |||
| 34 | #define CY7C63_VENDOR_ID 0xa2c | ||
| 35 | #define CY7C63_PRODUCT_ID 0x8 | ||
| 36 | |||
| 37 | #define CY7C63_READ_PORT 0x4 | ||
| 38 | #define CY7C63_WRITE_PORT 0x5 | ||
| 39 | #define CY7C63_READ_RAM 0x2 | ||
| 40 | #define CY7C63_WRITE_RAM 0x3 | ||
| 41 | #define CY7C63_READ_ROM 0x1 | ||
| 42 | |||
| 43 | #define CY7C63_READ_PORT_ID0 0 | ||
| 44 | #define CY7C63_WRITE_PORT_ID0 0 | ||
| 45 | #define CY7C63_READ_PORT_ID1 0x2 | ||
| 46 | #define CY7C63_WRITE_PORT_ID1 1 | ||
| 47 | |||
| 48 | #define CY7C63_MAX_REQSIZE 8 | ||
| 49 | |||
| 50 | |||
| 51 | /* table of devices that work with this driver */ | ||
| 52 | static struct usb_device_id cy7c63_table [] = { | ||
| 53 | { USB_DEVICE(CY7C63_VENDOR_ID, CY7C63_PRODUCT_ID) }, | ||
| 54 | { } | ||
| 55 | }; | ||
| 56 | MODULE_DEVICE_TABLE(usb, cy7c63_table); | ||
| 57 | |||
| 58 | /* structure to hold all of our device specific stuff */ | ||
| 59 | struct cy7c63 { | ||
| 60 | struct usb_device * udev; | ||
| 61 | char port0; | ||
| 62 | char port1; | ||
| 63 | }; | ||
| 64 | |||
| 65 | /* used to send usb control messages to device */ | ||
| 66 | int vendor_command(struct cy7c63 *dev, unsigned char request, | ||
| 67 | unsigned char address, unsigned char data) { | ||
| 68 | |||
| 69 | int retval = 0; | ||
| 70 | unsigned int pipe; | ||
| 71 | unsigned char *iobuf; | ||
| 72 | |||
| 73 | /* allocate some memory for the i/o buffer*/ | ||
| 74 | iobuf = kzalloc(CY7C63_MAX_REQSIZE, GFP_KERNEL); | ||
| 75 | if (!iobuf) { | ||
| 76 | dev_err(&dev->udev->dev, "Out of memory!\n"); | ||
| 77 | retval = -ENOMEM; | ||
| 78 | goto error; | ||
| 79 | } | ||
| 80 | |||
| 81 | dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data); | ||
| 82 | |||
| 83 | /* prepare usb control message and send it upstream */ | ||
| 84 | pipe = usb_rcvctrlpipe(dev->udev, 0); | ||
| 85 | retval = usb_control_msg(dev->udev, pipe, request, | ||
| 86 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, | ||
| 87 | address, data, iobuf, CY7C63_MAX_REQSIZE, | ||
| 88 | USB_CTRL_GET_TIMEOUT); | ||
| 89 | |||
| 90 | /* store returned data (more READs to be added!) */ | ||
| 91 | switch (request) { | ||
| 92 | case CY7C63_READ_PORT: | ||
| 93 | if (address == CY7C63_READ_PORT_ID0) { | ||
| 94 | dev->port0 = iobuf[1]; | ||
| 95 | dev_dbg(&dev->udev->dev, | ||
| 96 | "READ_PORT0 returned: %d\n",dev->port0); | ||
| 97 | } | ||
| 98 | else if (address == CY7C63_READ_PORT_ID1) { | ||
| 99 | dev->port1 = iobuf[1]; | ||
| 100 | dev_dbg(&dev->udev->dev, | ||
| 101 | "READ_PORT1 returned: %d\n",dev->port1); | ||
| 102 | } | ||
| 103 | break; | ||
| 104 | } | ||
| 105 | |||
| 106 | kfree(iobuf); | ||
| 107 | error: | ||
| 108 | return retval; | ||
| 109 | } | ||
| 110 | |||
| 111 | #define get_set_port(num,read_id,write_id) \ | ||
| 112 | static ssize_t set_port##num(struct device *dev, struct device_attribute *attr, \ | ||
| 113 | const char *buf, size_t count) { \ | ||
| 114 | \ | ||
| 115 | int value; \ | ||
| 116 | int result = 0; \ | ||
| 117 | \ | ||
| 118 | struct usb_interface *intf = to_usb_interface(dev); \ | ||
| 119 | struct cy7c63 *cyp = usb_get_intfdata(intf); \ | ||
| 120 | \ | ||
| 121 | dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", num); \ | ||
| 122 | \ | ||
| 123 | /* validate input data */ \ | ||
| 124 | if (sscanf(buf, "%d", &value) < 1) { \ | ||
| 125 | result = -EINVAL; \ | ||
| 126 | goto error; \ | ||
| 127 | } \ | ||
| 128 | if (value>255 || value<0) { \ | ||
| 129 | result = -EINVAL; \ | ||
| 130 | goto error; \ | ||
| 131 | } \ | ||
| 132 | \ | ||
| 133 | result = vendor_command(cyp, CY7C63_WRITE_PORT, write_id, \ | ||
| 134 | (unsigned char)value); \ | ||
| 135 | \ | ||
| 136 | dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n",result); \ | ||
| 137 | error: \ | ||
| 138 | return result < 0 ? result : count; \ | ||
| 139 | } \ | ||
| 140 | \ | ||
| 141 | static ssize_t get_port##num(struct device *dev, \ | ||
| 142 | struct device_attribute *attr, char *buf) { \ | ||
| 143 | \ | ||
| 144 | int result = 0; \ | ||
| 145 | \ | ||
| 146 | struct usb_interface *intf = to_usb_interface(dev); \ | ||
| 147 | struct cy7c63 *cyp = usb_get_intfdata(intf); \ | ||
| 148 | \ | ||
| 149 | dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", num); \ | ||
| 150 | \ | ||
| 151 | result = vendor_command(cyp, CY7C63_READ_PORT, read_id, 0); \ | ||
| 152 | \ | ||
| 153 | dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result); \ | ||
| 154 | \ | ||
| 155 | return sprintf(buf, "%d", cyp->port##num); \ | ||
| 156 | } \ | ||
| 157 | static DEVICE_ATTR(port##num, S_IWUGO | S_IRUGO, get_port##num, set_port##num); | ||
| 158 | |||
| 159 | get_set_port(0, CY7C63_READ_PORT_ID0, CY7C63_WRITE_PORT_ID0); | ||
| 160 | get_set_port(1, CY7C63_READ_PORT_ID1, CY7C63_WRITE_PORT_ID1); | ||
| 161 | |||
| 162 | static int cy7c63_probe(struct usb_interface *interface, | ||
| 163 | const struct usb_device_id *id) { | ||
| 164 | |||
| 165 | struct cy7c63 *dev = NULL; | ||
| 166 | int retval = -ENOMEM; | ||
| 167 | |||
| 168 | /* allocate memory for our device state and initialize it */ | ||
| 169 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
| 170 | if (dev == NULL) { | ||
| 171 | dev_err(&dev->udev->dev, "Out of memory!\n"); | ||
| 172 | goto error; | ||
| 173 | } | ||
| 174 | |||
| 175 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); | ||
| 176 | |||
| 177 | /* save our data pointer in this interface device */ | ||
| 178 | usb_set_intfdata(interface, dev); | ||
| 179 | |||
| 180 | /* create device attribute files */ | ||
| 181 | device_create_file(&interface->dev, &dev_attr_port0); | ||
| 182 | device_create_file(&interface->dev, &dev_attr_port1); | ||
| 183 | |||
| 184 | /* let the user know what node this device is now attached to */ | ||
| 185 | dev_info(&interface->dev, | ||
| 186 | "Cypress CY7C63xxx device now attached\n"); | ||
| 187 | |||
| 188 | retval = 0; | ||
| 189 | error: | ||
| 190 | return retval; | ||
| 191 | } | ||
| 192 | |||
| 193 | static void cy7c63_disconnect(struct usb_interface *interface) { | ||
| 194 | |||
| 195 | struct cy7c63 *dev; | ||
| 196 | |||
| 197 | dev = usb_get_intfdata(interface); | ||
| 198 | usb_set_intfdata(interface, NULL); | ||
| 199 | |||
| 200 | /* remove device attribute files */ | ||
| 201 | device_remove_file(&interface->dev, &dev_attr_port0); | ||
| 202 | device_remove_file(&interface->dev, &dev_attr_port1); | ||
| 203 | |||
| 204 | usb_put_dev(dev->udev); | ||
| 205 | |||
| 206 | dev_info(&interface->dev, | ||
| 207 | "Cypress CY7C63xxx device now disconnected\n"); | ||
| 208 | |||
| 209 | kfree(dev); | ||
| 210 | } | ||
| 211 | |||
| 212 | static struct usb_driver cy7c63_driver = { | ||
| 213 | .name = "cy7c63", | ||
| 214 | .probe = cy7c63_probe, | ||
| 215 | .disconnect = cy7c63_disconnect, | ||
| 216 | .id_table = cy7c63_table, | ||
| 217 | }; | ||
| 218 | |||
| 219 | static int __init cy7c63_init(void) { | ||
| 220 | |||
| 221 | int result; | ||
| 222 | |||
| 223 | /* register this driver with the USB subsystem */ | ||
| 224 | result = usb_register(&cy7c63_driver); | ||
| 225 | if (result) { | ||
| 226 | err("Function usb_register failed! Error number: %d\n", result); | ||
| 227 | } | ||
| 228 | |||
| 229 | return result; | ||
| 230 | } | ||
| 231 | |||
| 232 | static void __exit cy7c63_exit(void) { | ||
| 233 | |||
| 234 | /* deregister this driver with the USB subsystem */ | ||
| 235 | usb_deregister(&cy7c63_driver); | ||
| 236 | } | ||
| 237 | |||
| 238 | module_init(cy7c63_init); | ||
| 239 | module_exit(cy7c63_exit); | ||
| 240 | |||
| 241 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
| 242 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 243 | |||
| 244 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index 997db5d8e35b..13aeea2026cc 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * USB PhidgetInterfaceKit driver 1.0 | 2 | * USB PhidgetInterfaceKit driver 1.0 |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2004 Sean Young <sean@mess.org> | 4 | * Copyright (C) 2004, 2006 Sean Young <sean@mess.org> |
| 5 | * Copyright (C) 2005 Daniel Saakes <daniel@saakes.net> | ||
| 5 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> | 6 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> |
| 6 | * | 7 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| @@ -25,6 +26,7 @@ | |||
| 25 | 26 | ||
| 26 | #define USB_VENDOR_ID_GLAB 0x06c2 | 27 | #define USB_VENDOR_ID_GLAB 0x06c2 |
| 27 | #define USB_DEVICE_ID_INTERFACEKIT004 0x0040 | 28 | #define USB_DEVICE_ID_INTERFACEKIT004 0x0040 |
| 29 | #define USB_DEVICE_ID_INTERFACEKIT01616 0x0044 | ||
| 28 | #define USB_DEVICE_ID_INTERFACEKIT888 0x0045 | 30 | #define USB_DEVICE_ID_INTERFACEKIT888 0x0045 |
| 29 | #define USB_DEVICE_ID_INTERFACEKIT047 0x0051 | 31 | #define USB_DEVICE_ID_INTERFACEKIT047 0x0051 |
| 30 | #define USB_DEVICE_ID_INTERFACEKIT088 0x0053 | 32 | #define USB_DEVICE_ID_INTERFACEKIT088 0x0053 |
| @@ -32,7 +34,9 @@ | |||
| 32 | #define USB_VENDOR_ID_WISEGROUP 0x0925 | 34 | #define USB_VENDOR_ID_WISEGROUP 0x0925 |
| 33 | #define USB_DEVICE_ID_INTERFACEKIT884 0x8201 | 35 | #define USB_DEVICE_ID_INTERFACEKIT884 0x8201 |
| 34 | 36 | ||
| 35 | #define MAX_INTERFACES 8 | 37 | #define MAX_INTERFACES 16 |
| 38 | |||
| 39 | #define URB_INT_SIZE 8 | ||
| 36 | 40 | ||
| 37 | struct driver_interfacekit { | 41 | struct driver_interfacekit { |
| 38 | int sensors; | 42 | int sensors; |
| @@ -52,19 +56,24 @@ ifkit(8, 8, 8, 0); | |||
| 52 | ifkit(0, 4, 7, 1); | 56 | ifkit(0, 4, 7, 1); |
| 53 | ifkit(8, 8, 4, 0); | 57 | ifkit(8, 8, 4, 0); |
| 54 | ifkit(0, 8, 8, 1); | 58 | ifkit(0, 8, 8, 1); |
| 59 | ifkit(0, 16, 16, 0); | ||
| 55 | 60 | ||
| 56 | struct phidget_interfacekit { | 61 | struct interfacekit { |
| 57 | struct usb_device *udev; | 62 | struct usb_device *udev; |
| 58 | struct usb_interface *intf; | 63 | struct usb_interface *intf; |
| 59 | struct driver_interfacekit *ifkit; | 64 | struct driver_interfacekit *ifkit; |
| 60 | int outputs[MAX_INTERFACES]; | 65 | unsigned long outputs; |
| 61 | int inputs[MAX_INTERFACES]; | 66 | u8 inputs[MAX_INTERFACES]; |
| 62 | int sensors[MAX_INTERFACES]; | 67 | u16 sensors[MAX_INTERFACES]; |
| 63 | u8 lcd_files_on; | 68 | u8 lcd_files_on; |
| 64 | 69 | ||
| 65 | struct urb *irq; | 70 | struct urb *irq; |
| 66 | unsigned char *data; | 71 | unsigned char *data; |
| 67 | dma_addr_t data_dma; | 72 | dma_addr_t data_dma; |
| 73 | |||
| 74 | struct work_struct do_notify; | ||
| 75 | unsigned long input_events; | ||
| 76 | unsigned long sensor_events; | ||
| 68 | }; | 77 | }; |
| 69 | 78 | ||
| 70 | static struct usb_device_id id_table[] = { | 79 | static struct usb_device_id id_table[] = { |
| @@ -76,33 +85,33 @@ static struct usb_device_id id_table[] = { | |||
| 76 | .driver_info = (kernel_ulong_t)&ph_047}, | 85 | .driver_info = (kernel_ulong_t)&ph_047}, |
| 77 | {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088), | 86 | {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088), |
| 78 | .driver_info = (kernel_ulong_t)&ph_088}, | 87 | .driver_info = (kernel_ulong_t)&ph_088}, |
| 88 | {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT01616), | ||
| 89 | .driver_info = (kernel_ulong_t)&ph_01616}, | ||
| 79 | {USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_INTERFACEKIT884), | 90 | {USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_INTERFACEKIT884), |
| 80 | .driver_info = (kernel_ulong_t)&ph_884}, | 91 | .driver_info = (kernel_ulong_t)&ph_884}, |
| 81 | {} | 92 | {} |
| 82 | }; | 93 | }; |
| 83 | MODULE_DEVICE_TABLE(usb, id_table); | 94 | MODULE_DEVICE_TABLE(usb, id_table); |
| 84 | 95 | ||
| 85 | static int change_outputs(struct phidget_interfacekit *kit, int output_num, int enable) | 96 | static int change_outputs(struct interfacekit *kit, int output_num, int enable) |
| 86 | { | 97 | { |
| 87 | unsigned char *buffer; | 98 | u8 *buffer; |
| 88 | int retval; | 99 | int retval; |
| 89 | int n; | 100 | |
| 101 | if (enable) | ||
| 102 | set_bit(output_num, &kit->outputs); | ||
| 103 | else | ||
| 104 | clear_bit(output_num, &kit->outputs); | ||
| 90 | 105 | ||
| 91 | buffer = kzalloc(4, GFP_KERNEL); | 106 | buffer = kzalloc(4, GFP_KERNEL); |
| 92 | if (!buffer) { | 107 | if (!buffer) { |
| 93 | dev_err(&kit->udev->dev, "%s - out of memory\n", | 108 | dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__); |
| 94 | __FUNCTION__); | ||
| 95 | return -ENOMEM; | 109 | return -ENOMEM; |
| 96 | } | 110 | } |
| 111 | buffer[0] = (u8)kit->outputs; | ||
| 112 | buffer[1] = (u8)(kit->outputs >> 8); | ||
| 97 | 113 | ||
| 98 | kit->outputs[output_num] = enable; | 114 | dev_dbg(&kit->udev->dev, "sending data: 0x%04x\n", (u16)kit->outputs); |
| 99 | for (n=0; n<8; n++) { | ||
| 100 | if (kit->outputs[n]) { | ||
| 101 | buffer[0] |= 1 << n; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | dev_dbg(&kit->udev->dev, "sending data: %02x\n", buffer[0]); | ||
| 106 | 115 | ||
| 107 | retval = usb_control_msg(kit->udev, | 116 | retval = usb_control_msg(kit->udev, |
| 108 | usb_sndctrlpipe(kit->udev, 0), | 117 | usb_sndctrlpipe(kit->udev, 0), |
| @@ -116,10 +125,10 @@ static int change_outputs(struct phidget_interfacekit *kit, int output_num, int | |||
| 116 | return retval < 0 ? retval : 0; | 125 | return retval < 0 ? retval : 0; |
| 117 | } | 126 | } |
| 118 | 127 | ||
| 119 | static int change_string(struct phidget_interfacekit *kit, const char *display, unsigned char row) | 128 | static int change_string(struct interfacekit *kit, const char *display, unsigned char row) |
| 120 | { | 129 | { |
| 121 | unsigned char *buffer; | 130 | unsigned char *buffer; |
| 122 | unsigned char *form_buffer; | 131 | unsigned char *form_buffer; |
| 123 | int retval = -ENOMEM; | 132 | int retval = -ENOMEM; |
| 124 | int i,j, len, buf_ptr; | 133 | int i,j, len, buf_ptr; |
| 125 | 134 | ||
| @@ -175,7 +184,7 @@ exit: | |||
| 175 | static ssize_t lcd_line_##number(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ | 184 | static ssize_t lcd_line_##number(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ |
| 176 | { \ | 185 | { \ |
| 177 | struct usb_interface *intf = to_usb_interface(dev); \ | 186 | struct usb_interface *intf = to_usb_interface(dev); \ |
| 178 | struct phidget_interfacekit *kit = usb_get_intfdata(intf); \ | 187 | struct interfacekit *kit = usb_get_intfdata(intf); \ |
| 179 | change_string(kit, buf, number - 1); \ | 188 | change_string(kit, buf, number - 1); \ |
| 180 | return count; \ | 189 | return count; \ |
| 181 | } \ | 190 | } \ |
| @@ -186,7 +195,7 @@ set_lcd_line(2); | |||
| 186 | static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 195 | static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
| 187 | { | 196 | { |
| 188 | struct usb_interface *intf = to_usb_interface(dev); | 197 | struct usb_interface *intf = to_usb_interface(dev); |
| 189 | struct phidget_interfacekit *kit = usb_get_intfdata(intf); | 198 | struct interfacekit *kit = usb_get_intfdata(intf); |
| 190 | int enabled; | 199 | int enabled; |
| 191 | unsigned char *buffer; | 200 | unsigned char *buffer; |
| 192 | int retval = -ENOMEM; | 201 | int retval = -ENOMEM; |
| @@ -220,7 +229,7 @@ exit: | |||
| 220 | } | 229 | } |
| 221 | static DEVICE_ATTR(backlight, S_IWUGO, NULL, set_backlight); | 230 | static DEVICE_ATTR(backlight, S_IWUGO, NULL, set_backlight); |
| 222 | 231 | ||
| 223 | static void remove_lcd_files(struct phidget_interfacekit *kit) | 232 | static void remove_lcd_files(struct interfacekit *kit) |
| 224 | { | 233 | { |
| 225 | if (kit->lcd_files_on) { | 234 | if (kit->lcd_files_on) { |
| 226 | dev_dbg(&kit->udev->dev, "Removing lcd files\n"); | 235 | dev_dbg(&kit->udev->dev, "Removing lcd files\n"); |
| @@ -233,7 +242,7 @@ static void remove_lcd_files(struct phidget_interfacekit *kit) | |||
| 233 | static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 242 | static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
| 234 | { | 243 | { |
| 235 | struct usb_interface *intf = to_usb_interface(dev); | 244 | struct usb_interface *intf = to_usb_interface(dev); |
| 236 | struct phidget_interfacekit *kit = usb_get_intfdata(intf); | 245 | struct interfacekit *kit = usb_get_intfdata(intf); |
| 237 | int enable; | 246 | int enable; |
| 238 | 247 | ||
| 239 | if (kit->ifkit->has_lcd == 0) | 248 | if (kit->ifkit->has_lcd == 0) |
| @@ -263,10 +272,10 @@ static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files); | |||
| 263 | 272 | ||
| 264 | static void interfacekit_irq(struct urb *urb, struct pt_regs *regs) | 273 | static void interfacekit_irq(struct urb *urb, struct pt_regs *regs) |
| 265 | { | 274 | { |
| 266 | struct phidget_interfacekit *kit = urb->context; | 275 | struct interfacekit *kit = urb->context; |
| 267 | unsigned char *buffer = kit->data; | 276 | unsigned char *buffer = kit->data; |
| 277 | int i, level, sensor; | ||
| 268 | int status; | 278 | int status; |
| 269 | int n; | ||
| 270 | 279 | ||
| 271 | switch (urb->status) { | 280 | switch (urb->status) { |
| 272 | case 0: /* success */ | 281 | case 0: /* success */ |
| @@ -280,22 +289,63 @@ static void interfacekit_irq(struct urb *urb, struct pt_regs *regs) | |||
| 280 | goto resubmit; | 289 | goto resubmit; |
| 281 | } | 290 | } |
| 282 | 291 | ||
| 283 | for (n=0; n<8; n++) { | 292 | /* digital inputs */ |
| 284 | kit->inputs[n] = buffer[1] & (1 << n) ? 1 : 0; | 293 | if (kit->ifkit->inputs == 16) { |
| 294 | for (i=0; i < 8; i++) { | ||
| 295 | level = (buffer[0] >> i) & 1; | ||
| 296 | if (kit->inputs[i] != level) { | ||
| 297 | kit->inputs[i] = level; | ||
| 298 | set_bit(i, &kit->input_events); | ||
| 299 | } | ||
| 300 | level = (buffer[1] >> i) & 1; | ||
| 301 | if (kit->inputs[8 + i] != level) { | ||
| 302 | kit->inputs[8 + i] = level; | ||
| 303 | set_bit(8 + i, &kit->input_events); | ||
| 304 | } | ||
| 305 | } | ||
| 306 | } | ||
| 307 | else if (kit->ifkit->inputs == 8) { | ||
| 308 | for (i=0; i < 8; i++) { | ||
| 309 | level = (buffer[1] >> i) & 1; | ||
| 310 | if (kit->inputs[i] != level) { | ||
| 311 | kit->inputs[i] = level; | ||
| 312 | set_bit(i, &kit->input_events); | ||
| 313 | } | ||
| 314 | } | ||
| 285 | } | 315 | } |
| 286 | 316 | ||
| 287 | if (buffer[0] & 1) { | 317 | /* analog inputs */ |
| 288 | kit->sensors[4] = buffer[2] + (buffer[3] & 0x0f) * 256; | 318 | if (kit->ifkit->sensors) { |
| 289 | kit->sensors[5] = buffer[4] + (buffer[3] & 0xf0) * 16; | 319 | sensor = (buffer[0] & 1) ? 4 : 0; |
| 290 | kit->sensors[6] = buffer[5] + (buffer[6] & 0x0f) * 256; | 320 | |
| 291 | kit->sensors[7] = buffer[7] + (buffer[6] & 0xf0) * 16; | 321 | level = buffer[2] + (buffer[3] & 0x0f) * 256; |
| 292 | } else { | 322 | if (level != kit->sensors[sensor]) { |
| 293 | kit->sensors[0] = buffer[2] + (buffer[3] & 0x0f) * 256; | 323 | kit->sensors[sensor] = level; |
| 294 | kit->sensors[1] = buffer[4] + (buffer[3] & 0xf0) * 16; | 324 | set_bit(sensor, &kit->sensor_events); |
| 295 | kit->sensors[2] = buffer[5] + (buffer[6] & 0x0f) * 256; | 325 | } |
| 296 | kit->sensors[3] = buffer[7] + (buffer[6] & 0xf0) * 16; | 326 | sensor++; |
| 327 | level = buffer[4] + (buffer[3] & 0xf0) * 16; | ||
| 328 | if (level != kit->sensors[sensor]) { | ||
| 329 | kit->sensors[sensor] = level; | ||
| 330 | set_bit(sensor, &kit->sensor_events); | ||
| 331 | } | ||
| 332 | sensor++; | ||
| 333 | level = buffer[5] + (buffer[6] & 0x0f) * 256; | ||
| 334 | if (level != kit->sensors[sensor]) { | ||
| 335 | kit->sensors[sensor] = level; | ||
| 336 | set_bit(sensor, &kit->sensor_events); | ||
| 337 | } | ||
| 338 | sensor++; | ||
| 339 | level = buffer[7] + (buffer[6] & 0xf0) * 16; | ||
| 340 | if (level != kit->sensors[sensor]) { | ||
| 341 | kit->sensors[sensor] = level; | ||
| 342 | set_bit(sensor, &kit->sensor_events); | ||
| 343 | } | ||
| 297 | } | 344 | } |
| 298 | 345 | ||
| 346 | if (kit->input_events || kit->sensor_events) | ||
| 347 | schedule_work(&kit->do_notify); | ||
| 348 | |||
| 299 | resubmit: | 349 | resubmit: |
| 300 | status = usb_submit_urb(urb, SLAB_ATOMIC); | 350 | status = usb_submit_urb(urb, SLAB_ATOMIC); |
| 301 | if (status) | 351 | if (status) |
| @@ -304,20 +354,40 @@ resubmit: | |||
| 304 | kit->udev->devpath, status); | 354 | kit->udev->devpath, status); |
| 305 | } | 355 | } |
| 306 | 356 | ||
| 357 | static void do_notify(void *data) | ||
| 358 | { | ||
| 359 | struct interfacekit *kit = data; | ||
| 360 | int i; | ||
| 361 | char sysfs_file[8]; | ||
| 362 | |||
| 363 | for (i=0; i<kit->ifkit->inputs; i++) { | ||
| 364 | if (test_and_clear_bit(i, &kit->input_events)) { | ||
| 365 | sprintf(sysfs_file, "input%d", i + 1); | ||
| 366 | sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | for (i=0; i<kit->ifkit->sensors; i++) { | ||
| 371 | if (test_and_clear_bit(i, &kit->sensor_events)) { | ||
| 372 | sprintf(sysfs_file, "sensor%d", i + 1); | ||
| 373 | sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file); | ||
| 374 | } | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 307 | #define show_set_output(value) \ | 378 | #define show_set_output(value) \ |
| 308 | static ssize_t set_output##value(struct device *dev, struct device_attribute *attr, const char *buf, \ | 379 | static ssize_t set_output##value(struct device *dev, struct device_attribute *attr, const char *buf, \ |
| 309 | size_t count) \ | 380 | size_t count) \ |
| 310 | { \ | 381 | { \ |
| 311 | struct usb_interface *intf = to_usb_interface(dev); \ | 382 | struct usb_interface *intf = to_usb_interface(dev); \ |
| 312 | struct phidget_interfacekit *kit = usb_get_intfdata(intf); \ | 383 | struct interfacekit *kit = usb_get_intfdata(intf); \ |
| 313 | int enabled; \ | 384 | int enabled; \ |
| 314 | int retval; \ | 385 | int retval; \ |
| 315 | \ | 386 | \ |
| 316 | if (sscanf(buf, "%d", &enabled) < 1) { \ | 387 | if (sscanf(buf, "%d", &enabled) < 1) \ |
| 317 | return -EINVAL; \ | 388 | return -EINVAL; \ |
| 318 | } \ | ||
| 319 | \ | 389 | \ |
| 320 | retval = change_outputs(kit, value - 1, enabled ? 1 : 0); \ | 390 | retval = change_outputs(kit, value - 1, enabled); \ |
| 321 | \ | 391 | \ |
| 322 | return retval ? retval : count; \ | 392 | return retval ? retval : count; \ |
| 323 | } \ | 393 | } \ |
| @@ -325,9 +395,9 @@ static ssize_t set_output##value(struct device *dev, struct device_attribute *at | |||
| 325 | static ssize_t show_output##value(struct device *dev, struct device_attribute *attr, char *buf) \ | 395 | static ssize_t show_output##value(struct device *dev, struct device_attribute *attr, char *buf) \ |
| 326 | { \ | 396 | { \ |
| 327 | struct usb_interface *intf = to_usb_interface(dev); \ | 397 | struct usb_interface *intf = to_usb_interface(dev); \ |
| 328 | struct phidget_interfacekit *kit = usb_get_intfdata(intf); \ | 398 | struct interfacekit *kit = usb_get_intfdata(intf); \ |
| 329 | \ | 399 | \ |
| 330 | return sprintf(buf, "%d\n", kit->outputs[value - 1]); \ | 400 | return sprintf(buf, "%d\n", !!test_bit(value - 1, &kit->outputs));\ |
| 331 | } \ | 401 | } \ |
| 332 | static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO, \ | 402 | static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO, \ |
| 333 | show_output##value, set_output##value); | 403 | show_output##value, set_output##value); |
| @@ -338,15 +408,23 @@ show_set_output(4); | |||
| 338 | show_set_output(5); | 408 | show_set_output(5); |
| 339 | show_set_output(6); | 409 | show_set_output(6); |
| 340 | show_set_output(7); | 410 | show_set_output(7); |
| 341 | show_set_output(8); /* should be MAX_INTERFACES - 1 */ | 411 | show_set_output(8); |
| 412 | show_set_output(9); | ||
| 413 | show_set_output(10); | ||
| 414 | show_set_output(11); | ||
| 415 | show_set_output(12); | ||
| 416 | show_set_output(13); | ||
| 417 | show_set_output(14); | ||
| 418 | show_set_output(15); | ||
| 419 | show_set_output(16); | ||
| 342 | 420 | ||
| 343 | #define show_input(value) \ | 421 | #define show_input(value) \ |
| 344 | static ssize_t show_input##value(struct device *dev, struct device_attribute *attr, char *buf) \ | 422 | static ssize_t show_input##value(struct device *dev, struct device_attribute *attr, char *buf) \ |
| 345 | { \ | 423 | { \ |
| 346 | struct usb_interface *intf = to_usb_interface(dev); \ | 424 | struct usb_interface *intf = to_usb_interface(dev); \ |
| 347 | struct phidget_interfacekit *kit = usb_get_intfdata(intf); \ | 425 | struct interfacekit *kit = usb_get_intfdata(intf); \ |
| 348 | \ | 426 | \ |
| 349 | return sprintf(buf, "%d\n", kit->inputs[value - 1]); \ | 427 | return sprintf(buf, "%d\n", (int)kit->inputs[value - 1]); \ |
| 350 | } \ | 428 | } \ |
| 351 | static DEVICE_ATTR(input##value, S_IRUGO, show_input##value, NULL); | 429 | static DEVICE_ATTR(input##value, S_IRUGO, show_input##value, NULL); |
| 352 | 430 | ||
| @@ -357,15 +435,23 @@ show_input(4); | |||
| 357 | show_input(5); | 435 | show_input(5); |
| 358 | show_input(6); | 436 | show_input(6); |
| 359 | show_input(7); | 437 | show_input(7); |
| 360 | show_input(8); /* should be MAX_INTERFACES - 1 */ | 438 | show_input(8); |
| 439 | show_input(9); | ||
| 440 | show_input(10); | ||
| 441 | show_input(11); | ||
| 442 | show_input(12); | ||
| 443 | show_input(13); | ||
| 444 | show_input(14); | ||
| 445 | show_input(15); | ||
| 446 | show_input(16); | ||
| 361 | 447 | ||
| 362 | #define show_sensor(value) \ | 448 | #define show_sensor(value) \ |
| 363 | static ssize_t show_sensor##value(struct device *dev, struct device_attribute *attr, char *buf) \ | 449 | static ssize_t show_sensor##value(struct device *dev, struct device_attribute *attr, char *buf) \ |
| 364 | { \ | 450 | { \ |
| 365 | struct usb_interface *intf = to_usb_interface(dev); \ | 451 | struct usb_interface *intf = to_usb_interface(dev); \ |
| 366 | struct phidget_interfacekit *kit = usb_get_intfdata(intf); \ | 452 | struct interfacekit *kit = usb_get_intfdata(intf); \ |
| 367 | \ | 453 | \ |
| 368 | return sprintf(buf, "%d\n", kit->sensors[value - 1]); \ | 454 | return sprintf(buf, "%d\n", (int)kit->sensors[value - 1]); \ |
| 369 | } \ | 455 | } \ |
| 370 | static DEVICE_ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL); | 456 | static DEVICE_ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL); |
| 371 | 457 | ||
| @@ -376,16 +462,16 @@ show_sensor(4); | |||
| 376 | show_sensor(5); | 462 | show_sensor(5); |
| 377 | show_sensor(6); | 463 | show_sensor(6); |
| 378 | show_sensor(7); | 464 | show_sensor(7); |
| 379 | show_sensor(8); /* should be MAX_INTERFACES - 1 */ | 465 | show_sensor(8); |
| 380 | 466 | ||
| 381 | static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id) | 467 | static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id) |
| 382 | { | 468 | { |
| 383 | struct usb_device *dev = interface_to_usbdev(intf); | 469 | struct usb_device *dev = interface_to_usbdev(intf); |
| 384 | struct usb_host_interface *interface; | 470 | struct usb_host_interface *interface; |
| 385 | struct usb_endpoint_descriptor *endpoint; | 471 | struct usb_endpoint_descriptor *endpoint; |
| 386 | struct phidget_interfacekit *kit; | 472 | struct interfacekit *kit; |
| 387 | struct driver_interfacekit *ifkit; | 473 | struct driver_interfacekit *ifkit; |
| 388 | int pipe, maxp; | 474 | int pipe, maxp, rc = -ENOMEM; |
| 389 | 475 | ||
| 390 | ifkit = (struct driver_interfacekit *)id->driver_info; | 476 | ifkit = (struct driver_interfacekit *)id->driver_info; |
| 391 | if (!ifkit) | 477 | if (!ifkit) |
| @@ -405,29 +491,23 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic | |||
| 405 | maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); | 491 | maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); |
| 406 | 492 | ||
| 407 | kit = kzalloc(sizeof(*kit), GFP_KERNEL); | 493 | kit = kzalloc(sizeof(*kit), GFP_KERNEL); |
| 408 | if (kit == NULL) { | 494 | if (!kit) |
| 409 | dev_err(&intf->dev, "%s - out of memory\n", __FUNCTION__); | 495 | goto out; |
| 410 | return -ENOMEM; | ||
| 411 | } | ||
| 412 | kit->ifkit = ifkit; | ||
| 413 | 496 | ||
| 414 | kit->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kit->data_dma); | 497 | kit->ifkit = ifkit; |
| 415 | if (!kit->data) { | 498 | kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &kit->data_dma); |
| 416 | kfree(kit); | 499 | if (!kit->data) |
| 417 | return -ENOMEM; | 500 | goto out; |
| 418 | } | ||
| 419 | 501 | ||
| 420 | kit->irq = usb_alloc_urb(0, GFP_KERNEL); | 502 | kit->irq = usb_alloc_urb(0, GFP_KERNEL); |
| 421 | if (!kit->irq) { | 503 | if (!kit->irq) |
| 422 | usb_buffer_free(dev, 8, kit->data, kit->data_dma); | 504 | goto out; |
| 423 | kfree(kit); | ||
| 424 | return -ENOMEM; | ||
| 425 | } | ||
| 426 | 505 | ||
| 427 | kit->udev = usb_get_dev(dev); | 506 | kit->udev = usb_get_dev(dev); |
| 428 | kit->intf = intf; | 507 | kit->intf = intf; |
| 508 | INIT_WORK(&kit->do_notify, do_notify, kit); | ||
| 429 | usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data, | 509 | usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data, |
| 430 | (maxp > 8 ? 8 : maxp), | 510 | maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp, |
| 431 | interfacekit_irq, kit, endpoint->bInterval); | 511 | interfacekit_irq, kit, endpoint->bInterval); |
| 432 | kit->irq->transfer_dma = kit->data_dma; | 512 | kit->irq->transfer_dma = kit->data_dma; |
| 433 | kit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 513 | kit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
| @@ -435,7 +515,8 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic | |||
| 435 | usb_set_intfdata(intf, kit); | 515 | usb_set_intfdata(intf, kit); |
| 436 | 516 | ||
| 437 | if (usb_submit_urb(kit->irq, GFP_KERNEL)) { | 517 | if (usb_submit_urb(kit->irq, GFP_KERNEL)) { |
| 438 | return -EIO; | 518 | rc = -EIO; |
| 519 | goto out; | ||
| 439 | } | 520 | } |
| 440 | 521 | ||
| 441 | if (ifkit->outputs >= 4) { | 522 | if (ifkit->outputs >= 4) { |
| @@ -444,12 +525,22 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic | |||
| 444 | device_create_file(&intf->dev, &dev_attr_output3); | 525 | device_create_file(&intf->dev, &dev_attr_output3); |
| 445 | device_create_file(&intf->dev, &dev_attr_output4); | 526 | device_create_file(&intf->dev, &dev_attr_output4); |
| 446 | } | 527 | } |
| 447 | if (ifkit->outputs == 8) { | 528 | if (ifkit->outputs >= 8) { |
| 448 | device_create_file(&intf->dev, &dev_attr_output5); | 529 | device_create_file(&intf->dev, &dev_attr_output5); |
| 449 | device_create_file(&intf->dev, &dev_attr_output6); | 530 | device_create_file(&intf->dev, &dev_attr_output6); |
| 450 | device_create_file(&intf->dev, &dev_attr_output7); | 531 | device_create_file(&intf->dev, &dev_attr_output7); |
| 451 | device_create_file(&intf->dev, &dev_attr_output8); | 532 | device_create_file(&intf->dev, &dev_attr_output8); |
| 452 | } | 533 | } |
| 534 | if (ifkit->outputs == 16) { | ||
| 535 | device_create_file(&intf->dev, &dev_attr_output9); | ||
| 536 | device_create_file(&intf->dev, &dev_attr_output10); | ||
| 537 | device_create_file(&intf->dev, &dev_attr_output11); | ||
| 538 | device_create_file(&intf->dev, &dev_attr_output12); | ||
| 539 | device_create_file(&intf->dev, &dev_attr_output13); | ||
| 540 | device_create_file(&intf->dev, &dev_attr_output14); | ||
| 541 | device_create_file(&intf->dev, &dev_attr_output15); | ||
| 542 | device_create_file(&intf->dev, &dev_attr_output16); | ||
| 543 | } | ||
| 453 | 544 | ||
| 454 | if (ifkit->inputs >= 4) { | 545 | if (ifkit->inputs >= 4) { |
| 455 | device_create_file(&intf->dev, &dev_attr_input1); | 546 | device_create_file(&intf->dev, &dev_attr_input1); |
| @@ -457,12 +548,22 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic | |||
| 457 | device_create_file(&intf->dev, &dev_attr_input3); | 548 | device_create_file(&intf->dev, &dev_attr_input3); |
| 458 | device_create_file(&intf->dev, &dev_attr_input4); | 549 | device_create_file(&intf->dev, &dev_attr_input4); |
| 459 | } | 550 | } |
| 460 | if (ifkit->inputs == 8) { | 551 | if (ifkit->inputs >= 8) { |
| 461 | device_create_file(&intf->dev, &dev_attr_input5); | 552 | device_create_file(&intf->dev, &dev_attr_input5); |
| 462 | device_create_file(&intf->dev, &dev_attr_input6); | 553 | device_create_file(&intf->dev, &dev_attr_input6); |
| 463 | device_create_file(&intf->dev, &dev_attr_input7); | 554 | device_create_file(&intf->dev, &dev_attr_input7); |
| 464 | device_create_file(&intf->dev, &dev_attr_input8); | 555 | device_create_file(&intf->dev, &dev_attr_input8); |
| 465 | } | 556 | } |
| 557 | if (ifkit->inputs == 16) { | ||
| 558 | device_create_file(&intf->dev, &dev_attr_input9); | ||
| 559 | device_create_file(&intf->dev, &dev_attr_input10); | ||
| 560 | device_create_file(&intf->dev, &dev_attr_input11); | ||
| 561 | device_create_file(&intf->dev, &dev_attr_input12); | ||
| 562 | device_create_file(&intf->dev, &dev_attr_input13); | ||
| 563 | device_create_file(&intf->dev, &dev_attr_input14); | ||
| 564 | device_create_file(&intf->dev, &dev_attr_input15); | ||
| 565 | device_create_file(&intf->dev, &dev_attr_input16); | ||
| 566 | } | ||
| 466 | 567 | ||
| 467 | if (ifkit->sensors >= 4) { | 568 | if (ifkit->sensors >= 4) { |
| 468 | device_create_file(&intf->dev, &dev_attr_sensor1); | 569 | device_create_file(&intf->dev, &dev_attr_sensor1); |
| @@ -475,9 +576,8 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic | |||
| 475 | device_create_file(&intf->dev, &dev_attr_sensor6); | 576 | device_create_file(&intf->dev, &dev_attr_sensor6); |
| 476 | device_create_file(&intf->dev, &dev_attr_sensor7); | 577 | device_create_file(&intf->dev, &dev_attr_sensor7); |
| 477 | } | 578 | } |
| 478 | if (ifkit->sensors == 8) { | 579 | if (ifkit->sensors == 8) |
| 479 | device_create_file(&intf->dev, &dev_attr_sensor8); | 580 | device_create_file(&intf->dev, &dev_attr_sensor8); |
| 480 | } | ||
| 481 | 581 | ||
| 482 | if (ifkit->has_lcd) | 582 | if (ifkit->has_lcd) |
| 483 | device_create_file(&intf->dev, &dev_attr_lcd); | 583 | device_create_file(&intf->dev, &dev_attr_lcd); |
| @@ -486,29 +586,56 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic | |||
| 486 | ifkit->sensors, ifkit->inputs, ifkit->outputs); | 586 | ifkit->sensors, ifkit->inputs, ifkit->outputs); |
| 487 | 587 | ||
| 488 | return 0; | 588 | return 0; |
| 589 | |||
| 590 | out: | ||
| 591 | if (kit) { | ||
| 592 | if (kit->irq) | ||
| 593 | usb_free_urb(kit->irq); | ||
| 594 | if (kit->data) | ||
| 595 | usb_buffer_free(dev, URB_INT_SIZE, kit->data, kit->data_dma); | ||
| 596 | kfree(kit); | ||
| 597 | } | ||
| 598 | |||
| 599 | return rc; | ||
| 489 | } | 600 | } |
| 490 | 601 | ||
| 491 | static void interfacekit_disconnect(struct usb_interface *interface) | 602 | static void interfacekit_disconnect(struct usb_interface *interface) |
| 492 | { | 603 | { |
| 493 | struct phidget_interfacekit *kit; | 604 | struct interfacekit *kit; |
| 494 | 605 | ||
| 495 | kit = usb_get_intfdata(interface); | 606 | kit = usb_get_intfdata(interface); |
| 496 | usb_set_intfdata(interface, NULL); | 607 | usb_set_intfdata(interface, NULL); |
| 497 | if (!kit) | 608 | if (!kit) |
| 498 | return; | 609 | return; |
| 499 | 610 | ||
| 611 | usb_kill_urb(kit->irq); | ||
| 612 | usb_free_urb(kit->irq); | ||
| 613 | usb_buffer_free(kit->udev, URB_INT_SIZE, kit->data, kit->data_dma); | ||
| 614 | |||
| 615 | cancel_delayed_work(&kit->do_notify); | ||
| 616 | |||
| 500 | if (kit->ifkit->outputs >= 4) { | 617 | if (kit->ifkit->outputs >= 4) { |
| 501 | device_remove_file(&interface->dev, &dev_attr_output1); | 618 | device_remove_file(&interface->dev, &dev_attr_output1); |
| 502 | device_remove_file(&interface->dev, &dev_attr_output2); | 619 | device_remove_file(&interface->dev, &dev_attr_output2); |
| 503 | device_remove_file(&interface->dev, &dev_attr_output3); | 620 | device_remove_file(&interface->dev, &dev_attr_output3); |
| 504 | device_remove_file(&interface->dev, &dev_attr_output4); | 621 | device_remove_file(&interface->dev, &dev_attr_output4); |
| 505 | } | 622 | } |
| 506 | if (kit->ifkit->outputs == 8) { | 623 | if (kit->ifkit->outputs >= 8) { |
| 507 | device_remove_file(&interface->dev, &dev_attr_output5); | 624 | device_remove_file(&interface->dev, &dev_attr_output5); |
| 508 | device_remove_file(&interface->dev, &dev_attr_output6); | 625 | device_remove_file(&interface->dev, &dev_attr_output6); |
| 509 | device_remove_file(&interface->dev, &dev_attr_output7); | 626 | device_remove_file(&interface->dev, &dev_attr_output7); |
| 510 | device_remove_file(&interface->dev, &dev_attr_output8); | 627 | device_remove_file(&interface->dev, &dev_attr_output8); |
| 511 | } | 628 | } |
| 629 | if (kit->ifkit->outputs == 16) { | ||
| 630 | device_remove_file(&interface->dev, &dev_attr_output9); | ||
| 631 | device_remove_file(&interface->dev, &dev_attr_output10); | ||
| 632 | device_remove_file(&interface->dev, &dev_attr_output11); | ||
| 633 | device_remove_file(&interface->dev, &dev_attr_output12); | ||
| 634 | device_remove_file(&interface->dev, &dev_attr_output13); | ||
| 635 | device_remove_file(&interface->dev, &dev_attr_output14); | ||
| 636 | device_remove_file(&interface->dev, &dev_attr_output15); | ||
| 637 | device_remove_file(&interface->dev, &dev_attr_output16); | ||
| 638 | } | ||
| 512 | 639 | ||
| 513 | if (kit->ifkit->inputs >= 4) { | 640 | if (kit->ifkit->inputs >= 4) { |
| 514 | device_remove_file(&interface->dev, &dev_attr_input1); | 641 | device_remove_file(&interface->dev, &dev_attr_input1); |
| @@ -516,12 +643,22 @@ static void interfacekit_disconnect(struct usb_interface *interface) | |||
| 516 | device_remove_file(&interface->dev, &dev_attr_input3); | 643 | device_remove_file(&interface->dev, &dev_attr_input3); |
| 517 | device_remove_file(&interface->dev, &dev_attr_input4); | 644 | device_remove_file(&interface->dev, &dev_attr_input4); |
| 518 | } | 645 | } |
| 519 | if (kit->ifkit->inputs == 8) { | 646 | if (kit->ifkit->inputs >= 8) { |
| 520 | device_remove_file(&interface->dev, &dev_attr_input5); | 647 | device_remove_file(&interface->dev, &dev_attr_input5); |
| 521 | device_remove_file(&interface->dev, &dev_attr_input6); | 648 | device_remove_file(&interface->dev, &dev_attr_input6); |
| 522 | device_remove_file(&interface->dev, &dev_attr_input7); | 649 | device_remove_file(&interface->dev, &dev_attr_input7); |
| 523 | device_remove_file(&interface->dev, &dev_attr_input8); | 650 | device_remove_file(&interface->dev, &dev_attr_input8); |
| 524 | } | 651 | } |
| 652 | if (kit->ifkit->inputs == 16) { | ||
| 653 | device_remove_file(&interface->dev, &dev_attr_input9); | ||
| 654 | device_remove_file(&interface->dev, &dev_attr_input10); | ||
| 655 | device_remove_file(&interface->dev, &dev_attr_input11); | ||
| 656 | device_remove_file(&interface->dev, &dev_attr_input12); | ||
| 657 | device_remove_file(&interface->dev, &dev_attr_input13); | ||
| 658 | device_remove_file(&interface->dev, &dev_attr_input14); | ||
| 659 | device_remove_file(&interface->dev, &dev_attr_input15); | ||
| 660 | device_remove_file(&interface->dev, &dev_attr_input16); | ||
| 661 | } | ||
| 525 | 662 | ||
| 526 | if (kit->ifkit->sensors >= 4) { | 663 | if (kit->ifkit->sensors >= 4) { |
| 527 | device_remove_file(&interface->dev, &dev_attr_sensor1); | 664 | device_remove_file(&interface->dev, &dev_attr_sensor1); |
| @@ -534,19 +671,15 @@ static void interfacekit_disconnect(struct usb_interface *interface) | |||
| 534 | device_remove_file(&interface->dev, &dev_attr_sensor6); | 671 | device_remove_file(&interface->dev, &dev_attr_sensor6); |
| 535 | device_remove_file(&interface->dev, &dev_attr_sensor7); | 672 | device_remove_file(&interface->dev, &dev_attr_sensor7); |
| 536 | } | 673 | } |
| 537 | if (kit->ifkit->sensors == 8) { | 674 | if (kit->ifkit->sensors == 8) |
| 538 | device_remove_file(&interface->dev, &dev_attr_sensor8); | 675 | device_remove_file(&interface->dev, &dev_attr_sensor8); |
| 539 | } | 676 | |
| 540 | if (kit->ifkit->has_lcd) | 677 | if (kit->ifkit->has_lcd) |
| 541 | device_remove_file(&interface->dev, &dev_attr_lcd); | 678 | device_remove_file(&interface->dev, &dev_attr_lcd); |
| 542 | 679 | ||
| 543 | dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n", | 680 | dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n", |
| 544 | kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs); | 681 | kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs); |
| 545 | 682 | ||
| 546 | usb_kill_urb(kit->irq); | ||
| 547 | usb_free_urb(kit->irq); | ||
| 548 | usb_buffer_free(kit->udev, 8, kit->data, kit->data_dma); | ||
| 549 | |||
| 550 | usb_put_dev(kit->udev); | 683 | usb_put_dev(kit->udev); |
| 551 | kfree(kit); | 684 | kfree(kit); |
| 552 | } | 685 | } |
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 196c8794a73c..738bd7c7451f 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | */ | 37 | */ |
| 38 | 38 | ||
| 39 | #include <linux/config.h> | 39 | #include <linux/config.h> |
| 40 | #include <linux/mutex.h> | ||
| 40 | #include <linux/module.h> | 41 | #include <linux/module.h> |
| 41 | #include <linux/kernel.h> | 42 | #include <linux/kernel.h> |
| 42 | #include <linux/signal.h> | 43 | #include <linux/signal.h> |
| @@ -52,6 +53,7 @@ | |||
| 52 | #include <linux/vmalloc.h> | 53 | #include <linux/vmalloc.h> |
| 53 | 54 | ||
| 54 | #include "sisusb.h" | 55 | #include "sisusb.h" |
| 56 | #include "sisusb_init.h" | ||
| 55 | 57 | ||
| 56 | #ifdef INCL_SISUSB_CON | 58 | #ifdef INCL_SISUSB_CON |
| 57 | #include <linux/font.h> | 59 | #include <linux/font.h> |
| @@ -62,36 +64,6 @@ | |||
| 62 | /* Forward declarations / clean-up routines */ | 64 | /* Forward declarations / clean-up routines */ |
| 63 | 65 | ||
| 64 | #ifdef INCL_SISUSB_CON | 66 | #ifdef INCL_SISUSB_CON |
| 65 | int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); | ||
| 66 | int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data); | ||
| 67 | int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data); | ||
| 68 | int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data); | ||
| 69 | int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand, u8 myor); | ||
| 70 | int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor); | ||
| 71 | int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand); | ||
| 72 | |||
| 73 | int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); | ||
| 74 | int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data); | ||
| 75 | int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data); | ||
| 76 | int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data); | ||
| 77 | int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, | ||
| 78 | u32 dest, int length, size_t *bytes_written); | ||
| 79 | |||
| 80 | int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); | ||
| 81 | |||
| 82 | extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); | ||
| 83 | extern int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); | ||
| 84 | |||
| 85 | extern void sisusb_init_concode(void); | ||
| 86 | extern int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last); | ||
| 87 | extern void sisusb_console_exit(struct sisusb_usb_data *sisusb); | ||
| 88 | |||
| 89 | extern void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location); | ||
| 90 | |||
| 91 | extern int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, | ||
| 92 | u8 *arg, int cmapsz, int ch512, int dorecalc, | ||
| 93 | struct vc_data *c, int fh, int uplock); | ||
| 94 | |||
| 95 | static int sisusb_first_vc = 0; | 67 | static int sisusb_first_vc = 0; |
| 96 | static int sisusb_last_vc = 0; | 68 | static int sisusb_last_vc = 0; |
| 97 | module_param_named(first, sisusb_first_vc, int, 0); | 69 | module_param_named(first, sisusb_first_vc, int, 0); |
| @@ -102,7 +74,7 @@ MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES | |||
| 102 | 74 | ||
| 103 | static struct usb_driver sisusb_driver; | 75 | static struct usb_driver sisusb_driver; |
| 104 | 76 | ||
| 105 | DECLARE_MUTEX(disconnect_sem); | 77 | DEFINE_MUTEX(disconnect_mutex); |
| 106 | 78 | ||
| 107 | static void | 79 | static void |
| 108 | sisusb_free_buffers(struct sisusb_usb_data *sisusb) | 80 | sisusb_free_buffers(struct sisusb_usb_data *sisusb) |
| @@ -1359,9 +1331,6 @@ sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data) | |||
| 1359 | } | 1331 | } |
| 1360 | #endif | 1332 | #endif |
| 1361 | 1333 | ||
| 1362 | #ifndef INCL_SISUSB_CON | ||
| 1363 | static | ||
| 1364 | #endif | ||
| 1365 | int | 1334 | int |
| 1366 | sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data) | 1335 | sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data) |
| 1367 | { | 1336 | { |
| @@ -1371,9 +1340,6 @@ sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data) | |||
| 1371 | return ret; | 1340 | return ret; |
| 1372 | } | 1341 | } |
| 1373 | 1342 | ||
| 1374 | #ifndef INCL_SISUSB_CON | ||
| 1375 | static | ||
| 1376 | #endif | ||
| 1377 | int | 1343 | int |
| 1378 | sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data) | 1344 | sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data) |
| 1379 | { | 1345 | { |
| @@ -1383,9 +1349,6 @@ sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data) | |||
| 1383 | return ret; | 1349 | return ret; |
| 1384 | } | 1350 | } |
| 1385 | 1351 | ||
| 1386 | #ifndef INCL_SISUSB_CON | ||
| 1387 | static | ||
| 1388 | #endif | ||
| 1389 | int | 1352 | int |
| 1390 | sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, | 1353 | sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, |
| 1391 | u8 myand, u8 myor) | 1354 | u8 myand, u8 myor) |
| @@ -1415,18 +1378,12 @@ sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx, | |||
| 1415 | return ret; | 1378 | return ret; |
| 1416 | } | 1379 | } |
| 1417 | 1380 | ||
| 1418 | #ifndef INCL_SISUSB_CON | ||
| 1419 | static | ||
| 1420 | #endif | ||
| 1421 | int | 1381 | int |
| 1422 | sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor) | 1382 | sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor) |
| 1423 | { | 1383 | { |
| 1424 | return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor)); | 1384 | return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor)); |
| 1425 | } | 1385 | } |
| 1426 | 1386 | ||
| 1427 | #ifndef INCL_SISUSB_CON | ||
| 1428 | static | ||
| 1429 | #endif | ||
| 1430 | int | 1387 | int |
| 1431 | sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand) | 1388 | sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand) |
| 1432 | { | 1389 | { |
| @@ -1448,6 +1405,8 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) | |||
| 1448 | return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); | 1405 | return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); |
| 1449 | } | 1406 | } |
| 1450 | 1407 | ||
| 1408 | #if 0 | ||
| 1409 | |||
| 1451 | int | 1410 | int |
| 1452 | sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data) | 1411 | sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data) |
| 1453 | { | 1412 | { |
| @@ -1460,6 +1419,8 @@ sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data) | |||
| 1460 | return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); | 1419 | return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data)); |
| 1461 | } | 1420 | } |
| 1462 | 1421 | ||
| 1422 | #endif /* 0 */ | ||
| 1423 | |||
| 1463 | int | 1424 | int |
| 1464 | sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, | 1425 | sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, |
| 1465 | u32 dest, int length, size_t *bytes_written) | 1426 | u32 dest, int length, size_t *bytes_written) |
| @@ -2552,39 +2513,39 @@ sisusb_open(struct inode *inode, struct file *file) | |||
| 2552 | struct usb_interface *interface; | 2513 | struct usb_interface *interface; |
| 2553 | int subminor = iminor(inode); | 2514 | int subminor = iminor(inode); |
| 2554 | 2515 | ||
| 2555 | down(&disconnect_sem); | 2516 | mutex_lock(&disconnect_mutex); |
| 2556 | 2517 | ||
| 2557 | if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { | 2518 | if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { |
| 2558 | printk(KERN_ERR "sisusb[%d]: Failed to find interface\n", | 2519 | printk(KERN_ERR "sisusb[%d]: Failed to find interface\n", |
| 2559 | subminor); | 2520 | subminor); |
| 2560 | up(&disconnect_sem); | 2521 | mutex_unlock(&disconnect_mutex); |
| 2561 | return -ENODEV; | 2522 | return -ENODEV; |
| 2562 | } | 2523 | } |
| 2563 | 2524 | ||
| 2564 | if (!(sisusb = usb_get_intfdata(interface))) { | 2525 | if (!(sisusb = usb_get_intfdata(interface))) { |
| 2565 | up(&disconnect_sem); | 2526 | mutex_unlock(&disconnect_mutex); |
| 2566 | return -ENODEV; | 2527 | return -ENODEV; |
| 2567 | } | 2528 | } |
| 2568 | 2529 | ||
| 2569 | down(&sisusb->lock); | 2530 | mutex_lock(&sisusb->lock); |
| 2570 | 2531 | ||
| 2571 | if (!sisusb->present || !sisusb->ready) { | 2532 | if (!sisusb->present || !sisusb->ready) { |
| 2572 | up(&sisusb->lock); | 2533 | mutex_unlock(&sisusb->lock); |
| 2573 | up(&disconnect_sem); | 2534 | mutex_unlock(&disconnect_mutex); |
| 2574 | return -ENODEV; | 2535 | return -ENODEV; |
| 2575 | } | 2536 | } |
| 2576 | 2537 | ||
| 2577 | if (sisusb->isopen) { | 2538 | if (sisusb->isopen) { |
| 2578 | up(&sisusb->lock); | 2539 | mutex_unlock(&sisusb->lock); |
| 2579 | up(&disconnect_sem); | 2540 | mutex_unlock(&disconnect_mutex); |
| 2580 | return -EBUSY; | 2541 | return -EBUSY; |
| 2581 | } | 2542 | } |
| 2582 | 2543 | ||
| 2583 | if (!sisusb->devinit) { | 2544 | if (!sisusb->devinit) { |
| 2584 | if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) { | 2545 | if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) { |
| 2585 | if (sisusb_init_gfxdevice(sisusb, 0)) { | 2546 | if (sisusb_init_gfxdevice(sisusb, 0)) { |
| 2586 | up(&sisusb->lock); | 2547 | mutex_unlock(&sisusb->lock); |
| 2587 | up(&disconnect_sem); | 2548 | mutex_unlock(&disconnect_mutex); |
| 2588 | printk(KERN_ERR | 2549 | printk(KERN_ERR |
| 2589 | "sisusbvga[%d]: Failed to initialize " | 2550 | "sisusbvga[%d]: Failed to initialize " |
| 2590 | "device\n", | 2551 | "device\n", |
| @@ -2592,8 +2553,8 @@ sisusb_open(struct inode *inode, struct file *file) | |||
| 2592 | return -EIO; | 2553 | return -EIO; |
| 2593 | } | 2554 | } |
| 2594 | } else { | 2555 | } else { |
| 2595 | up(&sisusb->lock); | 2556 | mutex_unlock(&sisusb->lock); |
| 2596 | up(&disconnect_sem); | 2557 | mutex_unlock(&disconnect_mutex); |
| 2597 | printk(KERN_ERR | 2558 | printk(KERN_ERR |
| 2598 | "sisusbvga[%d]: Device not attached to " | 2559 | "sisusbvga[%d]: Device not attached to " |
| 2599 | "USB 2.0 hub\n", | 2560 | "USB 2.0 hub\n", |
| @@ -2609,9 +2570,9 @@ sisusb_open(struct inode *inode, struct file *file) | |||
| 2609 | 2570 | ||
| 2610 | file->private_data = sisusb; | 2571 | file->private_data = sisusb; |
| 2611 | 2572 | ||
| 2612 | up(&sisusb->lock); | 2573 | mutex_unlock(&sisusb->lock); |
| 2613 | 2574 | ||
| 2614 | up(&disconnect_sem); | 2575 | mutex_unlock(&disconnect_mutex); |
| 2615 | 2576 | ||
| 2616 | return 0; | 2577 | return 0; |
| 2617 | } | 2578 | } |
| @@ -2642,14 +2603,14 @@ sisusb_release(struct inode *inode, struct file *file) | |||
| 2642 | struct sisusb_usb_data *sisusb; | 2603 | struct sisusb_usb_data *sisusb; |
| 2643 | int myminor; | 2604 | int myminor; |
| 2644 | 2605 | ||
| 2645 | down(&disconnect_sem); | 2606 | mutex_lock(&disconnect_mutex); |
| 2646 | 2607 | ||
| 2647 | if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) { | 2608 | if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) { |
| 2648 | up(&disconnect_sem); | 2609 | mutex_unlock(&disconnect_mutex); |
| 2649 | return -ENODEV; | 2610 | return -ENODEV; |
| 2650 | } | 2611 | } |
| 2651 | 2612 | ||
| 2652 | down(&sisusb->lock); | 2613 | mutex_lock(&sisusb->lock); |
| 2653 | 2614 | ||
| 2654 | if (sisusb->present) { | 2615 | if (sisusb->present) { |
| 2655 | /* Wait for all URBs to finish if device still present */ | 2616 | /* Wait for all URBs to finish if device still present */ |
| @@ -2662,12 +2623,12 @@ sisusb_release(struct inode *inode, struct file *file) | |||
| 2662 | sisusb->isopen = 0; | 2623 | sisusb->isopen = 0; |
| 2663 | file->private_data = NULL; | 2624 | file->private_data = NULL; |
| 2664 | 2625 | ||
| 2665 | up(&sisusb->lock); | 2626 | mutex_unlock(&sisusb->lock); |
| 2666 | 2627 | ||
| 2667 | /* decrement the usage count on our device */ | 2628 | /* decrement the usage count on our device */ |
| 2668 | kref_put(&sisusb->kref, sisusb_delete); | 2629 | kref_put(&sisusb->kref, sisusb_delete); |
| 2669 | 2630 | ||
| 2670 | up(&disconnect_sem); | 2631 | mutex_unlock(&disconnect_mutex); |
| 2671 | 2632 | ||
| 2672 | return 0; | 2633 | return 0; |
| 2673 | } | 2634 | } |
| @@ -2685,11 +2646,11 @@ sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | |||
| 2685 | if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) | 2646 | if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) |
| 2686 | return -ENODEV; | 2647 | return -ENODEV; |
| 2687 | 2648 | ||
| 2688 | down(&sisusb->lock); | 2649 | mutex_lock(&sisusb->lock); |
| 2689 | 2650 | ||
| 2690 | /* Sanity check */ | 2651 | /* Sanity check */ |
| 2691 | if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { | 2652 | if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { |
| 2692 | up(&sisusb->lock); | 2653 | mutex_unlock(&sisusb->lock); |
| 2693 | return -ENODEV; | 2654 | return -ENODEV; |
| 2694 | } | 2655 | } |
| 2695 | 2656 | ||
| @@ -2784,7 +2745,7 @@ sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | |||
| 2784 | (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) { | 2745 | (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) { |
| 2785 | 2746 | ||
| 2786 | if (count != 4) { | 2747 | if (count != 4) { |
| 2787 | up(&sisusb->lock); | 2748 | mutex_unlock(&sisusb->lock); |
| 2788 | return -EINVAL; | 2749 | return -EINVAL; |
| 2789 | } | 2750 | } |
| 2790 | 2751 | ||
| @@ -2808,7 +2769,7 @@ sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | |||
| 2808 | 2769 | ||
| 2809 | (*ppos) += bytes_read; | 2770 | (*ppos) += bytes_read; |
| 2810 | 2771 | ||
| 2811 | up(&sisusb->lock); | 2772 | mutex_unlock(&sisusb->lock); |
| 2812 | 2773 | ||
| 2813 | return errno ? errno : bytes_read; | 2774 | return errno ? errno : bytes_read; |
| 2814 | } | 2775 | } |
| @@ -2827,11 +2788,11 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count, | |||
| 2827 | if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) | 2788 | if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) |
| 2828 | return -ENODEV; | 2789 | return -ENODEV; |
| 2829 | 2790 | ||
| 2830 | down(&sisusb->lock); | 2791 | mutex_lock(&sisusb->lock); |
| 2831 | 2792 | ||
| 2832 | /* Sanity check */ | 2793 | /* Sanity check */ |
| 2833 | if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { | 2794 | if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { |
| 2834 | up(&sisusb->lock); | 2795 | mutex_unlock(&sisusb->lock); |
| 2835 | return -ENODEV; | 2796 | return -ENODEV; |
| 2836 | } | 2797 | } |
| 2837 | 2798 | ||
| @@ -2930,7 +2891,7 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count, | |||
| 2930 | (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) { | 2891 | (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) { |
| 2931 | 2892 | ||
| 2932 | if (count != 4) { | 2893 | if (count != 4) { |
| 2933 | up(&sisusb->lock); | 2894 | mutex_unlock(&sisusb->lock); |
| 2934 | return -EINVAL; | 2895 | return -EINVAL; |
| 2935 | } | 2896 | } |
| 2936 | 2897 | ||
| @@ -2956,7 +2917,7 @@ sisusb_write(struct file *file, const char __user *buffer, size_t count, | |||
| 2956 | 2917 | ||
| 2957 | (*ppos) += bytes_written; | 2918 | (*ppos) += bytes_written; |
| 2958 | 2919 | ||
| 2959 | up(&sisusb->lock); | 2920 | mutex_unlock(&sisusb->lock); |
| 2960 | 2921 | ||
| 2961 | return errno ? errno : bytes_written; | 2922 | return errno ? errno : bytes_written; |
| 2962 | } | 2923 | } |
| @@ -2970,11 +2931,11 @@ sisusb_lseek(struct file *file, loff_t offset, int orig) | |||
| 2970 | if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) | 2931 | if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) |
| 2971 | return -ENODEV; | 2932 | return -ENODEV; |
| 2972 | 2933 | ||
| 2973 | down(&sisusb->lock); | 2934 | mutex_lock(&sisusb->lock); |
| 2974 | 2935 | ||
| 2975 | /* Sanity check */ | 2936 | /* Sanity check */ |
| 2976 | if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { | 2937 | if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { |
| 2977 | up(&sisusb->lock); | 2938 | mutex_unlock(&sisusb->lock); |
| 2978 | return -ENODEV; | 2939 | return -ENODEV; |
| 2979 | } | 2940 | } |
| 2980 | 2941 | ||
| @@ -2994,7 +2955,7 @@ sisusb_lseek(struct file *file, loff_t offset, int orig) | |||
| 2994 | ret = -EINVAL; | 2955 | ret = -EINVAL; |
| 2995 | } | 2956 | } |
| 2996 | 2957 | ||
| 2997 | up(&sisusb->lock); | 2958 | mutex_unlock(&sisusb->lock); |
| 2998 | return ret; | 2959 | return ret; |
| 2999 | } | 2960 | } |
| 3000 | 2961 | ||
| @@ -3136,7 +3097,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
| 3136 | if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) | 3097 | if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) |
| 3137 | return -ENODEV; | 3098 | return -ENODEV; |
| 3138 | 3099 | ||
| 3139 | down(&sisusb->lock); | 3100 | mutex_lock(&sisusb->lock); |
| 3140 | 3101 | ||
| 3141 | /* Sanity check */ | 3102 | /* Sanity check */ |
| 3142 | if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { | 3103 | if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { |
| @@ -3193,7 +3154,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
| 3193 | } | 3154 | } |
| 3194 | 3155 | ||
| 3195 | err_out: | 3156 | err_out: |
| 3196 | up(&sisusb->lock); | 3157 | mutex_unlock(&sisusb->lock); |
| 3197 | return retval; | 3158 | return retval; |
| 3198 | } | 3159 | } |
| 3199 | 3160 | ||
| @@ -3258,7 +3219,7 @@ static int sisusb_probe(struct usb_interface *intf, | |||
| 3258 | } | 3219 | } |
| 3259 | kref_init(&sisusb->kref); | 3220 | kref_init(&sisusb->kref); |
| 3260 | 3221 | ||
| 3261 | init_MUTEX(&(sisusb->lock)); | 3222 | mutex_init(&(sisusb->lock)); |
| 3262 | 3223 | ||
| 3263 | /* Register device */ | 3224 | /* Register device */ |
| 3264 | if ((retval = usb_register_dev(intf, &usb_sisusb_class))) { | 3225 | if ((retval = usb_register_dev(intf, &usb_sisusb_class))) { |
| @@ -3429,9 +3390,9 @@ static void sisusb_disconnect(struct usb_interface *intf) | |||
| 3429 | * protect all other routines from the disconnect | 3390 | * protect all other routines from the disconnect |
| 3430 | * case, not the other way round. | 3391 | * case, not the other way round. |
| 3431 | */ | 3392 | */ |
| 3432 | down(&disconnect_sem); | 3393 | mutex_lock(&disconnect_mutex); |
| 3433 | 3394 | ||
| 3434 | down(&sisusb->lock); | 3395 | mutex_lock(&sisusb->lock); |
| 3435 | 3396 | ||
| 3436 | /* Wait for all URBs to complete and kill them in case (MUST do) */ | 3397 | /* Wait for all URBs to complete and kill them in case (MUST do) */ |
| 3437 | if (!sisusb_wait_all_out_complete(sisusb)) | 3398 | if (!sisusb_wait_all_out_complete(sisusb)) |
| @@ -3462,12 +3423,12 @@ static void sisusb_disconnect(struct usb_interface *intf) | |||
| 3462 | sisusb->present = 0; | 3423 | sisusb->present = 0; |
| 3463 | sisusb->ready = 0; | 3424 | sisusb->ready = 0; |
| 3464 | 3425 | ||
| 3465 | up(&sisusb->lock); | 3426 | mutex_unlock(&sisusb->lock); |
| 3466 | 3427 | ||
| 3467 | /* decrement our usage count */ | 3428 | /* decrement our usage count */ |
| 3468 | kref_put(&sisusb->kref, sisusb_delete); | 3429 | kref_put(&sisusb->kref, sisusb_delete); |
| 3469 | 3430 | ||
| 3470 | up(&disconnect_sem); | 3431 | mutex_unlock(&disconnect_mutex); |
| 3471 | 3432 | ||
| 3472 | printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor); | 3433 | printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor); |
| 3473 | } | 3434 | } |
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h index a716825d1f9b..8e1120a64806 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.h +++ b/drivers/usb/misc/sisusbvga/sisusb.h | |||
| @@ -41,6 +41,8 @@ | |||
| 41 | #define SISUSB_NEW_CONFIG_COMPAT | 41 | #define SISUSB_NEW_CONFIG_COMPAT |
| 42 | #endif | 42 | #endif |
| 43 | 43 | ||
| 44 | #include <linux/mutex.h> | ||
| 45 | |||
| 44 | /* For older kernels, support for text consoles is by default | 46 | /* For older kernels, support for text consoles is by default |
| 45 | * off. To ensable text console support, change the following: | 47 | * off. To ensable text console support, change the following: |
| 46 | */ | 48 | */ |
| @@ -60,11 +62,9 @@ | |||
| 60 | #define INCL_SISUSB_CON 1 | 62 | #define INCL_SISUSB_CON 1 |
| 61 | #endif | 63 | #endif |
| 62 | 64 | ||
| 63 | #ifdef INCL_SISUSB_CON | ||
| 64 | #include <linux/console.h> | 65 | #include <linux/console.h> |
| 65 | #include <linux/vt_kern.h> | 66 | #include <linux/vt_kern.h> |
| 66 | #include "sisusb_struct.h" | 67 | #include "sisusb_struct.h" |
| 67 | #endif | ||
| 68 | 68 | ||
| 69 | /* USB related */ | 69 | /* USB related */ |
| 70 | 70 | ||
| @@ -116,7 +116,7 @@ struct sisusb_usb_data { | |||
| 116 | struct usb_interface *interface; | 116 | struct usb_interface *interface; |
| 117 | struct kref kref; | 117 | struct kref kref; |
| 118 | wait_queue_head_t wait_q; /* for syncind and timeouts */ | 118 | wait_queue_head_t wait_q; /* for syncind and timeouts */ |
| 119 | struct semaphore lock; /* general race avoidance */ | 119 | struct mutex lock; /* general race avoidance */ |
| 120 | unsigned int ifnum; /* interface number of the USB device */ | 120 | unsigned int ifnum; /* interface number of the USB device */ |
| 121 | int minor; /* minor (for logging clarity) */ | 121 | int minor; /* minor (for logging clarity) */ |
| 122 | int isopen; /* !=0 if open */ | 122 | int isopen; /* !=0 if open */ |
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c index be5c1a25ae21..fb48feca8353 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_con.c +++ b/drivers/usb/misc/sisusbvga/sisusb_con.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | */ | 48 | */ |
| 49 | 49 | ||
| 50 | #include <linux/config.h> | 50 | #include <linux/config.h> |
| 51 | #include <linux/mutex.h> | ||
| 51 | #include <linux/module.h> | 52 | #include <linux/module.h> |
| 52 | #include <linux/kernel.h> | 53 | #include <linux/kernel.h> |
| 53 | #include <linux/signal.h> | 54 | #include <linux/signal.h> |
| @@ -69,27 +70,9 @@ | |||
| 69 | #include <linux/vmalloc.h> | 70 | #include <linux/vmalloc.h> |
| 70 | 71 | ||
| 71 | #include "sisusb.h" | 72 | #include "sisusb.h" |
| 73 | #include "sisusb_init.h" | ||
| 72 | 74 | ||
| 73 | #ifdef INCL_SISUSB_CON | 75 | #ifdef INCL_SISUSB_CON |
| 74 | extern int sisusb_setreg(struct sisusb_usb_data *, int, u8); | ||
| 75 | extern int sisusb_getreg(struct sisusb_usb_data *, int, u8 *); | ||
| 76 | extern int sisusb_setidxreg(struct sisusb_usb_data *, int, u8, u8); | ||
| 77 | extern int sisusb_getidxreg(struct sisusb_usb_data *, int, u8, u8 *); | ||
| 78 | extern int sisusb_setidxregor(struct sisusb_usb_data *, int, u8, u8); | ||
| 79 | extern int sisusb_setidxregand(struct sisusb_usb_data *, int, u8, u8); | ||
| 80 | extern int sisusb_setidxregandor(struct sisusb_usb_data *, int, u8, u8, u8); | ||
| 81 | |||
| 82 | extern int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); | ||
| 83 | extern int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data); | ||
| 84 | extern int sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data); | ||
| 85 | extern int sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data); | ||
| 86 | extern int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, | ||
| 87 | u32 dest, int length, size_t *bytes_written); | ||
| 88 | |||
| 89 | extern void sisusb_delete(struct kref *kref); | ||
| 90 | extern int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); | ||
| 91 | |||
| 92 | extern int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); | ||
| 93 | 76 | ||
| 94 | #define sisusbcon_writew(val, addr) (*(addr) = (val)) | 77 | #define sisusbcon_writew(val, addr) (*(addr) = (val)) |
| 95 | #define sisusbcon_readw(addr) (*(addr)) | 78 | #define sisusbcon_readw(addr) (*(addr)) |
| @@ -102,8 +85,6 @@ static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES]; | |||
| 102 | /* Forward declaration */ | 85 | /* Forward declaration */ |
| 103 | static const struct consw sisusb_con; | 86 | static const struct consw sisusb_con; |
| 104 | 87 | ||
| 105 | extern struct semaphore disconnect_sem; | ||
| 106 | |||
| 107 | static inline void | 88 | static inline void |
| 108 | sisusbcon_memsetw(u16 *s, u16 c, unsigned int count) | 89 | sisusbcon_memsetw(u16 *s, u16 c, unsigned int count) |
| 109 | { | 90 | { |
| @@ -194,11 +175,11 @@ sisusb_get_sisusb_lock_and_check(unsigned short console) | |||
| 194 | if (!(sisusb = sisusb_get_sisusb(console))) | 175 | if (!(sisusb = sisusb_get_sisusb(console))) |
| 195 | return NULL; | 176 | return NULL; |
| 196 | 177 | ||
| 197 | down(&sisusb->lock); | 178 | mutex_lock(&sisusb->lock); |
| 198 | 179 | ||
| 199 | if (!sisusb_sisusb_valid(sisusb) || | 180 | if (!sisusb_sisusb_valid(sisusb) || |
| 200 | !sisusb->havethisconsole[console]) { | 181 | !sisusb->havethisconsole[console]) { |
| 201 | up(&sisusb->lock); | 182 | mutex_unlock(&sisusb->lock); |
| 202 | return NULL; | 183 | return NULL; |
| 203 | } | 184 | } |
| 204 | 185 | ||
| @@ -236,18 +217,18 @@ sisusbcon_init(struct vc_data *c, int init) | |||
| 236 | * are set up/restored. | 217 | * are set up/restored. |
| 237 | */ | 218 | */ |
| 238 | 219 | ||
| 239 | down(&disconnect_sem); | 220 | mutex_lock(&disconnect_mutex); |
| 240 | 221 | ||
| 241 | if (!(sisusb = sisusb_get_sisusb(c->vc_num))) { | 222 | if (!(sisusb = sisusb_get_sisusb(c->vc_num))) { |
| 242 | up(&disconnect_sem); | 223 | mutex_unlock(&disconnect_mutex); |
| 243 | return; | 224 | return; |
| 244 | } | 225 | } |
| 245 | 226 | ||
| 246 | down(&sisusb->lock); | 227 | mutex_lock(&sisusb->lock); |
| 247 | 228 | ||
| 248 | if (!sisusb_sisusb_valid(sisusb)) { | 229 | if (!sisusb_sisusb_valid(sisusb)) { |
| 249 | up(&sisusb->lock); | 230 | mutex_unlock(&sisusb->lock); |
| 250 | up(&disconnect_sem); | 231 | mutex_unlock(&disconnect_mutex); |
| 251 | return; | 232 | return; |
| 252 | } | 233 | } |
| 253 | 234 | ||
| @@ -284,9 +265,9 @@ sisusbcon_init(struct vc_data *c, int init) | |||
| 284 | if (!*c->vc_uni_pagedir_loc) | 265 | if (!*c->vc_uni_pagedir_loc) |
| 285 | con_set_default_unimap(c); | 266 | con_set_default_unimap(c); |
| 286 | 267 | ||
| 287 | up(&sisusb->lock); | 268 | mutex_unlock(&sisusb->lock); |
| 288 | 269 | ||
| 289 | up(&disconnect_sem); | 270 | mutex_unlock(&disconnect_mutex); |
| 290 | 271 | ||
| 291 | if (init) { | 272 | if (init) { |
| 292 | c->vc_cols = cols; | 273 | c->vc_cols = cols; |
| @@ -306,14 +287,14 @@ sisusbcon_deinit(struct vc_data *c) | |||
| 306 | * and others, ie not under our control. | 287 | * and others, ie not under our control. |
| 307 | */ | 288 | */ |
| 308 | 289 | ||
| 309 | down(&disconnect_sem); | 290 | mutex_lock(&disconnect_mutex); |
| 310 | 291 | ||
| 311 | if (!(sisusb = sisusb_get_sisusb(c->vc_num))) { | 292 | if (!(sisusb = sisusb_get_sisusb(c->vc_num))) { |
| 312 | up(&disconnect_sem); | 293 | mutex_unlock(&disconnect_mutex); |
| 313 | return; | 294 | return; |
| 314 | } | 295 | } |
| 315 | 296 | ||
| 316 | down(&sisusb->lock); | 297 | mutex_lock(&sisusb->lock); |
| 317 | 298 | ||
| 318 | /* Clear ourselves in mysisusbs */ | 299 | /* Clear ourselves in mysisusbs */ |
| 319 | mysisusbs[c->vc_num] = NULL; | 300 | mysisusbs[c->vc_num] = NULL; |
| @@ -332,12 +313,12 @@ sisusbcon_deinit(struct vc_data *c) | |||
| 332 | } | 313 | } |
| 333 | } | 314 | } |
| 334 | 315 | ||
| 335 | up(&sisusb->lock); | 316 | mutex_unlock(&sisusb->lock); |
| 336 | 317 | ||
| 337 | /* decrement the usage count on our sisusb */ | 318 | /* decrement the usage count on our sisusb */ |
| 338 | kref_put(&sisusb->kref, sisusb_delete); | 319 | kref_put(&sisusb->kref, sisusb_delete); |
| 339 | 320 | ||
| 340 | up(&disconnect_sem); | 321 | mutex_unlock(&disconnect_mutex); |
| 341 | } | 322 | } |
| 342 | 323 | ||
| 343 | /* interface routine */ | 324 | /* interface routine */ |
| @@ -417,7 +398,7 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) | |||
| 417 | #endif | 398 | #endif |
| 418 | 399 | ||
| 419 | if (sisusb_is_inactive(c, sisusb)) { | 400 | if (sisusb_is_inactive(c, sisusb)) { |
| 420 | up(&sisusb->lock); | 401 | mutex_unlock(&sisusb->lock); |
| 421 | return; | 402 | return; |
| 422 | } | 403 | } |
| 423 | 404 | ||
| @@ -425,7 +406,7 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x) | |||
| 425 | sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), | 406 | sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), |
| 426 | (u32)SISUSB_HADDR(x, y), 2, &written); | 407 | (u32)SISUSB_HADDR(x, y), 2, &written); |
| 427 | 408 | ||
| 428 | up(&sisusb->lock); | 409 | mutex_unlock(&sisusb->lock); |
| 429 | } | 410 | } |
| 430 | 411 | ||
| 431 | /* Interface routine */ | 412 | /* Interface routine */ |
| @@ -453,14 +434,14 @@ sisusbcon_putcs(struct vc_data *c, const unsigned short *s, | |||
| 453 | sisusbcon_writew(sisusbcon_readw(s++), dest++); | 434 | sisusbcon_writew(sisusbcon_readw(s++), dest++); |
| 454 | 435 | ||
| 455 | if (sisusb_is_inactive(c, sisusb)) { | 436 | if (sisusb_is_inactive(c, sisusb)) { |
| 456 | up(&sisusb->lock); | 437 | mutex_unlock(&sisusb->lock); |
| 457 | return; | 438 | return; |
| 458 | } | 439 | } |
| 459 | 440 | ||
| 460 | sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), | 441 | sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), |
| 461 | (u32)SISUSB_HADDR(x, y), count * 2, &written); | 442 | (u32)SISUSB_HADDR(x, y), count * 2, &written); |
| 462 | 443 | ||
| 463 | up(&sisusb->lock); | 444 | mutex_unlock(&sisusb->lock); |
| 464 | } | 445 | } |
| 465 | 446 | ||
| 466 | /* Interface routine */ | 447 | /* Interface routine */ |
| @@ -504,7 +485,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) | |||
| 504 | } | 485 | } |
| 505 | 486 | ||
| 506 | if (sisusb_is_inactive(c, sisusb)) { | 487 | if (sisusb_is_inactive(c, sisusb)) { |
| 507 | up(&sisusb->lock); | 488 | mutex_unlock(&sisusb->lock); |
| 508 | return; | 489 | return; |
| 509 | } | 490 | } |
| 510 | 491 | ||
| @@ -514,7 +495,7 @@ sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) | |||
| 514 | sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), | 495 | sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), |
| 515 | (u32)SISUSB_HADDR(x, y), length, &written); | 496 | (u32)SISUSB_HADDR(x, y), length, &written); |
| 516 | 497 | ||
| 517 | up(&sisusb->lock); | 498 | mutex_unlock(&sisusb->lock); |
| 518 | } | 499 | } |
| 519 | 500 | ||
| 520 | /* Interface routine */ | 501 | /* Interface routine */ |
| @@ -576,7 +557,7 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, | |||
| 576 | #endif | 557 | #endif |
| 577 | 558 | ||
| 578 | if (sisusb_is_inactive(c, sisusb)) { | 559 | if (sisusb_is_inactive(c, sisusb)) { |
| 579 | up(&sisusb->lock); | 560 | mutex_unlock(&sisusb->lock); |
| 580 | return; | 561 | return; |
| 581 | } | 562 | } |
| 582 | 563 | ||
| @@ -586,7 +567,7 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx, | |||
| 586 | sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), | 567 | sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), |
| 587 | (u32)SISUSB_HADDR(dx, dy), length, &written); | 568 | (u32)SISUSB_HADDR(dx, dy), length, &written); |
| 588 | 569 | ||
| 589 | up(&sisusb->lock); | 570 | mutex_unlock(&sisusb->lock); |
| 590 | } | 571 | } |
| 591 | 572 | ||
| 592 | /* interface routine */ | 573 | /* interface routine */ |
| @@ -609,7 +590,7 @@ sisusbcon_switch(struct vc_data *c) | |||
| 609 | 590 | ||
| 610 | /* Don't write to screen if in gfx mode */ | 591 | /* Don't write to screen if in gfx mode */ |
| 611 | if (sisusb_is_inactive(c, sisusb)) { | 592 | if (sisusb_is_inactive(c, sisusb)) { |
| 612 | up(&sisusb->lock); | 593 | mutex_unlock(&sisusb->lock); |
| 613 | return 0; | 594 | return 0; |
| 614 | } | 595 | } |
| 615 | 596 | ||
| @@ -618,7 +599,7 @@ sisusbcon_switch(struct vc_data *c) | |||
| 618 | * as origin. | 599 | * as origin. |
| 619 | */ | 600 | */ |
| 620 | if (c->vc_origin == (unsigned long)c->vc_screenbuf) { | 601 | if (c->vc_origin == (unsigned long)c->vc_screenbuf) { |
| 621 | up(&sisusb->lock); | 602 | mutex_unlock(&sisusb->lock); |
| 622 | printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n"); | 603 | printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n"); |
| 623 | return 0; | 604 | return 0; |
| 624 | } | 605 | } |
| @@ -635,7 +616,7 @@ sisusbcon_switch(struct vc_data *c) | |||
| 635 | (u32)SISUSB_HADDR(0, 0), | 616 | (u32)SISUSB_HADDR(0, 0), |
| 636 | length, &written); | 617 | length, &written); |
| 637 | 618 | ||
| 638 | up(&sisusb->lock); | 619 | mutex_unlock(&sisusb->lock); |
| 639 | 620 | ||
| 640 | return 0; | 621 | return 0; |
| 641 | } | 622 | } |
| @@ -657,7 +638,7 @@ sisusbcon_save_screen(struct vc_data *c) | |||
| 657 | /* sisusb->lock is down */ | 638 | /* sisusb->lock is down */ |
| 658 | 639 | ||
| 659 | if (sisusb_is_inactive(c, sisusb)) { | 640 | if (sisusb_is_inactive(c, sisusb)) { |
| 660 | up(&sisusb->lock); | 641 | mutex_unlock(&sisusb->lock); |
| 661 | return; | 642 | return; |
| 662 | } | 643 | } |
| 663 | 644 | ||
| @@ -669,7 +650,7 @@ sisusbcon_save_screen(struct vc_data *c) | |||
| 669 | sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, | 650 | sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, |
| 670 | length); | 651 | length); |
| 671 | 652 | ||
| 672 | up(&sisusb->lock); | 653 | mutex_unlock(&sisusb->lock); |
| 673 | } | 654 | } |
| 674 | 655 | ||
| 675 | /* interface routine */ | 656 | /* interface routine */ |
| @@ -690,7 +671,7 @@ sisusbcon_set_palette(struct vc_data *c, unsigned char *table) | |||
| 690 | /* sisusb->lock is down */ | 671 | /* sisusb->lock is down */ |
| 691 | 672 | ||
| 692 | if (sisusb_is_inactive(c, sisusb)) { | 673 | if (sisusb_is_inactive(c, sisusb)) { |
| 693 | up(&sisusb->lock); | 674 | mutex_unlock(&sisusb->lock); |
| 694 | return -EINVAL; | 675 | return -EINVAL; |
| 695 | } | 676 | } |
| 696 | 677 | ||
| @@ -705,7 +686,7 @@ sisusbcon_set_palette(struct vc_data *c, unsigned char *table) | |||
| 705 | break; | 686 | break; |
| 706 | } | 687 | } |
| 707 | 688 | ||
| 708 | up(&sisusb->lock); | 689 | mutex_unlock(&sisusb->lock); |
| 709 | 690 | ||
| 710 | return 0; | 691 | return 0; |
| 711 | } | 692 | } |
| @@ -728,7 +709,7 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) | |||
| 728 | sisusb->is_gfx = blank ? 1 : 0; | 709 | sisusb->is_gfx = blank ? 1 : 0; |
| 729 | 710 | ||
| 730 | if (sisusb_is_inactive(c, sisusb)) { | 711 | if (sisusb_is_inactive(c, sisusb)) { |
| 731 | up(&sisusb->lock); | 712 | mutex_unlock(&sisusb->lock); |
| 732 | return 0; | 713 | return 0; |
| 733 | } | 714 | } |
| 734 | 715 | ||
| @@ -777,7 +758,7 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) | |||
| 777 | cr63 = 0x40; | 758 | cr63 = 0x40; |
| 778 | break; | 759 | break; |
| 779 | default: | 760 | default: |
| 780 | up(&sisusb->lock); | 761 | mutex_unlock(&sisusb->lock); |
| 781 | return -EINVAL; | 762 | return -EINVAL; |
| 782 | } | 763 | } |
| 783 | 764 | ||
| @@ -788,7 +769,7 @@ sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) | |||
| 788 | 769 | ||
| 789 | } | 770 | } |
| 790 | 771 | ||
| 791 | up(&sisusb->lock); | 772 | mutex_unlock(&sisusb->lock); |
| 792 | 773 | ||
| 793 | return ret; | 774 | return ret; |
| 794 | } | 775 | } |
| @@ -809,7 +790,7 @@ sisusbcon_scrolldelta(struct vc_data *c, int lines) | |||
| 809 | /* sisusb->lock is down */ | 790 | /* sisusb->lock is down */ |
| 810 | 791 | ||
| 811 | if (sisusb_is_inactive(c, sisusb)) { | 792 | if (sisusb_is_inactive(c, sisusb)) { |
| 812 | up(&sisusb->lock); | 793 | mutex_unlock(&sisusb->lock); |
| 813 | return 0; | 794 | return 0; |
| 814 | } | 795 | } |
| 815 | 796 | ||
| @@ -849,7 +830,7 @@ sisusbcon_scrolldelta(struct vc_data *c, int lines) | |||
| 849 | 830 | ||
| 850 | sisusbcon_set_start_address(sisusb, c); | 831 | sisusbcon_set_start_address(sisusb, c); |
| 851 | 832 | ||
| 852 | up(&sisusb->lock); | 833 | mutex_unlock(&sisusb->lock); |
| 853 | 834 | ||
| 854 | return 1; | 835 | return 1; |
| 855 | } | 836 | } |
| @@ -867,7 +848,7 @@ sisusbcon_cursor(struct vc_data *c, int mode) | |||
| 867 | /* sisusb->lock is down */ | 848 | /* sisusb->lock is down */ |
| 868 | 849 | ||
| 869 | if (sisusb_is_inactive(c, sisusb)) { | 850 | if (sisusb_is_inactive(c, sisusb)) { |
| 870 | up(&sisusb->lock); | 851 | mutex_unlock(&sisusb->lock); |
| 871 | return; | 852 | return; |
| 872 | } | 853 | } |
| 873 | 854 | ||
| @@ -879,7 +860,7 @@ sisusbcon_cursor(struct vc_data *c, int mode) | |||
| 879 | if (mode == CM_ERASE) { | 860 | if (mode == CM_ERASE) { |
| 880 | sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20); | 861 | sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20); |
| 881 | sisusb->sisusb_cursor_size_to = -1; | 862 | sisusb->sisusb_cursor_size_to = -1; |
| 882 | up(&sisusb->lock); | 863 | mutex_unlock(&sisusb->lock); |
| 883 | return; | 864 | return; |
| 884 | } | 865 | } |
| 885 | 866 | ||
| @@ -919,7 +900,7 @@ sisusbcon_cursor(struct vc_data *c, int mode) | |||
| 919 | sisusb->sisusb_cursor_size_to = to; | 900 | sisusb->sisusb_cursor_size_to = to; |
| 920 | } | 901 | } |
| 921 | 902 | ||
| 922 | up(&sisusb->lock); | 903 | mutex_unlock(&sisusb->lock); |
| 923 | } | 904 | } |
| 924 | 905 | ||
| 925 | static int | 906 | static int |
| @@ -961,7 +942,7 @@ sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, | |||
| 961 | sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), | 942 | sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), |
| 962 | (u32)SISUSB_HADDR(0, t), length, &written); | 943 | (u32)SISUSB_HADDR(0, t), length, &written); |
| 963 | 944 | ||
| 964 | up(&sisusb->lock); | 945 | mutex_unlock(&sisusb->lock); |
| 965 | 946 | ||
| 966 | return 1; | 947 | return 1; |
| 967 | } | 948 | } |
| @@ -994,7 +975,7 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines) | |||
| 994 | /* sisusb->lock is down */ | 975 | /* sisusb->lock is down */ |
| 995 | 976 | ||
| 996 | if (sisusb_is_inactive(c, sisusb)) { | 977 | if (sisusb_is_inactive(c, sisusb)) { |
| 997 | up(&sisusb->lock); | 978 | mutex_unlock(&sisusb->lock); |
| 998 | return 0; | 979 | return 0; |
| 999 | } | 980 | } |
| 1000 | 981 | ||
| @@ -1084,7 +1065,7 @@ sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines) | |||
| 1084 | 1065 | ||
| 1085 | c->vc_pos = c->vc_pos - oldorigin + c->vc_origin; | 1066 | c->vc_pos = c->vc_pos - oldorigin + c->vc_origin; |
| 1086 | 1067 | ||
| 1087 | up(&sisusb->lock); | 1068 | mutex_unlock(&sisusb->lock); |
| 1088 | 1069 | ||
| 1089 | return 1; | 1070 | return 1; |
| 1090 | } | 1071 | } |
| @@ -1106,7 +1087,7 @@ sisusbcon_set_origin(struct vc_data *c) | |||
| 1106 | /* sisusb->lock is down */ | 1087 | /* sisusb->lock is down */ |
| 1107 | 1088 | ||
| 1108 | if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) { | 1089 | if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) { |
| 1109 | up(&sisusb->lock); | 1090 | mutex_unlock(&sisusb->lock); |
| 1110 | return 0; | 1091 | return 0; |
| 1111 | } | 1092 | } |
| 1112 | 1093 | ||
| @@ -1116,7 +1097,7 @@ sisusbcon_set_origin(struct vc_data *c) | |||
| 1116 | 1097 | ||
| 1117 | sisusb->con_rolled_over = 0; | 1098 | sisusb->con_rolled_over = 0; |
| 1118 | 1099 | ||
| 1119 | up(&sisusb->lock); | 1100 | mutex_unlock(&sisusb->lock); |
| 1120 | 1101 | ||
| 1121 | return 1; | 1102 | return 1; |
| 1122 | } | 1103 | } |
| @@ -1133,7 +1114,7 @@ sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows) | |||
| 1133 | 1114 | ||
| 1134 | fh = sisusb->current_font_height; | 1115 | fh = sisusb->current_font_height; |
| 1135 | 1116 | ||
| 1136 | up(&sisusb->lock); | 1117 | mutex_unlock(&sisusb->lock); |
| 1137 | 1118 | ||
| 1138 | /* We are quite unflexible as regards resizing. The vt code | 1119 | /* We are quite unflexible as regards resizing. The vt code |
| 1139 | * handles sizes where the line length isn't equal the pitch | 1120 | * handles sizes where the line length isn't equal the pitch |
| @@ -1167,7 +1148,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, | |||
| 1167 | 1148 | ||
| 1168 | if ((slot != 0 && slot != 2) || !fh) { | 1149 | if ((slot != 0 && slot != 2) || !fh) { |
| 1169 | if (uplock) | 1150 | if (uplock) |
| 1170 | up(&sisusb->lock); | 1151 | mutex_unlock(&sisusb->lock); |
| 1171 | return -EINVAL; | 1152 | return -EINVAL; |
| 1172 | } | 1153 | } |
| 1173 | 1154 | ||
| @@ -1327,7 +1308,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, | |||
| 1327 | } | 1308 | } |
| 1328 | 1309 | ||
| 1329 | if (uplock) | 1310 | if (uplock) |
| 1330 | up(&sisusb->lock); | 1311 | mutex_unlock(&sisusb->lock); |
| 1331 | 1312 | ||
| 1332 | if (dorecalc && c) { | 1313 | if (dorecalc && c) { |
| 1333 | int i, rows = c->vc_scan_lines / fh; | 1314 | int i, rows = c->vc_scan_lines / fh; |
| @@ -1351,7 +1332,7 @@ sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, | |||
| 1351 | 1332 | ||
| 1352 | font_op_error: | 1333 | font_op_error: |
| 1353 | if (uplock) | 1334 | if (uplock) |
| 1354 | up(&sisusb->lock); | 1335 | mutex_unlock(&sisusb->lock); |
| 1355 | 1336 | ||
| 1356 | return -EIO; | 1337 | return -EIO; |
| 1357 | } | 1338 | } |
| @@ -1417,19 +1398,19 @@ sisusbcon_font_get(struct vc_data *c, struct console_font *font) | |||
| 1417 | font->charcount = 256; | 1398 | font->charcount = 256; |
| 1418 | 1399 | ||
| 1419 | if (!font->data) { | 1400 | if (!font->data) { |
| 1420 | up(&sisusb->lock); | 1401 | mutex_unlock(&sisusb->lock); |
| 1421 | return 0; | 1402 | return 0; |
| 1422 | } | 1403 | } |
| 1423 | 1404 | ||
| 1424 | if (!sisusb->font_backup) { | 1405 | if (!sisusb->font_backup) { |
| 1425 | up(&sisusb->lock); | 1406 | mutex_unlock(&sisusb->lock); |
| 1426 | return -ENODEV; | 1407 | return -ENODEV; |
| 1427 | } | 1408 | } |
| 1428 | 1409 | ||
| 1429 | /* Copy 256 chars only, like vgacon */ | 1410 | /* Copy 256 chars only, like vgacon */ |
| 1430 | memcpy(font->data, sisusb->font_backup, 256 * 32); | 1411 | memcpy(font->data, sisusb->font_backup, 256 * 32); |
| 1431 | 1412 | ||
| 1432 | up(&sisusb->lock); | 1413 | mutex_unlock(&sisusb->lock); |
| 1433 | 1414 | ||
| 1434 | return 0; | 1415 | return 0; |
| 1435 | } | 1416 | } |
| @@ -1486,7 +1467,7 @@ static int sisusbdummycon_dummy(void) | |||
| 1486 | 1467 | ||
| 1487 | #define SISUSBCONDUMMY (void *)sisusbdummycon_dummy | 1468 | #define SISUSBCONDUMMY (void *)sisusbdummycon_dummy |
| 1488 | 1469 | ||
| 1489 | const struct consw sisusb_dummy_con = { | 1470 | static const struct consw sisusb_dummy_con = { |
| 1490 | .owner = THIS_MODULE, | 1471 | .owner = THIS_MODULE, |
| 1491 | .con_startup = sisusbdummycon_startup, | 1472 | .con_startup = sisusbdummycon_startup, |
| 1492 | .con_init = sisusbdummycon_init, | 1473 | .con_init = sisusbdummycon_init, |
| @@ -1512,14 +1493,14 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) | |||
| 1512 | { | 1493 | { |
| 1513 | int i, ret, minor = sisusb->minor; | 1494 | int i, ret, minor = sisusb->minor; |
| 1514 | 1495 | ||
| 1515 | down(&disconnect_sem); | 1496 | mutex_lock(&disconnect_mutex); |
| 1516 | 1497 | ||
| 1517 | down(&sisusb->lock); | 1498 | mutex_lock(&sisusb->lock); |
| 1518 | 1499 | ||
| 1519 | /* Erm.. that should not happen */ | 1500 | /* Erm.. that should not happen */ |
| 1520 | if (sisusb->haveconsole || !sisusb->SiS_Pr) { | 1501 | if (sisusb->haveconsole || !sisusb->SiS_Pr) { |
| 1521 | up(&sisusb->lock); | 1502 | mutex_unlock(&sisusb->lock); |
| 1522 | up(&disconnect_sem); | 1503 | mutex_unlock(&disconnect_mutex); |
| 1523 | return 1; | 1504 | return 1; |
| 1524 | } | 1505 | } |
| 1525 | 1506 | ||
| @@ -1529,15 +1510,15 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) | |||
| 1529 | if (first > last || | 1510 | if (first > last || |
| 1530 | first > MAX_NR_CONSOLES || | 1511 | first > MAX_NR_CONSOLES || |
| 1531 | last > MAX_NR_CONSOLES) { | 1512 | last > MAX_NR_CONSOLES) { |
| 1532 | up(&sisusb->lock); | 1513 | mutex_unlock(&sisusb->lock); |
| 1533 | up(&disconnect_sem); | 1514 | mutex_unlock(&disconnect_mutex); |
| 1534 | return 1; | 1515 | return 1; |
| 1535 | } | 1516 | } |
| 1536 | 1517 | ||
| 1537 | /* If gfxcore not initialized or no consoles given, quit graciously */ | 1518 | /* If gfxcore not initialized or no consoles given, quit graciously */ |
| 1538 | if (!sisusb->gfxinit || first < 1 || last < 1) { | 1519 | if (!sisusb->gfxinit || first < 1 || last < 1) { |
| 1539 | up(&sisusb->lock); | 1520 | mutex_unlock(&sisusb->lock); |
| 1540 | up(&disconnect_sem); | 1521 | mutex_unlock(&disconnect_mutex); |
| 1541 | return 0; | 1522 | return 0; |
| 1542 | } | 1523 | } |
| 1543 | 1524 | ||
| @@ -1547,8 +1528,8 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) | |||
| 1547 | 1528 | ||
| 1548 | /* Set up text mode (and upload default font) */ | 1529 | /* Set up text mode (and upload default font) */ |
| 1549 | if (sisusb_reset_text_mode(sisusb, 1)) { | 1530 | if (sisusb_reset_text_mode(sisusb, 1)) { |
| 1550 | up(&sisusb->lock); | 1531 | mutex_unlock(&sisusb->lock); |
| 1551 | up(&disconnect_sem); | 1532 | mutex_unlock(&disconnect_mutex); |
| 1552 | printk(KERN_ERR | 1533 | printk(KERN_ERR |
| 1553 | "sisusbvga[%d]: Failed to set up text mode\n", | 1534 | "sisusbvga[%d]: Failed to set up text mode\n", |
| 1554 | minor); | 1535 | minor); |
| @@ -1571,16 +1552,16 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) | |||
| 1571 | 1552 | ||
| 1572 | /* Allocate screen buffer */ | 1553 | /* Allocate screen buffer */ |
| 1573 | if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { | 1554 | if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { |
| 1574 | up(&sisusb->lock); | 1555 | mutex_unlock(&sisusb->lock); |
| 1575 | up(&disconnect_sem); | 1556 | mutex_unlock(&disconnect_mutex); |
| 1576 | printk(KERN_ERR | 1557 | printk(KERN_ERR |
| 1577 | "sisusbvga[%d]: Failed to allocate screen buffer\n", | 1558 | "sisusbvga[%d]: Failed to allocate screen buffer\n", |
| 1578 | minor); | 1559 | minor); |
| 1579 | return 1; | 1560 | return 1; |
| 1580 | } | 1561 | } |
| 1581 | 1562 | ||
| 1582 | up(&sisusb->lock); | 1563 | mutex_unlock(&sisusb->lock); |
| 1583 | up(&disconnect_sem); | 1564 | mutex_unlock(&disconnect_mutex); |
| 1584 | 1565 | ||
| 1585 | /* Now grab the desired console(s) */ | 1566 | /* Now grab the desired console(s) */ |
| 1586 | ret = take_over_console(&sisusb_con, first - 1, last - 1, 0); | 1567 | ret = take_over_console(&sisusb_con, first - 1, last - 1, 0); |
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index 044fa4482f9f..968f0d38cff7 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c | |||
| @@ -74,6 +74,7 @@ SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) | |||
| 74 | /* HELPER: Get ModeID */ | 74 | /* HELPER: Get ModeID */ |
| 75 | /*********************************************/ | 75 | /*********************************************/ |
| 76 | 76 | ||
| 77 | #if 0 | ||
| 77 | unsigned short | 78 | unsigned short |
| 78 | SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) | 79 | SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) |
| 79 | { | 80 | { |
| @@ -157,6 +158,7 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth) | |||
| 157 | 158 | ||
| 158 | return ModeIndex; | 159 | return ModeIndex; |
| 159 | } | 160 | } |
| 161 | #endif /* 0 */ | ||
| 160 | 162 | ||
| 161 | /*********************************************/ | 163 | /*********************************************/ |
| 162 | /* HELPER: SetReg, GetReg */ | 164 | /* HELPER: SetReg, GetReg */ |
| @@ -233,7 +235,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr) | |||
| 233 | /* HELPER: Init Port Addresses */ | 235 | /* HELPER: Init Port Addresses */ |
| 234 | /*********************************************/ | 236 | /*********************************************/ |
| 235 | 237 | ||
| 236 | void | 238 | static void |
| 237 | SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) | 239 | SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) |
| 238 | { | 240 | { |
| 239 | SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; | 241 | SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; |
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h index 5b11577835c8..f05f83268af4 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.h +++ b/drivers/usb/misc/sisusbvga/sisusb_init.h | |||
| @@ -690,7 +690,7 @@ static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = | |||
| 690 | 0x41}} /* 0x54 */ | 690 | 0x41}} /* 0x54 */ |
| 691 | }; | 691 | }; |
| 692 | 692 | ||
| 693 | static struct SiS_VCLKData SiSUSB_VCLKData[] = | 693 | static const struct SiS_VCLKData SiSUSB_VCLKData[] = |
| 694 | { | 694 | { |
| 695 | { 0x1b,0xe1, 25}, /* 0x00 */ | 695 | { 0x1b,0xe1, 25}, /* 0x00 */ |
| 696 | { 0x4e,0xe4, 28}, /* 0x01 */ | 696 | { 0x4e,0xe4, 28}, /* 0x01 */ |
| @@ -808,8 +808,8 @@ static struct SiS_VCLKData SiSUSB_VCLKData[] = | |||
| 808 | { 0x2b,0xc2, 35} /* 0x71 768@576@60 */ | 808 | { 0x2b,0xc2, 35} /* 0x71 768@576@60 */ |
| 809 | }; | 809 | }; |
| 810 | 810 | ||
| 811 | void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr); | 811 | extern struct mutex disconnect_mutex; |
| 812 | unsigned short SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth); | 812 | |
| 813 | int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); | 813 | int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); |
| 814 | int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); | 814 | int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); |
| 815 | 815 | ||
| @@ -826,5 +826,19 @@ extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, | |||
| 826 | extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, | 826 | extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, |
| 827 | u8 idx, u8 myand); | 827 | u8 idx, u8 myand); |
| 828 | 828 | ||
| 829 | void sisusb_delete(struct kref *kref); | ||
| 830 | int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); | ||
| 831 | int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data); | ||
| 832 | int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, | ||
| 833 | u32 dest, int length, size_t *bytes_written); | ||
| 834 | int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); | ||
| 835 | int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, | ||
| 836 | u8 *arg, int cmapsz, int ch512, int dorecalc, | ||
| 837 | struct vc_data *c, int fh, int uplock); | ||
| 838 | void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location); | ||
| 839 | int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last); | ||
| 840 | void sisusb_console_exit(struct sisusb_usb_data *sisusb); | ||
| 841 | void sisusb_init_concode(void); | ||
| 842 | |||
| 829 | #endif | 843 | #endif |
| 830 | 844 | ||
diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h index 94edd4726c42..f325ecb29a61 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h | |||
| @@ -161,7 +161,7 @@ struct SiS_Private | |||
| 161 | const struct SiS_Ext *SiS_EModeIDTable; | 161 | const struct SiS_Ext *SiS_EModeIDTable; |
| 162 | const struct SiS_Ext2 *SiS_RefIndex; | 162 | const struct SiS_Ext2 *SiS_RefIndex; |
| 163 | const struct SiS_CRT1Table *SiS_CRT1Table; | 163 | const struct SiS_CRT1Table *SiS_CRT1Table; |
| 164 | struct SiS_VCLKData *SiS_VCLKData; | 164 | const struct SiS_VCLKData *SiS_VCLKData; |
| 165 | const struct SiS_ModeResInfo *SiS_ModeResInfo; | 165 | const struct SiS_ModeResInfo *SiS_ModeResInfo; |
| 166 | }; | 166 | }; |
| 167 | 167 | ||
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index ccc5e8238bd8..81ba14c73dc7 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c | |||
| @@ -802,7 +802,9 @@ error: | |||
| 802 | 802 | ||
| 803 | if (u == urb || !u->dev) | 803 | if (u == urb || !u->dev) |
| 804 | continue; | 804 | continue; |
| 805 | spin_unlock(&ctx->lock); | ||
| 805 | status = usb_unlink_urb (u); | 806 | status = usb_unlink_urb (u); |
| 807 | spin_lock(&ctx->lock); | ||
| 806 | switch (status) { | 808 | switch (status) { |
| 807 | case -EINPROGRESS: | 809 | case -EINPROGRESS: |
| 808 | case -EBUSY: | 810 | case -EBUSY: |
| @@ -1335,7 +1337,9 @@ struct iso_context { | |||
| 1335 | unsigned pending; | 1337 | unsigned pending; |
| 1336 | spinlock_t lock; | 1338 | spinlock_t lock; |
| 1337 | struct completion done; | 1339 | struct completion done; |
| 1340 | int submit_error; | ||
| 1338 | unsigned long errors; | 1341 | unsigned long errors; |
| 1342 | unsigned long packet_count; | ||
| 1339 | struct usbtest_dev *dev; | 1343 | struct usbtest_dev *dev; |
| 1340 | }; | 1344 | }; |
| 1341 | 1345 | ||
| @@ -1346,10 +1350,14 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs) | |||
| 1346 | spin_lock(&ctx->lock); | 1350 | spin_lock(&ctx->lock); |
| 1347 | ctx->count--; | 1351 | ctx->count--; |
| 1348 | 1352 | ||
| 1353 | ctx->packet_count += urb->number_of_packets; | ||
| 1349 | if (urb->error_count > 0) | 1354 | if (urb->error_count > 0) |
| 1350 | ctx->errors += urb->error_count; | 1355 | ctx->errors += urb->error_count; |
| 1356 | else if (urb->status != 0) | ||
| 1357 | ctx->errors += urb->number_of_packets; | ||
| 1351 | 1358 | ||
| 1352 | if (urb->status == 0 && ctx->count > (ctx->pending - 1)) { | 1359 | if (urb->status == 0 && ctx->count > (ctx->pending - 1) |
| 1360 | && !ctx->submit_error) { | ||
| 1353 | int status = usb_submit_urb (urb, GFP_ATOMIC); | 1361 | int status = usb_submit_urb (urb, GFP_ATOMIC); |
| 1354 | switch (status) { | 1362 | switch (status) { |
| 1355 | case 0: | 1363 | case 0: |
| @@ -1360,6 +1368,8 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs) | |||
| 1360 | status); | 1368 | status); |
| 1361 | /* FALLTHROUGH */ | 1369 | /* FALLTHROUGH */ |
| 1362 | case -ENODEV: /* disconnected */ | 1370 | case -ENODEV: /* disconnected */ |
| 1371 | case -ESHUTDOWN: /* endpoint disabled */ | ||
| 1372 | ctx->submit_error = 1; | ||
| 1363 | break; | 1373 | break; |
| 1364 | } | 1374 | } |
| 1365 | } | 1375 | } |
| @@ -1369,8 +1379,8 @@ static void iso_callback (struct urb *urb, struct pt_regs *regs) | |||
| 1369 | if (ctx->pending == 0) { | 1379 | if (ctx->pending == 0) { |
| 1370 | if (ctx->errors) | 1380 | if (ctx->errors) |
| 1371 | dev_dbg (&ctx->dev->intf->dev, | 1381 | dev_dbg (&ctx->dev->intf->dev, |
| 1372 | "iso test, %lu errors\n", | 1382 | "iso test, %lu errors out of %lu\n", |
| 1373 | ctx->errors); | 1383 | ctx->errors, ctx->packet_count); |
| 1374 | complete (&ctx->done); | 1384 | complete (&ctx->done); |
| 1375 | } | 1385 | } |
| 1376 | done: | 1386 | done: |
| @@ -1431,15 +1441,14 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, | |||
| 1431 | struct usb_device *udev; | 1441 | struct usb_device *udev; |
| 1432 | unsigned i; | 1442 | unsigned i; |
| 1433 | unsigned long packets = 0; | 1443 | unsigned long packets = 0; |
| 1434 | int status; | 1444 | int status = 0; |
| 1435 | struct urb *urbs[10]; /* FIXME no limit */ | 1445 | struct urb *urbs[10]; /* FIXME no limit */ |
| 1436 | 1446 | ||
| 1437 | if (param->sglen > 10) | 1447 | if (param->sglen > 10) |
| 1438 | return -EDOM; | 1448 | return -EDOM; |
| 1439 | 1449 | ||
| 1450 | memset(&context, 0, sizeof context); | ||
| 1440 | context.count = param->iterations * param->sglen; | 1451 | context.count = param->iterations * param->sglen; |
| 1441 | context.pending = param->sglen; | ||
| 1442 | context.errors = 0; | ||
| 1443 | context.dev = dev; | 1452 | context.dev = dev; |
| 1444 | init_completion (&context.done); | 1453 | init_completion (&context.done); |
| 1445 | spin_lock_init (&context.lock); | 1454 | spin_lock_init (&context.lock); |
| @@ -1471,6 +1480,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, | |||
| 1471 | 1480 | ||
| 1472 | spin_lock_irq (&context.lock); | 1481 | spin_lock_irq (&context.lock); |
| 1473 | for (i = 0; i < param->sglen; i++) { | 1482 | for (i = 0; i < param->sglen; i++) { |
| 1483 | ++context.pending; | ||
| 1474 | status = usb_submit_urb (urbs [i], SLAB_ATOMIC); | 1484 | status = usb_submit_urb (urbs [i], SLAB_ATOMIC); |
| 1475 | if (status < 0) { | 1485 | if (status < 0) { |
| 1476 | ERROR (dev, "submit iso[%d], error %d\n", i, status); | 1486 | ERROR (dev, "submit iso[%d], error %d\n", i, status); |
| @@ -1481,12 +1491,26 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, | |||
| 1481 | 1491 | ||
| 1482 | simple_free_urb (urbs [i]); | 1492 | simple_free_urb (urbs [i]); |
| 1483 | context.pending--; | 1493 | context.pending--; |
| 1494 | context.submit_error = 1; | ||
| 1495 | break; | ||
| 1484 | } | 1496 | } |
| 1485 | } | 1497 | } |
| 1486 | spin_unlock_irq (&context.lock); | 1498 | spin_unlock_irq (&context.lock); |
| 1487 | 1499 | ||
| 1488 | wait_for_completion (&context.done); | 1500 | wait_for_completion (&context.done); |
| 1489 | return 0; | 1501 | |
| 1502 | /* | ||
| 1503 | * Isochronous transfers are expected to fail sometimes. As an | ||
| 1504 | * arbitrary limit, we will report an error if any submissions | ||
| 1505 | * fail or if the transfer failure rate is > 10%. | ||
| 1506 | */ | ||
| 1507 | if (status != 0) | ||
| 1508 | ; | ||
| 1509 | else if (context.submit_error) | ||
| 1510 | status = -EACCES; | ||
| 1511 | else if (context.errors > context.packet_count / 10) | ||
| 1512 | status = -EIO; | ||
| 1513 | return status; | ||
| 1490 | 1514 | ||
| 1491 | fail: | 1515 | fail: |
| 1492 | for (i = 0; i < param->sglen; i++) { | 1516 | for (i = 0; i < param->sglen; i++) { |
diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c index 0a1367b760a0..ddcfc01e77a0 100644 --- a/drivers/usb/mon/mon_dma.c +++ b/drivers/usb/mon/mon_dma.c | |||
| @@ -13,7 +13,10 @@ | |||
| 13 | #include <linux/usb.h> /* Only needed for declarations in usb_mon.h */ | 13 | #include <linux/usb.h> /* Only needed for declarations in usb_mon.h */ |
| 14 | #include "usb_mon.h" | 14 | #include "usb_mon.h" |
| 15 | 15 | ||
| 16 | #ifdef __i386__ /* CONFIG_ARCH_I386 does not exit */ | 16 | /* |
| 17 | * PC-compatibles, are, fortunately, sufficiently cache-coherent for this. | ||
| 18 | */ | ||
| 19 | #if defined(__i386__) || defined(__x86_64__) /* CONFIG_ARCH_I386 doesn't exit */ | ||
| 17 | #define MON_HAS_UNMAP 1 | 20 | #define MON_HAS_UNMAP 1 |
| 18 | 21 | ||
| 19 | #define phys_to_page(phys) pfn_to_page((phys) >> PAGE_SHIFT) | 22 | #define phys_to_page(phys) pfn_to_page((phys) >> PAGE_SHIFT) |
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 6ecc27302211..275a66f83058 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c | |||
| @@ -97,6 +97,7 @@ static void mon_submit(struct usb_bus *ubus, struct urb *urb) | |||
| 97 | if (mbus->nreaders == 0) | 97 | if (mbus->nreaders == 0) |
| 98 | goto out_locked; | 98 | goto out_locked; |
| 99 | 99 | ||
| 100 | mbus->cnt_events++; | ||
| 100 | list_for_each (pos, &mbus->r_list) { | 101 | list_for_each (pos, &mbus->r_list) { |
| 101 | r = list_entry(pos, struct mon_reader, r_link); | 102 | r = list_entry(pos, struct mon_reader, r_link); |
| 102 | r->rnf_submit(r->r_data, urb); | 103 | r->rnf_submit(r->r_data, urb); |
| @@ -113,20 +114,32 @@ out_unlocked: | |||
| 113 | 114 | ||
| 114 | /* | 115 | /* |
| 115 | */ | 116 | */ |
| 116 | static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int err) | 117 | static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) |
| 117 | { | 118 | { |
| 118 | struct mon_bus *mbus; | 119 | struct mon_bus *mbus; |
| 120 | unsigned long flags; | ||
| 121 | struct list_head *pos; | ||
| 122 | struct mon_reader *r; | ||
| 119 | 123 | ||
| 120 | mbus = ubus->mon_bus; | 124 | mbus = ubus->mon_bus; |
| 121 | if (mbus == NULL) | 125 | if (mbus == NULL) |
| 122 | goto out_unlocked; | 126 | goto out_unlocked; |
| 123 | 127 | ||
| 124 | /* | 128 | spin_lock_irqsave(&mbus->lock, flags); |
| 125 | * XXX Capture the error code and the 'E' event. | 129 | if (mbus->nreaders == 0) |
| 126 | */ | 130 | goto out_locked; |
| 127 | 131 | ||
| 132 | mbus->cnt_events++; | ||
| 133 | list_for_each (pos, &mbus->r_list) { | ||
| 134 | r = list_entry(pos, struct mon_reader, r_link); | ||
| 135 | r->rnf_error(r->r_data, urb, error); | ||
| 136 | } | ||
| 137 | |||
| 138 | spin_unlock_irqrestore(&mbus->lock, flags); | ||
| 128 | return; | 139 | return; |
| 129 | 140 | ||
| 141 | out_locked: | ||
| 142 | spin_unlock_irqrestore(&mbus->lock, flags); | ||
| 130 | out_unlocked: | 143 | out_unlocked: |
| 131 | return; | 144 | return; |
| 132 | } | 145 | } |
| @@ -152,6 +165,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) | |||
| 152 | } | 165 | } |
| 153 | 166 | ||
| 154 | spin_lock_irqsave(&mbus->lock, flags); | 167 | spin_lock_irqsave(&mbus->lock, flags); |
| 168 | mbus->cnt_events++; | ||
| 155 | list_for_each (pos, &mbus->r_list) { | 169 | list_for_each (pos, &mbus->r_list) { |
| 156 | r = list_entry(pos, struct mon_reader, r_link); | 170 | r = list_entry(pos, struct mon_reader, r_link); |
| 157 | r->rnf_complete(r->r_data, urb); | 171 | r->rnf_complete(r->r_data, urb); |
| @@ -163,7 +177,6 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb) | |||
| 163 | 177 | ||
| 164 | /* | 178 | /* |
| 165 | * Stop monitoring. | 179 | * Stop monitoring. |
| 166 | * Obviously this must be well locked, so no need to play with mb's. | ||
| 167 | */ | 180 | */ |
| 168 | static void mon_stop(struct mon_bus *mbus) | 181 | static void mon_stop(struct mon_bus *mbus) |
| 169 | { | 182 | { |
diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c index 6e4b165d070a..1fe01d994a79 100644 --- a/drivers/usb/mon/mon_stat.c +++ b/drivers/usb/mon/mon_stat.c | |||
| @@ -31,8 +31,8 @@ static int mon_stat_open(struct inode *inode, struct file *file) | |||
| 31 | mbus = inode->u.generic_ip; | 31 | mbus = inode->u.generic_ip; |
| 32 | 32 | ||
| 33 | sp->slen = snprintf(sp->str, STAT_BUF_SIZE, | 33 | sp->slen = snprintf(sp->str, STAT_BUF_SIZE, |
| 34 | "nreaders %d text_lost %u\n", | 34 | "nreaders %d events %u text_lost %u\n", |
| 35 | mbus->nreaders, mbus->cnt_text_lost); | 35 | mbus->nreaders, mbus->cnt_events, mbus->cnt_text_lost); |
| 36 | 36 | ||
| 37 | file->private_data = sp; | 37 | file->private_data = sp; |
| 38 | return 0; | 38 | return 0; |
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index ac043ec2b8dc..e02c1a30c4cd 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c | |||
| @@ -26,10 +26,13 @@ | |||
| 26 | 26 | ||
| 27 | /* | 27 | /* |
| 28 | * This limit exists to prevent OOMs when the user process stops reading. | 28 | * This limit exists to prevent OOMs when the user process stops reading. |
| 29 | * If usbmon were available to unprivileged processes, it might be open | ||
| 30 | * to a local DoS. But we have to keep to root in order to prevent | ||
| 31 | * password sniffing from HID devices. | ||
| 29 | */ | 32 | */ |
| 30 | #define EVENT_MAX 25 | 33 | #define EVENT_MAX (2*PAGE_SIZE / sizeof(struct mon_event_text)) |
| 31 | 34 | ||
| 32 | #define PRINTF_DFL 130 | 35 | #define PRINTF_DFL 160 |
| 33 | 36 | ||
| 34 | struct mon_event_text { | 37 | struct mon_event_text { |
| 35 | struct list_head e_link; | 38 | struct list_head e_link; |
| @@ -111,7 +114,7 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, | |||
| 111 | * number of corner cases, but it seems that the following is | 114 | * number of corner cases, but it seems that the following is |
| 112 | * more or less safe. | 115 | * more or less safe. |
| 113 | * | 116 | * |
| 114 | * We do not even try to look transfer_buffer, because it can | 117 | * We do not even try to look at transfer_buffer, because it can |
| 115 | * contain non-NULL garbage in case the upper level promised to | 118 | * contain non-NULL garbage in case the upper level promised to |
| 116 | * set DMA for the HCD. | 119 | * set DMA for the HCD. |
| 117 | */ | 120 | */ |
| @@ -179,6 +182,32 @@ static void mon_text_complete(void *data, struct urb *urb) | |||
| 179 | mon_text_event(rp, urb, 'C'); | 182 | mon_text_event(rp, urb, 'C'); |
| 180 | } | 183 | } |
| 181 | 184 | ||
| 185 | static void mon_text_error(void *data, struct urb *urb, int error) | ||
| 186 | { | ||
| 187 | struct mon_reader_text *rp = data; | ||
| 188 | struct mon_event_text *ep; | ||
| 189 | |||
| 190 | if (rp->nevents >= EVENT_MAX || | ||
| 191 | (ep = kmem_cache_alloc(rp->e_slab, SLAB_ATOMIC)) == NULL) { | ||
| 192 | rp->r.m_bus->cnt_text_lost++; | ||
| 193 | return; | ||
| 194 | } | ||
| 195 | |||
| 196 | ep->type = 'E'; | ||
| 197 | ep->pipe = urb->pipe; | ||
| 198 | ep->id = (unsigned long) urb; | ||
| 199 | ep->tstamp = 0; | ||
| 200 | ep->length = 0; | ||
| 201 | ep->status = error; | ||
| 202 | |||
| 203 | ep->setup_flag = '-'; | ||
| 204 | ep->data_flag = 'E'; | ||
| 205 | |||
| 206 | rp->nevents++; | ||
| 207 | list_add_tail(&ep->e_link, &rp->e_list); | ||
| 208 | wake_up(&rp->wait); | ||
| 209 | } | ||
| 210 | |||
| 182 | /* | 211 | /* |
| 183 | * Fetch next event from the circular buffer. | 212 | * Fetch next event from the circular buffer. |
| 184 | */ | 213 | */ |
| @@ -232,6 +261,7 @@ static int mon_text_open(struct inode *inode, struct file *file) | |||
| 232 | rp->r.m_bus = mbus; | 261 | rp->r.m_bus = mbus; |
| 233 | rp->r.r_data = rp; | 262 | rp->r.r_data = rp; |
| 234 | rp->r.rnf_submit = mon_text_submit; | 263 | rp->r.rnf_submit = mon_text_submit; |
| 264 | rp->r.rnf_error = mon_text_error; | ||
| 235 | rp->r.rnf_complete = mon_text_complete; | 265 | rp->r.rnf_complete = mon_text_complete; |
| 236 | 266 | ||
| 237 | snprintf(rp->slab_name, SLAB_NAME_SZ, "mon%dt_%lx", ubus->busnum, | 267 | snprintf(rp->slab_name, SLAB_NAME_SZ, "mon%dt_%lx", ubus->busnum, |
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index 8e0613c350cc..33678c24ebee 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h | |||
| @@ -27,6 +27,7 @@ struct mon_bus { | |||
| 27 | struct kref ref; /* Under mon_lock */ | 27 | struct kref ref; /* Under mon_lock */ |
| 28 | 28 | ||
| 29 | /* Stats */ | 29 | /* Stats */ |
| 30 | unsigned int cnt_events; | ||
| 30 | unsigned int cnt_text_lost; | 31 | unsigned int cnt_text_lost; |
| 31 | }; | 32 | }; |
| 32 | 33 | ||
| @@ -39,6 +40,7 @@ struct mon_reader { | |||
| 39 | void *r_data; /* Use container_of instead? */ | 40 | void *r_data; /* Use container_of instead? */ |
| 40 | 41 | ||
| 41 | void (*rnf_submit)(void *data, struct urb *urb); | 42 | void (*rnf_submit)(void *data, struct urb *urb); |
| 43 | void (*rnf_error)(void *data, struct urb *urb, int error); | ||
| 42 | void (*rnf_complete)(void *data, struct urb *urb); | 44 | void (*rnf_complete)(void *data, struct urb *urb); |
| 43 | }; | 45 | }; |
| 44 | 46 | ||
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 12b599a0b539..37111acec875 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c | |||
| @@ -912,6 +912,10 @@ static const struct usb_device_id products [] = { | |||
| 912 | USB_DEVICE (0x0b95, 0x7720), | 912 | USB_DEVICE (0x0b95, 0x7720), |
| 913 | .driver_info = (unsigned long) &ax88772_info, | 913 | .driver_info = (unsigned long) &ax88772_info, |
| 914 | }, { | 914 | }, { |
| 915 | // ASIX AX88178 10/100/1000 | ||
| 916 | USB_DEVICE (0x0b95, 0x1780), | ||
| 917 | .driver_info = (unsigned long) &ax88772_info, | ||
| 918 | }, { | ||
| 915 | // Linksys USB200M Rev 2 | 919 | // Linksys USB200M Rev 2 |
| 916 | USB_DEVICE (0x13b1, 0x0018), | 920 | USB_DEVICE (0x13b1, 0x0018), |
| 917 | .driver_info = (unsigned long) &ax88772_info, | 921 | .driver_info = (unsigned long) &ax88772_info, |
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index 63f1f3ba8e0b..efd195b5912c 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | #include <linux/workqueue.h> | 31 | #include <linux/workqueue.h> |
| 32 | #include <linux/mii.h> | 32 | #include <linux/mii.h> |
| 33 | #include <linux/usb.h> | 33 | #include <linux/usb.h> |
| 34 | #include <linux/usb_cdc.h> | 34 | #include <linux/usb/cdc.h> |
| 35 | 35 | ||
| 36 | #include "usbnet.h" | 36 | #include "usbnet.h" |
| 37 | 37 | ||
| @@ -455,6 +455,18 @@ static const struct usb_device_id products [] = { | |||
| 455 | .driver_info = 0, | 455 | .driver_info = 0, |
| 456 | }, | 456 | }, |
| 457 | 457 | ||
| 458 | /* Olympus has some models with a Zaurus-compatible option. | ||
| 459 | * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) | ||
| 460 | */ | ||
| 461 | { | ||
| 462 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | ||
| 463 | | USB_DEVICE_ID_MATCH_DEVICE, | ||
| 464 | .idVendor = 0x07B4, | ||
| 465 | .idProduct = 0x0F02, /* R-1000 */ | ||
| 466 | ZAURUS_MASTER_INTERFACE, | ||
| 467 | .driver_info = 0, | ||
| 468 | }, | ||
| 469 | |||
| 458 | /* | 470 | /* |
| 459 | * WHITELIST!!! | 471 | * WHITELIST!!! |
| 460 | * | 472 | * |
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 7683926a1b6f..ab21f960d255 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c | |||
| @@ -163,6 +163,8 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, | |||
| 163 | 163 | ||
| 164 | /* using ATOMIC, we'd never wake up if we slept */ | 164 | /* using ATOMIC, we'd never wake up if we slept */ |
| 165 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { | 165 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { |
| 166 | if (ret == -ENODEV) | ||
| 167 | netif_device_detach(pegasus->net); | ||
| 166 | if (netif_msg_drv(pegasus)) | 168 | if (netif_msg_drv(pegasus)) |
| 167 | dev_err(&pegasus->intf->dev, "%s, status %d\n", | 169 | dev_err(&pegasus->intf->dev, "%s, status %d\n", |
| 168 | __FUNCTION__, ret); | 170 | __FUNCTION__, ret); |
| @@ -217,6 +219,8 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size, | |||
| 217 | set_current_state(TASK_UNINTERRUPTIBLE); | 219 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 218 | 220 | ||
| 219 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { | 221 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { |
| 222 | if (ret == -ENODEV) | ||
| 223 | netif_device_detach(pegasus->net); | ||
| 220 | if (netif_msg_drv(pegasus)) | 224 | if (netif_msg_drv(pegasus)) |
| 221 | dev_err(&pegasus->intf->dev, "%s, status %d\n", | 225 | dev_err(&pegasus->intf->dev, "%s, status %d\n", |
| 222 | __FUNCTION__, ret); | 226 | __FUNCTION__, ret); |
| @@ -268,6 +272,8 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) | |||
| 268 | set_current_state(TASK_UNINTERRUPTIBLE); | 272 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 269 | 273 | ||
| 270 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { | 274 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { |
| 275 | if (ret == -ENODEV) | ||
| 276 | netif_device_detach(pegasus->net); | ||
| 271 | if (netif_msg_drv(pegasus)) | 277 | if (netif_msg_drv(pegasus)) |
| 272 | dev_err(&pegasus->intf->dev, "%s, status %d\n", | 278 | dev_err(&pegasus->intf->dev, "%s, status %d\n", |
| 273 | __FUNCTION__, ret); | 279 | __FUNCTION__, ret); |
| @@ -298,10 +304,13 @@ static int update_eth_regs_async(pegasus_t * pegasus) | |||
| 298 | (char *) &pegasus->dr, | 304 | (char *) &pegasus->dr, |
| 299 | pegasus->eth_regs, 3, ctrl_callback, pegasus); | 305 | pegasus->eth_regs, 3, ctrl_callback, pegasus); |
| 300 | 306 | ||
| 301 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) | 307 | if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { |
| 308 | if (ret == -ENODEV) | ||
| 309 | netif_device_detach(pegasus->net); | ||
| 302 | if (netif_msg_drv(pegasus)) | 310 | if (netif_msg_drv(pegasus)) |
| 303 | dev_err(&pegasus->intf->dev, "%s, status %d\n", | 311 | dev_err(&pegasus->intf->dev, "%s, status %d\n", |
| 304 | __FUNCTION__, ret); | 312 | __FUNCTION__, ret); |
| 313 | } | ||
| 305 | 314 | ||
| 306 | return ret; | 315 | return ret; |
| 307 | } | 316 | } |
| @@ -692,7 +701,10 @@ goon: | |||
| 692 | usb_rcvbulkpipe(pegasus->usb, 1), | 701 | usb_rcvbulkpipe(pegasus->usb, 1), |
| 693 | pegasus->rx_skb->data, PEGASUS_MTU + 8, | 702 | pegasus->rx_skb->data, PEGASUS_MTU + 8, |
| 694 | read_bulk_callback, pegasus); | 703 | read_bulk_callback, pegasus); |
| 695 | if (usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC)) { | 704 | rx_status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); |
| 705 | if (rx_status == -ENODEV) | ||
| 706 | netif_device_detach(pegasus->net); | ||
| 707 | else if (rx_status) { | ||
| 696 | pegasus->flags |= PEGASUS_RX_URB_FAIL; | 708 | pegasus->flags |= PEGASUS_RX_URB_FAIL; |
| 697 | goto tl_sched; | 709 | goto tl_sched; |
| 698 | } else { | 710 | } else { |
| @@ -709,6 +721,7 @@ static void rx_fixup(unsigned long data) | |||
| 709 | { | 721 | { |
| 710 | pegasus_t *pegasus; | 722 | pegasus_t *pegasus; |
| 711 | unsigned long flags; | 723 | unsigned long flags; |
| 724 | int status; | ||
| 712 | 725 | ||
| 713 | pegasus = (pegasus_t *) data; | 726 | pegasus = (pegasus_t *) data; |
| 714 | if (pegasus->flags & PEGASUS_UNPLUG) | 727 | if (pegasus->flags & PEGASUS_UNPLUG) |
| @@ -734,7 +747,10 @@ static void rx_fixup(unsigned long data) | |||
| 734 | pegasus->rx_skb->data, PEGASUS_MTU + 8, | 747 | pegasus->rx_skb->data, PEGASUS_MTU + 8, |
| 735 | read_bulk_callback, pegasus); | 748 | read_bulk_callback, pegasus); |
| 736 | try_again: | 749 | try_again: |
| 737 | if (usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC)) { | 750 | status = usb_submit_urb(pegasus->rx_urb, GFP_ATOMIC); |
| 751 | if (status == -ENODEV) | ||
| 752 | netif_device_detach(pegasus->net); | ||
| 753 | else if (status) { | ||
| 738 | pegasus->flags |= PEGASUS_RX_URB_FAIL; | 754 | pegasus->flags |= PEGASUS_RX_URB_FAIL; |
| 739 | tasklet_schedule(&pegasus->rx_tl); | 755 | tasklet_schedule(&pegasus->rx_tl); |
| 740 | } else { | 756 | } else { |
| @@ -836,6 +852,8 @@ static void intr_callback(struct urb *urb, struct pt_regs *regs) | |||
| 836 | } | 852 | } |
| 837 | 853 | ||
| 838 | status = usb_submit_urb(urb, SLAB_ATOMIC); | 854 | status = usb_submit_urb(urb, SLAB_ATOMIC); |
| 855 | if (status == -ENODEV) | ||
| 856 | netif_device_detach(pegasus->net); | ||
| 839 | if (status && netif_msg_timer(pegasus)) | 857 | if (status && netif_msg_timer(pegasus)) |
| 840 | printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n", | 858 | printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n", |
| 841 | net->name, status); | 859 | net->name, status); |
| @@ -874,6 +892,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
| 874 | /* cleanup should already have been scheduled */ | 892 | /* cleanup should already have been scheduled */ |
| 875 | break; | 893 | break; |
| 876 | case -ENODEV: /* disconnect() upcoming */ | 894 | case -ENODEV: /* disconnect() upcoming */ |
| 895 | netif_device_detach(pegasus->net); | ||
| 877 | break; | 896 | break; |
| 878 | default: | 897 | default: |
| 879 | pegasus->stats.tx_errors++; | 898 | pegasus->stats.tx_errors++; |
| @@ -999,6 +1018,8 @@ static int pegasus_open(struct net_device *net) | |||
| 999 | pegasus->rx_skb->data, PEGASUS_MTU + 8, | 1018 | pegasus->rx_skb->data, PEGASUS_MTU + 8, |
| 1000 | read_bulk_callback, pegasus); | 1019 | read_bulk_callback, pegasus); |
| 1001 | if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) { | 1020 | if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL))) { |
| 1021 | if (res == -ENODEV) | ||
| 1022 | netif_device_detach(pegasus->net); | ||
| 1002 | if (netif_msg_ifup(pegasus)) | 1023 | if (netif_msg_ifup(pegasus)) |
| 1003 | pr_debug("%s: failed rx_urb, %d", net->name, res); | 1024 | pr_debug("%s: failed rx_urb, %d", net->name, res); |
| 1004 | goto exit; | 1025 | goto exit; |
| @@ -1009,6 +1030,8 @@ static int pegasus_open(struct net_device *net) | |||
| 1009 | pegasus->intr_buff, sizeof (pegasus->intr_buff), | 1030 | pegasus->intr_buff, sizeof (pegasus->intr_buff), |
| 1010 | intr_callback, pegasus, pegasus->intr_interval); | 1031 | intr_callback, pegasus, pegasus->intr_interval); |
| 1011 | if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) { | 1032 | if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL))) { |
| 1033 | if (res == -ENODEV) | ||
| 1034 | netif_device_detach(pegasus->net); | ||
| 1012 | if (netif_msg_ifup(pegasus)) | 1035 | if (netif_msg_ifup(pegasus)) |
| 1013 | pr_debug("%s: failed intr_urb, %d\n", net->name, res); | 1036 | pr_debug("%s: failed intr_urb, %d\n", net->name, res); |
| 1014 | usb_kill_urb(pegasus->rx_urb); | 1037 | usb_kill_urb(pegasus->rx_urb); |
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index 94ddfe16fdda..f551546d7521 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
| 31 | #include <linux/mii.h> | 31 | #include <linux/mii.h> |
| 32 | #include <linux/usb.h> | 32 | #include <linux/usb.h> |
| 33 | #include <linux/usb_cdc.h> | 33 | #include <linux/usb/cdc.h> |
| 34 | 34 | ||
| 35 | #include "usbnet.h" | 35 | #include "usbnet.h" |
| 36 | 36 | ||
diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c index f7ac9d6b9856..813e470d0600 100644 --- a/drivers/usb/net/zaurus.c +++ b/drivers/usb/net/zaurus.c | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | #include <linux/mii.h> | 30 | #include <linux/mii.h> |
| 31 | #include <linux/crc32.h> | 31 | #include <linux/crc32.h> |
| 32 | #include <linux/usb.h> | 32 | #include <linux/usb.h> |
| 33 | #include <linux/usb_cdc.h> | 33 | #include <linux/usb/cdc.h> |
| 34 | 34 | ||
| 35 | #include "usbnet.h" | 35 | #include "usbnet.h" |
| 36 | 36 | ||
| @@ -109,7 +109,7 @@ static const struct driver_info zaurus_sl5x00_info = { | |||
| 109 | .check_connect = always_connected, | 109 | .check_connect = always_connected, |
| 110 | .bind = zaurus_bind, | 110 | .bind = zaurus_bind, |
| 111 | .unbind = usbnet_cdc_unbind, | 111 | .unbind = usbnet_cdc_unbind, |
| 112 | .tx_fixup = zaurus_tx_fixup, | 112 | .tx_fixup = zaurus_tx_fixup, |
| 113 | }; | 113 | }; |
| 114 | #define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info) | 114 | #define ZAURUS_STRONGARM_INFO ((unsigned long)&zaurus_sl5x00_info) |
| 115 | 115 | ||
| @@ -119,7 +119,7 @@ static const struct driver_info zaurus_pxa_info = { | |||
| 119 | .check_connect = always_connected, | 119 | .check_connect = always_connected, |
| 120 | .bind = zaurus_bind, | 120 | .bind = zaurus_bind, |
| 121 | .unbind = usbnet_cdc_unbind, | 121 | .unbind = usbnet_cdc_unbind, |
| 122 | .tx_fixup = zaurus_tx_fixup, | 122 | .tx_fixup = zaurus_tx_fixup, |
| 123 | }; | 123 | }; |
| 124 | #define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info) | 124 | #define ZAURUS_PXA_INFO ((unsigned long)&zaurus_pxa_info) |
| 125 | 125 | ||
| @@ -129,7 +129,7 @@ static const struct driver_info olympus_mxl_info = { | |||
| 129 | .check_connect = always_connected, | 129 | .check_connect = always_connected, |
| 130 | .bind = zaurus_bind, | 130 | .bind = zaurus_bind, |
| 131 | .unbind = usbnet_cdc_unbind, | 131 | .unbind = usbnet_cdc_unbind, |
| 132 | .tx_fixup = zaurus_tx_fixup, | 132 | .tx_fixup = zaurus_tx_fixup, |
| 133 | }; | 133 | }; |
| 134 | #define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info) | 134 | #define OLYMPUS_MXL_INFO ((unsigned long)&olympus_mxl_info) |
| 135 | 135 | ||
| @@ -228,6 +228,11 @@ bad_detail: | |||
| 228 | detail->bDetailData[2]); | 228 | detail->bDetailData[2]); |
| 229 | goto bad_desc; | 229 | goto bad_desc; |
| 230 | } | 230 | } |
| 231 | |||
| 232 | /* same extra framing as for non-BLAN mode */ | ||
| 233 | dev->net->hard_header_len += 6; | ||
| 234 | dev->rx_urb_size = dev->net->hard_header_len | ||
| 235 | + dev->net->mtu; | ||
| 231 | break; | 236 | break; |
| 232 | } | 237 | } |
| 233 | next_desc: | 238 | next_desc: |
| @@ -258,7 +263,7 @@ static const struct driver_info bogus_mdlm_info = { | |||
| 258 | .description = "pseudo-MDLM (BLAN) device", | 263 | .description = "pseudo-MDLM (BLAN) device", |
| 259 | .flags = FLAG_FRAMING_Z, | 264 | .flags = FLAG_FRAMING_Z, |
| 260 | .check_connect = always_connected, | 265 | .check_connect = always_connected, |
| 261 | .tx_fixup = zaurus_tx_fixup, | 266 | .tx_fixup = zaurus_tx_fixup, |
| 262 | .bind = blan_mdlm_bind, | 267 | .bind = blan_mdlm_bind, |
| 263 | }; | 268 | }; |
| 264 | 269 | ||
| @@ -367,13 +372,13 @@ static struct usb_driver zaurus_driver = { | |||
| 367 | 372 | ||
| 368 | static int __init zaurus_init(void) | 373 | static int __init zaurus_init(void) |
| 369 | { | 374 | { |
| 370 | return usb_register(&zaurus_driver); | 375 | return usb_register(&zaurus_driver); |
| 371 | } | 376 | } |
| 372 | module_init(zaurus_init); | 377 | module_init(zaurus_init); |
| 373 | 378 | ||
| 374 | static void __exit zaurus_exit(void) | 379 | static void __exit zaurus_exit(void) |
| 375 | { | 380 | { |
| 376 | usb_deregister(&zaurus_driver); | 381 | usb_deregister(&zaurus_driver); |
| 377 | } | 382 | } |
| 378 | module_exit(zaurus_exit); | 383 | module_exit(zaurus_exit); |
| 379 | 384 | ||
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 5c60be521561..8bd44fda5eaf 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig | |||
| @@ -417,7 +417,7 @@ config USB_SERIAL_MCT_U232 | |||
| 417 | Magic Control Technology Corp. (U232 is one of the model numbers). | 417 | Magic Control Technology Corp. (U232 is one of the model numbers). |
| 418 | 418 | ||
| 419 | This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB | 419 | This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB |
| 420 | BAY devices. | 420 | BAY, Belkin F5U109, and Belkin F5U409 devices. |
| 421 | 421 | ||
| 422 | To compile this driver as a module, choose M here: the | 422 | To compile this driver as a module, choose M here: the |
| 423 | module will be called mct_u232. | 423 | module will be called mct_u232. |
| @@ -491,16 +491,22 @@ config USB_SERIAL_XIRCOM | |||
| 491 | module will be called keyspan_pda. | 491 | module will be called keyspan_pda. |
| 492 | 492 | ||
| 493 | config USB_SERIAL_OPTION | 493 | config USB_SERIAL_OPTION |
| 494 | tristate "USB Option PCMCIA serial driver" | 494 | tristate "USB driver for GSM modems" |
| 495 | depends on USB_SERIAL && USB_OHCI_HCD && PCCARD | 495 | depends on USB_SERIAL |
| 496 | help | 496 | help |
| 497 | Say Y here if you want to use an Option card. This is a | 497 | Say Y here if you have an "Option" GSM PCMCIA card |
| 498 | GSM card, controlled by three serial ports which are connected | 498 | (or an OEM version: branded Huawei, Audiovox, or Novatel). |
| 499 | via an OHCI adapter located on a PC card. | 499 | |
| 500 | These cards feature a built-in OHCI-USB adapter and an | ||
| 501 | internally-connected GSM modem. The USB bus is not | ||
| 502 | accessible externally. | ||
| 500 | 503 | ||
| 501 | To compile this driver as a module, choose M here: the | 504 | To compile this driver as a module, choose M here: the |
| 502 | module will be called option. | 505 | module will be called option. |
| 503 | 506 | ||
| 507 | If this driver doesn't recognize your device, | ||
| 508 | it might be accessible via the FTDI_SIO driver. | ||
| 509 | |||
| 504 | config USB_SERIAL_OMNINET | 510 | config USB_SERIAL_OMNINET |
| 505 | tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)" | 511 | tristate "USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)" |
| 506 | depends on USB_SERIAL && EXPERIMENTAL | 512 | depends on USB_SERIAL && EXPERIMENTAL |
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 694b205f9b73..94b9ba0ff875 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c | |||
| @@ -16,9 +16,11 @@ | |||
| 16 | #include "usb-serial.h" | 16 | #include "usb-serial.h" |
| 17 | 17 | ||
| 18 | static struct usb_device_id id_table [] = { | 18 | static struct usb_device_id id_table [] = { |
| 19 | { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ | ||
| 19 | { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ | 20 | { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ |
| 20 | { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ | 21 | { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ |
| 21 | { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ | 22 | { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ |
| 23 | { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ | ||
| 22 | { }, | 24 | { }, |
| 23 | }; | 25 | }; |
| 24 | MODULE_DEVICE_TABLE(usb, id_table); | 26 | MODULE_DEVICE_TABLE(usb, id_table); |
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 8023bb7279b1..f3404e10afb4 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c | |||
| @@ -202,7 +202,7 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun | |||
| 202 | struct usb_serial *serial; | 202 | struct usb_serial *serial; |
| 203 | int retval = -ENODEV; | 203 | int retval = -ENODEV; |
| 204 | 204 | ||
| 205 | if (!port) | 205 | if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) |
| 206 | return; | 206 | return; |
| 207 | serial = port->serial; | 207 | serial = port->serial; |
| 208 | 208 | ||
| @@ -213,17 +213,38 @@ static void usb_console_write(struct console *co, const char *buf, unsigned coun | |||
| 213 | 213 | ||
| 214 | if (!port->open_count) { | 214 | if (!port->open_count) { |
| 215 | dbg ("%s - port not opened", __FUNCTION__); | 215 | dbg ("%s - port not opened", __FUNCTION__); |
| 216 | goto exit; | 216 | return; |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | /* pass on to the driver specific version of this function if it is available */ | 219 | while (count) { |
| 220 | if (serial->type->write) | 220 | unsigned int i; |
| 221 | retval = serial->type->write(port, buf, count); | 221 | unsigned int lf; |
| 222 | else | 222 | /* search for LF so we can insert CR if necessary */ |
| 223 | retval = usb_serial_generic_write(port, buf, count); | 223 | for (i=0, lf=0 ; i < count ; i++) { |
| 224 | 224 | if (*(buf + i) == 10) { | |
| 225 | exit: | 225 | lf = 1; |
| 226 | dbg("%s - return value (if we had one): %d", __FUNCTION__, retval); | 226 | i++; |
| 227 | break; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | /* pass on to the driver specific version of this function if it is available */ | ||
| 231 | if (serial->type->write) | ||
| 232 | retval = serial->type->write(port, buf, i); | ||
| 233 | else | ||
| 234 | retval = usb_serial_generic_write(port, buf, i); | ||
| 235 | dbg("%s - return value : %d", __FUNCTION__, retval); | ||
| 236 | if (lf) { | ||
| 237 | /* append CR after LF */ | ||
| 238 | unsigned char cr = 13; | ||
| 239 | if (serial->type->write) | ||
| 240 | retval = serial->type->write(port, &cr, 1); | ||
| 241 | else | ||
| 242 | retval = usb_serial_generic_write(port, &cr, 1); | ||
| 243 | dbg("%s - return value : %d", __FUNCTION__, retval); | ||
| 244 | } | ||
| 245 | buf += i; | ||
| 246 | count -= i; | ||
| 247 | } | ||
| 227 | } | 248 | } |
| 228 | 249 | ||
| 229 | static struct console usbcons = { | 250 | static struct console usbcons = { |
| @@ -234,6 +255,14 @@ static struct console usbcons = { | |||
| 234 | .index = -1, | 255 | .index = -1, |
| 235 | }; | 256 | }; |
| 236 | 257 | ||
| 258 | void usb_serial_console_disconnect(struct usb_serial *serial) | ||
| 259 | { | ||
| 260 | if (serial && serial->port && serial->port[0] && serial->port[0] == usbcons_info.port) { | ||
| 261 | usb_serial_console_exit(); | ||
| 262 | usb_serial_put(serial); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 237 | void usb_serial_console_init (int serial_debug, int minor) | 266 | void usb_serial_console_init (int serial_debug, int minor) |
| 238 | { | 267 | { |
| 239 | debug = serial_debug; | 268 | debug = serial_debug; |
| @@ -259,6 +288,11 @@ void usb_serial_console_init (int serial_debug, int minor) | |||
| 259 | 288 | ||
| 260 | void usb_serial_console_exit (void) | 289 | void usb_serial_console_exit (void) |
| 261 | { | 290 | { |
| 262 | unregister_console(&usbcons); | 291 | if (usbcons_info.port) { |
| 292 | unregister_console(&usbcons); | ||
| 293 | if (usbcons_info.port->open_count) | ||
| 294 | usbcons_info.port->open_count--; | ||
| 295 | usbcons_info.port = NULL; | ||
| 296 | } | ||
| 263 | } | 297 | } |
| 264 | 298 | ||
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index e0c2acdb3f06..f8c0cb287736 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c | |||
| @@ -59,6 +59,7 @@ static struct usb_device_id id_table [] = { | |||
| 59 | { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ | 59 | { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ |
| 60 | { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ | 60 | { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ |
| 61 | { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ | 61 | { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ |
| 62 | { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ | ||
| 62 | { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ | 63 | { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ |
| 63 | { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ | 64 | { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ |
| 64 | { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ | 65 | { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ |
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 2357b1d102d7..1fd5c5a9f2ef 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c | |||
| @@ -469,7 +469,7 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs | |||
| 469 | 469 | ||
| 470 | exit: | 470 | exit: |
| 471 | spin_unlock(&priv->lock); | 471 | spin_unlock(&priv->lock); |
| 472 | schedule_work(&port->work); | 472 | usb_serial_port_softint(port); |
| 473 | } | 473 | } |
| 474 | 474 | ||
| 475 | static int __init cyberjack_init (void) | 475 | static int __init cyberjack_init (void) |
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 7212fbe3b6f2..5de76efe1b37 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c | |||
| @@ -824,7 +824,7 @@ send: | |||
| 824 | priv->bytes_out += count; /* do not count the line control and size bytes */ | 824 | priv->bytes_out += count; /* do not count the line control and size bytes */ |
| 825 | spin_unlock_irqrestore(&priv->lock, flags); | 825 | spin_unlock_irqrestore(&priv->lock, flags); |
| 826 | 826 | ||
| 827 | schedule_work(&port->work); | 827 | usb_serial_port_softint(port); |
| 828 | } /* cypress_send */ | 828 | } /* cypress_send */ |
| 829 | 829 | ||
| 830 | 830 | ||
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 63f7c78a1152..afca1eae5fb5 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c | |||
| @@ -335,7 +335,7 @@ static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
| 335 | return; | 335 | return; |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | schedule_work(&port->work); | 338 | usb_serial_port_softint(port); |
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | 341 | ||
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 986d7622273d..b2bfea7c815a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
| @@ -500,6 +500,7 @@ static struct usb_device_id id_table_combined [] = { | |||
| 500 | { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, | 500 | { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, |
| 501 | { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, | 501 | { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, |
| 502 | { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, | 502 | { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, |
| 503 | { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, | ||
| 503 | { }, /* Optional parameter entry */ | 504 | { }, /* Optional parameter entry */ |
| 504 | { } /* Terminating entry */ | 505 | { } /* Terminating entry */ |
| 505 | }; | 506 | }; |
| @@ -1261,7 +1262,6 @@ static void ftdi_shutdown (struct usb_serial *serial) | |||
| 1261 | 1262 | ||
| 1262 | static int ftdi_open (struct usb_serial_port *port, struct file *filp) | 1263 | static int ftdi_open (struct usb_serial_port *port, struct file *filp) |
| 1263 | { /* ftdi_open */ | 1264 | { /* ftdi_open */ |
| 1264 | struct termios tmp_termios; | ||
| 1265 | struct usb_device *dev = port->serial->dev; | 1265 | struct usb_device *dev = port->serial->dev; |
| 1266 | struct ftdi_private *priv = usb_get_serial_port_data(port); | 1266 | struct ftdi_private *priv = usb_get_serial_port_data(port); |
| 1267 | unsigned long flags; | 1267 | unsigned long flags; |
| @@ -1271,8 +1271,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) | |||
| 1271 | 1271 | ||
| 1272 | dbg("%s", __FUNCTION__); | 1272 | dbg("%s", __FUNCTION__); |
| 1273 | 1273 | ||
| 1274 | 1274 | if (port->tty) | |
| 1275 | port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; | 1275 | port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; |
| 1276 | 1276 | ||
| 1277 | /* No error checking for this (will get errors later anyway) */ | 1277 | /* No error checking for this (will get errors later anyway) */ |
| 1278 | /* See ftdi_sio.h for description of what is reset */ | 1278 | /* See ftdi_sio.h for description of what is reset */ |
| @@ -1286,7 +1286,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) | |||
| 1286 | This is same behaviour as serial.c/rs_open() - Kuba */ | 1286 | This is same behaviour as serial.c/rs_open() - Kuba */ |
| 1287 | 1287 | ||
| 1288 | /* ftdi_set_termios will send usb control messages */ | 1288 | /* ftdi_set_termios will send usb control messages */ |
| 1289 | ftdi_set_termios(port, &tmp_termios); | 1289 | if (port->tty) |
| 1290 | ftdi_set_termios(port, NULL); | ||
| 1290 | 1291 | ||
| 1291 | /* FIXME: Flow control might be enabled, so it should be checked - | 1292 | /* FIXME: Flow control might be enabled, so it should be checked - |
| 1292 | we have no control of defaults! */ | 1293 | we have no control of defaults! */ |
| @@ -1472,7 +1473,7 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
| 1472 | return; | 1473 | return; |
| 1473 | } | 1474 | } |
| 1474 | 1475 | ||
| 1475 | schedule_work(&port->work); | 1476 | usb_serial_port_softint(port); |
| 1476 | } /* ftdi_write_bulk_callback */ | 1477 | } /* ftdi_write_bulk_callback */ |
| 1477 | 1478 | ||
| 1478 | 1479 | ||
| @@ -1867,7 +1868,7 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ | |||
| 1867 | err("%s urb failed to set baudrate", __FUNCTION__); | 1868 | err("%s urb failed to set baudrate", __FUNCTION__); |
| 1868 | } | 1869 | } |
| 1869 | /* Ensure RTS and DTR are raised when baudrate changed from 0 */ | 1870 | /* Ensure RTS and DTR are raised when baudrate changed from 0 */ |
| 1870 | if ((old_termios->c_cflag & CBAUD) == B0) { | 1871 | if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) { |
| 1871 | set_mctrl(port, TIOCM_DTR | TIOCM_RTS); | 1872 | set_mctrl(port, TIOCM_DTR | TIOCM_RTS); |
| 1872 | } | 1873 | } |
| 1873 | } | 1874 | } |
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index d69a917e768f..6ab2ac845bd7 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h | |||
| @@ -436,6 +436,12 @@ | |||
| 436 | */ | 436 | */ |
| 437 | #define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */ | 437 | #define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */ |
| 438 | 438 | ||
| 439 | /* | ||
| 440 | * Yost Engineering, Inc. products (www.yostengineering.com). | ||
| 441 | * PID 0xE050 submitted by Aaron Prose. | ||
| 442 | */ | ||
| 443 | #define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */ | ||
| 444 | |||
| 439 | /* Commands */ | 445 | /* Commands */ |
| 440 | #define FTDI_SIO_RESET 0 /* Reset the port */ | 446 | #define FTDI_SIO_RESET 0 /* Reset the port */ |
| 441 | #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ | 447 | #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ |
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 5ec9bf5bac8d..04767759cf8a 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c | |||
| @@ -1012,7 +1012,7 @@ static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
| 1012 | garmin_data_p->flags |= CLEAR_HALT_REQUIRED; | 1012 | garmin_data_p->flags |= CLEAR_HALT_REQUIRED; |
| 1013 | } | 1013 | } |
| 1014 | 1014 | ||
| 1015 | schedule_work(&port->work); | 1015 | usb_serial_port_softint(port); |
| 1016 | } | 1016 | } |
| 1017 | 1017 | ||
| 1018 | 1018 | ||
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index c62cc2876519..07a478c59fb2 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
| @@ -299,9 +299,7 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *re | |||
| 299 | return; | 299 | return; |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | usb_serial_port_softint((void *)port); | 302 | usb_serial_port_softint(port); |
| 303 | |||
| 304 | schedule_work(&port->work); | ||
| 305 | } | 303 | } |
| 306 | EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); | 304 | EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); |
| 307 | 305 | ||
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index b606c5968102..b85d2156dfdc 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c | |||
| @@ -142,7 +142,7 @@ struct edgeport_port { | |||
| 142 | 142 | ||
| 143 | /* This structure holds all of the individual device information */ | 143 | /* This structure holds all of the individual device information */ |
| 144 | struct edgeport_serial { | 144 | struct edgeport_serial { |
| 145 | char name[MAX_NAME_LEN+1]; /* string name of this device */ | 145 | char name[MAX_NAME_LEN+2]; /* string name of this device */ |
| 146 | 146 | ||
| 147 | struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */ | 147 | struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */ |
| 148 | struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */ | 148 | struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */ |
| @@ -270,7 +270,7 @@ static void get_manufacturing_desc (struct edgeport_serial *edge_serial); | |||
| 270 | static void get_boot_desc (struct edgeport_serial *edge_serial); | 270 | static void get_boot_desc (struct edgeport_serial *edge_serial); |
| 271 | static void load_application_firmware (struct edgeport_serial *edge_serial); | 271 | static void load_application_firmware (struct edgeport_serial *edge_serial); |
| 272 | 272 | ||
| 273 | static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size); | 273 | static void unicode_to_ascii(char *string, int buflen, __le16 *unicode, int unicode_size); |
| 274 | 274 | ||
| 275 | 275 | ||
| 276 | // ************************************************************************ | 276 | // ************************************************************************ |
| @@ -373,7 +373,7 @@ static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial) | |||
| 373 | * Get string descriptor from device * | 373 | * Get string descriptor from device * |
| 374 | * * | 374 | * * |
| 375 | ************************************************************************/ | 375 | ************************************************************************/ |
| 376 | static int get_string (struct usb_device *dev, int Id, char *string) | 376 | static int get_string (struct usb_device *dev, int Id, char *string, int buflen) |
| 377 | { | 377 | { |
| 378 | struct usb_string_descriptor StringDesc; | 378 | struct usb_string_descriptor StringDesc; |
| 379 | struct usb_string_descriptor *pStringDesc; | 379 | struct usb_string_descriptor *pStringDesc; |
| @@ -395,7 +395,7 @@ static int get_string (struct usb_device *dev, int Id, char *string) | |||
| 395 | return 0; | 395 | return 0; |
| 396 | } | 396 | } |
| 397 | 397 | ||
| 398 | unicode_to_ascii(string, pStringDesc->wData, pStringDesc->bLength/2-1); | 398 | unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2); |
| 399 | 399 | ||
| 400 | kfree(pStringDesc); | 400 | kfree(pStringDesc); |
| 401 | return strlen(string); | 401 | return strlen(string); |
| @@ -2564,16 +2564,20 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio | |||
| 2564 | * ASCII range, but it's only for debugging... | 2564 | * ASCII range, but it's only for debugging... |
| 2565 | * NOTE: expects the unicode in LE format | 2565 | * NOTE: expects the unicode in LE format |
| 2566 | ****************************************************************************/ | 2566 | ****************************************************************************/ |
| 2567 | static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size) | 2567 | static void unicode_to_ascii(char *string, int buflen, __le16 *unicode, int unicode_size) |
| 2568 | { | 2568 | { |
| 2569 | int i; | 2569 | int i; |
| 2570 | 2570 | ||
| 2571 | if (unicode_size <= 0) | 2571 | if (buflen <= 0) /* never happens, but... */ |
| 2572 | return; | 2572 | return; |
| 2573 | --buflen; /* space for nul */ | ||
| 2573 | 2574 | ||
| 2574 | for (i = 0; i < unicode_size; ++i) | 2575 | for (i = 0; i < unicode_size; i++) { |
| 2576 | if (i >= buflen) | ||
| 2577 | break; | ||
| 2575 | string[i] = (char)(le16_to_cpu(unicode[i])); | 2578 | string[i] = (char)(le16_to_cpu(unicode[i])); |
| 2576 | string[unicode_size] = 0x00; | 2579 | } |
| 2580 | string[i] = 0x00; | ||
| 2577 | } | 2581 | } |
| 2578 | 2582 | ||
| 2579 | 2583 | ||
| @@ -2603,11 +2607,17 @@ static void get_manufacturing_desc (struct edgeport_serial *edge_serial) | |||
| 2603 | dbg(" BoardRev: %d", edge_serial->manuf_descriptor.BoardRev); | 2607 | dbg(" BoardRev: %d", edge_serial->manuf_descriptor.BoardRev); |
| 2604 | dbg(" NumPorts: %d", edge_serial->manuf_descriptor.NumPorts); | 2608 | dbg(" NumPorts: %d", edge_serial->manuf_descriptor.NumPorts); |
| 2605 | dbg(" DescDate: %d/%d/%d", edge_serial->manuf_descriptor.DescDate[0], edge_serial->manuf_descriptor.DescDate[1], edge_serial->manuf_descriptor.DescDate[2]+1900); | 2609 | dbg(" DescDate: %d/%d/%d", edge_serial->manuf_descriptor.DescDate[0], edge_serial->manuf_descriptor.DescDate[1], edge_serial->manuf_descriptor.DescDate[2]+1900); |
| 2606 | unicode_to_ascii (string, edge_serial->manuf_descriptor.SerialNumber, edge_serial->manuf_descriptor.SerNumLength/2-1); | 2610 | unicode_to_ascii(string, sizeof(string), |
| 2611 | edge_serial->manuf_descriptor.SerialNumber, | ||
| 2612 | edge_serial->manuf_descriptor.SerNumLength/2); | ||
| 2607 | dbg(" SerialNumber: %s", string); | 2613 | dbg(" SerialNumber: %s", string); |
| 2608 | unicode_to_ascii (string, edge_serial->manuf_descriptor.AssemblyNumber, edge_serial->manuf_descriptor.AssemblyNumLength/2-1); | 2614 | unicode_to_ascii(string, sizeof(string), |
| 2615 | edge_serial->manuf_descriptor.AssemblyNumber, | ||
| 2616 | edge_serial->manuf_descriptor.AssemblyNumLength/2); | ||
| 2609 | dbg(" AssemblyNumber: %s", string); | 2617 | dbg(" AssemblyNumber: %s", string); |
| 2610 | unicode_to_ascii (string, edge_serial->manuf_descriptor.OemAssyNumber, edge_serial->manuf_descriptor.OemAssyNumLength/2-1); | 2618 | unicode_to_ascii(string, sizeof(string), |
| 2619 | edge_serial->manuf_descriptor.OemAssyNumber, | ||
| 2620 | edge_serial->manuf_descriptor.OemAssyNumLength/2); | ||
| 2611 | dbg(" OemAssyNumber: %s", string); | 2621 | dbg(" OemAssyNumber: %s", string); |
| 2612 | dbg(" UartType: %d", edge_serial->manuf_descriptor.UartType); | 2622 | dbg(" UartType: %d", edge_serial->manuf_descriptor.UartType); |
| 2613 | dbg(" IonPid: %d", edge_serial->manuf_descriptor.IonPid); | 2623 | dbg(" IonPid: %d", edge_serial->manuf_descriptor.IonPid); |
| @@ -2720,7 +2730,7 @@ static int edge_startup (struct usb_serial *serial) | |||
| 2720 | struct edgeport_serial *edge_serial; | 2730 | struct edgeport_serial *edge_serial; |
| 2721 | struct edgeport_port *edge_port; | 2731 | struct edgeport_port *edge_port; |
| 2722 | struct usb_device *dev; | 2732 | struct usb_device *dev; |
| 2723 | int i; | 2733 | int i, j; |
| 2724 | 2734 | ||
| 2725 | dev = serial->dev; | 2735 | dev = serial->dev; |
| 2726 | 2736 | ||
| @@ -2735,11 +2745,11 @@ static int edge_startup (struct usb_serial *serial) | |||
| 2735 | usb_set_serial_data(serial, edge_serial); | 2745 | usb_set_serial_data(serial, edge_serial); |
| 2736 | 2746 | ||
| 2737 | /* get the name for the device from the device */ | 2747 | /* get the name for the device from the device */ |
| 2738 | if ( (i = get_string(dev, dev->descriptor.iManufacturer, &edge_serial->name[0])) != 0) { | 2748 | i = get_string(dev, dev->descriptor.iManufacturer, |
| 2739 | edge_serial->name[i-1] = ' '; | 2749 | &edge_serial->name[0], MAX_NAME_LEN+1); |
| 2740 | } | 2750 | edge_serial->name[i++] = ' '; |
| 2741 | 2751 | get_string(dev, dev->descriptor.iProduct, | |
| 2742 | get_string(dev, dev->descriptor.iProduct, &edge_serial->name[i]); | 2752 | &edge_serial->name[i], MAX_NAME_LEN+2 - i); |
| 2743 | 2753 | ||
| 2744 | dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); | 2754 | dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); |
| 2745 | 2755 | ||
| @@ -2784,6 +2794,10 @@ static int edge_startup (struct usb_serial *serial) | |||
| 2784 | edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); | 2794 | edge_port = kmalloc (sizeof(struct edgeport_port), GFP_KERNEL); |
| 2785 | if (edge_port == NULL) { | 2795 | if (edge_port == NULL) { |
| 2786 | dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); | 2796 | dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__); |
| 2797 | for (j = 0; j < i; ++j) { | ||
| 2798 | kfree (usb_get_serial_port_data(serial->port[j])); | ||
| 2799 | usb_set_serial_port_data(serial->port[j], NULL); | ||
| 2800 | } | ||
| 2787 | usb_set_serial_data(serial, NULL); | 2801 | usb_set_serial_data(serial, NULL); |
| 2788 | kfree(edge_serial); | 2802 | kfree(edge_serial); |
| 2789 | return -ENOMEM; | 2803 | return -ENOMEM; |
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 9a5c97989562..9da6d2a8f2b0 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c | |||
| @@ -870,7 +870,7 @@ static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs) | |||
| 870 | spin_unlock_irqrestore(&write_list_lock, flags); | 870 | spin_unlock_irqrestore(&write_list_lock, flags); |
| 871 | } | 871 | } |
| 872 | 872 | ||
| 873 | schedule_work(&port->work); | 873 | usb_serial_port_softint(port); |
| 874 | } | 874 | } |
| 875 | 875 | ||
| 876 | static int ipaq_write_room(struct usb_serial_port *port) | 876 | static int ipaq_write_room(struct usb_serial_port *port) |
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index e760a70242c1..a4a0bfeaab00 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c | |||
| @@ -376,7 +376,7 @@ static void ipw_write_bulk_callback(struct urb *urb, struct pt_regs *regs) | |||
| 376 | if (urb->status) | 376 | if (urb->status) |
| 377 | dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); | 377 | dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); |
| 378 | 378 | ||
| 379 | schedule_work(&port->work); | 379 | usb_serial_port_softint(port); |
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int count) | 382 | static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int count) |
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 426182ddc42a..9432c7302275 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c | |||
| @@ -408,7 +408,7 @@ static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
| 408 | urb->actual_length, | 408 | urb->actual_length, |
| 409 | urb->transfer_buffer); | 409 | urb->transfer_buffer); |
| 410 | 410 | ||
| 411 | schedule_work(&port->work); | 411 | usb_serial_port_softint(port); |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs) | 414 | static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs) |
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 052b735c4fbd..2cf6ade704e4 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c | |||
| @@ -481,7 +481,7 @@ static void usa2x_outdat_callback(struct urb *urb, struct pt_regs *regs) | |||
| 481 | dbg ("%s - urb %d", __FUNCTION__, urb == p_priv->out_urbs[1]); | 481 | dbg ("%s - urb %d", __FUNCTION__, urb == p_priv->out_urbs[1]); |
| 482 | 482 | ||
| 483 | if (port->open_count) | 483 | if (port->open_count) |
| 484 | schedule_work(&port->work); | 484 | usb_serial_port_softint(port); |
| 485 | } | 485 | } |
| 486 | 486 | ||
| 487 | static void usa26_inack_callback(struct urb *urb, struct pt_regs *regs) | 487 | static void usa26_inack_callback(struct urb *urb, struct pt_regs *regs) |
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 78335a5f7743..65d79f630fa4 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c | |||
| @@ -569,8 +569,7 @@ static void klsi_105_write_bulk_callback ( struct urb *urb, struct pt_regs *regs | |||
| 569 | return; | 569 | return; |
| 570 | } | 570 | } |
| 571 | 571 | ||
| 572 | /* from generic_write_bulk_callback */ | 572 | usb_serial_port_softint(port); |
| 573 | schedule_work(&port->work); | ||
| 574 | } /* klsi_105_write_bulk_completion_callback */ | 573 | } /* klsi_105_write_bulk_completion_callback */ |
| 575 | 574 | ||
| 576 | 575 | ||
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 238033a87092..6dcdb5f598b8 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c | |||
| @@ -320,7 +320,7 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
| 320 | return; | 320 | return; |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | schedule_work(&port->work); | 323 | usb_serial_port_softint(port); |
| 324 | } | 324 | } |
| 325 | 325 | ||
| 326 | 326 | ||
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5cf2b80add7a..b0861b61bba7 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | Option Card (PCMCIA to) USB to Serial Driver | 2 | USB Driver for GSM modems |
| 3 | 3 | ||
| 4 | Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de> | 4 | Copyright (C) 2005 Matthias Urlichs <smurf@smurf.noris.de> |
| 5 | 5 | ||
| @@ -28,15 +28,34 @@ | |||
| 28 | 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard | 28 | 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard |
| 29 | 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes | 29 | 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes |
| 30 | wants to send >2000 bytes. | 30 | wants to send >2000 bytes. |
| 31 | 2006-04-10 v0.4.2 fixed two array overrun errors :-/ | 31 | 2006-04-10 v0.5 fixed two array overrun errors :-/ |
| 32 | 2006-04-21 v0.5.1 added support for Sierra Wireless MC8755 | ||
| 33 | 2006-05-15 v0.6 re-enable multi-port support | ||
| 34 | 2006-06-01 v0.6.1 add COBRA | ||
| 35 | 2006-06-01 v0.6.2 add backwards-compatibility stuff | ||
| 36 | 2006-06-01 v0.6.3 add Novatel Wireless | ||
| 37 | 2006-06-01 v0.7 Option => GSM | ||
| 32 | 38 | ||
| 33 | Work sponsored by: Sigos GmbH, Germany <info@sigos.de> | 39 | Work sponsored by: Sigos GmbH, Germany <info@sigos.de> |
| 34 | 40 | ||
| 41 | This driver exists because the "normal" serial driver doesn't work too well | ||
| 42 | with GSM modems. Issues: | ||
| 43 | - data loss -- one single Receive URB is not nearly enough | ||
| 44 | - nonstandard flow (Option devices) and multiplex (Sierra) control | ||
| 45 | - controlling the baud rate doesn't make sense | ||
| 46 | |||
| 47 | This driver is named "option" because the most common device it's | ||
| 48 | used for is a PC-Card (with an internal OHCI-USB interface, behind | ||
| 49 | which the GSM interface sits), made by Option Inc. | ||
| 50 | |||
| 51 | Some of the "one port" devices actually exhibit multiple USB instances | ||
| 52 | on the USB bus. This is not a bug, these ports are used for different | ||
| 53 | device features. | ||
| 35 | */ | 54 | */ |
| 36 | 55 | ||
| 37 | #define DRIVER_VERSION "v0.4" | 56 | #define DRIVER_VERSION "v0.7.0" |
| 38 | #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" | 57 | #define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>" |
| 39 | #define DRIVER_DESC "Option Card (PC-Card to) USB to Serial Driver" | 58 | #define DRIVER_DESC "USB Driver for GSM modems" |
| 40 | 59 | ||
| 41 | #include <linux/config.h> | 60 | #include <linux/config.h> |
| 42 | #include <linux/kernel.h> | 61 | #include <linux/kernel.h> |
| @@ -74,22 +93,45 @@ static int option_tiocmset(struct usb_serial_port *port, struct file *file, | |||
| 74 | static int option_send_setup(struct usb_serial_port *port); | 93 | static int option_send_setup(struct usb_serial_port *port); |
| 75 | 94 | ||
| 76 | /* Vendor and product IDs */ | 95 | /* Vendor and product IDs */ |
| 77 | #define OPTION_VENDOR_ID 0x0AF0 | 96 | #define OPTION_VENDOR_ID 0x0AF0 |
| 78 | #define HUAWEI_VENDOR_ID 0x12D1 | 97 | #define HUAWEI_VENDOR_ID 0x12D1 |
| 79 | #define AUDIOVOX_VENDOR_ID 0x0F3D | 98 | #define AUDIOVOX_VENDOR_ID 0x0F3D |
| 80 | 99 | #define SIERRAWIRELESS_VENDOR_ID 0x1199 | |
| 81 | #define OPTION_PRODUCT_OLD 0x5000 | 100 | #define NOVATELWIRELESS_VENDOR_ID 0x1410 |
| 82 | #define OPTION_PRODUCT_FUSION 0x6000 | 101 | |
| 83 | #define OPTION_PRODUCT_FUSION2 0x6300 | 102 | #define OPTION_PRODUCT_OLD 0x5000 |
| 84 | #define HUAWEI_PRODUCT_E600 0x1001 | 103 | #define OPTION_PRODUCT_FUSION 0x6000 |
| 85 | #define AUDIOVOX_PRODUCT_AIRCARD 0x0112 | 104 | #define OPTION_PRODUCT_FUSION2 0x6300 |
| 105 | #define OPTION_PRODUCT_COBRA 0x6500 | ||
| 106 | #define HUAWEI_PRODUCT_E600 0x1001 | ||
| 107 | #define AUDIOVOX_PRODUCT_AIRCARD 0x0112 | ||
| 108 | #define SIERRAWIRELESS_PRODUCT_MC8755 0x6802 | ||
| 109 | #define NOVATELWIRELESS_PRODUCT_U740 0x1400 | ||
| 86 | 110 | ||
| 87 | static struct usb_device_id option_ids[] = { | 111 | static struct usb_device_id option_ids[] = { |
| 88 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, | 112 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, |
| 89 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, | 113 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, |
| 90 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, | 114 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, |
| 115 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, | ||
| 91 | { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, | 116 | { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, |
| 92 | { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, | 117 | { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, |
| 118 | { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) }, | ||
| 119 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, | ||
| 120 | { } /* Terminating entry */ | ||
| 121 | }; | ||
| 122 | |||
| 123 | static struct usb_device_id option_ids1[] = { | ||
| 124 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, | ||
| 125 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, | ||
| 126 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, | ||
| 127 | { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, | ||
| 128 | { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, | ||
| 129 | { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, | ||
| 130 | { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, | ||
| 131 | { } /* Terminating entry */ | ||
| 132 | }; | ||
| 133 | static struct usb_device_id option_ids3[] = { | ||
| 134 | { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) }, | ||
| 93 | { } /* Terminating entry */ | 135 | { } /* Terminating entry */ |
| 94 | }; | 136 | }; |
| 95 | 137 | ||
| @@ -111,12 +153,39 @@ static struct usb_serial_driver option_3port_device = { | |||
| 111 | .owner = THIS_MODULE, | 153 | .owner = THIS_MODULE, |
| 112 | .name = "option", | 154 | .name = "option", |
| 113 | }, | 155 | }, |
| 114 | .description = "Option 3G data card", | 156 | .description = "GSM modem (3-port)", |
| 115 | .id_table = option_ids, | 157 | .id_table = option_ids3, |
| 116 | .num_interrupt_in = NUM_DONT_CARE, | 158 | .num_interrupt_in = NUM_DONT_CARE, |
| 117 | .num_bulk_in = NUM_DONT_CARE, | 159 | .num_bulk_in = NUM_DONT_CARE, |
| 118 | .num_bulk_out = NUM_DONT_CARE, | 160 | .num_bulk_out = NUM_DONT_CARE, |
| 119 | .num_ports = 1, /* 3, but the card reports its ports separately */ | 161 | .num_ports = 3, |
| 162 | .open = option_open, | ||
| 163 | .close = option_close, | ||
| 164 | .write = option_write, | ||
| 165 | .write_room = option_write_room, | ||
| 166 | .chars_in_buffer = option_chars_in_buffer, | ||
| 167 | .throttle = option_rx_throttle, | ||
| 168 | .unthrottle = option_rx_unthrottle, | ||
| 169 | .set_termios = option_set_termios, | ||
| 170 | .break_ctl = option_break_ctl, | ||
| 171 | .tiocmget = option_tiocmget, | ||
| 172 | .tiocmset = option_tiocmset, | ||
| 173 | .attach = option_startup, | ||
| 174 | .shutdown = option_shutdown, | ||
| 175 | .read_int_callback = option_instat_callback, | ||
| 176 | }; | ||
| 177 | |||
| 178 | static struct usb_serial_driver option_1port_device = { | ||
| 179 | .driver = { | ||
| 180 | .owner = THIS_MODULE, | ||
| 181 | .name = "option", | ||
| 182 | }, | ||
| 183 | .description = "GSM modem (1-port)", | ||
| 184 | .id_table = option_ids1, | ||
| 185 | .num_interrupt_in = NUM_DONT_CARE, | ||
| 186 | .num_bulk_in = NUM_DONT_CARE, | ||
| 187 | .num_bulk_out = NUM_DONT_CARE, | ||
| 188 | .num_ports = 1, | ||
| 120 | .open = option_open, | 189 | .open = option_open, |
| 121 | .close = option_close, | 190 | .close = option_close, |
| 122 | .write = option_write, | 191 | .write = option_write, |
| @@ -170,6 +239,9 @@ struct option_port_private { | |||
| 170 | static int __init option_init(void) | 239 | static int __init option_init(void) |
| 171 | { | 240 | { |
| 172 | int retval; | 241 | int retval; |
| 242 | retval = usb_serial_register(&option_1port_device); | ||
| 243 | if (retval) | ||
| 244 | goto failed_1port_device_register; | ||
| 173 | retval = usb_serial_register(&option_3port_device); | 245 | retval = usb_serial_register(&option_3port_device); |
| 174 | if (retval) | 246 | if (retval) |
| 175 | goto failed_3port_device_register; | 247 | goto failed_3port_device_register; |
| @@ -184,6 +256,8 @@ static int __init option_init(void) | |||
| 184 | failed_driver_register: | 256 | failed_driver_register: |
| 185 | usb_serial_deregister (&option_3port_device); | 257 | usb_serial_deregister (&option_3port_device); |
| 186 | failed_3port_device_register: | 258 | failed_3port_device_register: |
| 259 | usb_serial_deregister (&option_1port_device); | ||
| 260 | failed_1port_device_register: | ||
| 187 | return retval; | 261 | return retval; |
| 188 | } | 262 | } |
| 189 | 263 | ||
| @@ -191,6 +265,7 @@ static void __exit option_exit(void) | |||
| 191 | { | 265 | { |
| 192 | usb_deregister (&option_driver); | 266 | usb_deregister (&option_driver); |
| 193 | usb_serial_deregister (&option_3port_device); | 267 | usb_serial_deregister (&option_3port_device); |
| 268 | usb_serial_deregister (&option_1port_device); | ||
| 194 | } | 269 | } |
| 195 | 270 | ||
| 196 | module_init(option_init); | 271 | module_init(option_init); |
| @@ -365,8 +440,7 @@ static void option_outdat_callback(struct urb *urb, struct pt_regs *regs) | |||
| 365 | 440 | ||
| 366 | port = (struct usb_serial_port *) urb->context; | 441 | port = (struct usb_serial_port *) urb->context; |
| 367 | 442 | ||
| 368 | if (port->open_count) | 443 | usb_serial_port_softint(port); |
| 369 | schedule_work(&port->work); | ||
| 370 | } | 444 | } |
| 371 | 445 | ||
| 372 | static void option_instat_callback(struct urb *urb, struct pt_regs *regs) | 446 | static void option_instat_callback(struct urb *urb, struct pt_regs *regs) |
| @@ -573,27 +647,30 @@ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint, | |||
| 573 | /* Setup urbs */ | 647 | /* Setup urbs */ |
| 574 | static void option_setup_urbs(struct usb_serial *serial) | 648 | static void option_setup_urbs(struct usb_serial *serial) |
| 575 | { | 649 | { |
| 576 | int j; | 650 | int i,j; |
| 577 | struct usb_serial_port *port; | 651 | struct usb_serial_port *port; |
| 578 | struct option_port_private *portdata; | 652 | struct option_port_private *portdata; |
| 579 | 653 | ||
| 580 | dbg("%s", __FUNCTION__); | 654 | dbg("%s", __FUNCTION__); |
| 581 | 655 | ||
| 582 | port = serial->port[0]; | 656 | |
| 583 | portdata = usb_get_serial_port_data(port); | 657 | for (i = 0; i < serial->num_ports; i++) { |
| 658 | port = serial->port[i]; | ||
| 659 | portdata = usb_get_serial_port_data(port); | ||
| 584 | 660 | ||
| 585 | /* Do indat endpoints first */ | 661 | /* Do indat endpoints first */ |
| 586 | for (j = 0; j < N_IN_URB; ++j) { | 662 | for (j = 0; j < N_IN_URB; ++j) { |
| 587 | portdata->in_urbs[j] = option_setup_urb (serial, | 663 | portdata->in_urbs[j] = option_setup_urb (serial, |
| 588 | port->bulk_in_endpointAddress, USB_DIR_IN, port, | 664 | port->bulk_in_endpointAddress, USB_DIR_IN, port, |
| 589 | portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); | 665 | portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); |
| 590 | } | 666 | } |
| 591 | 667 | ||
| 592 | /* outdat endpoints */ | 668 | /* outdat endpoints */ |
| 593 | for (j = 0; j < N_OUT_URB; ++j) { | 669 | for (j = 0; j < N_OUT_URB; ++j) { |
| 594 | portdata->out_urbs[j] = option_setup_urb (serial, | 670 | portdata->out_urbs[j] = option_setup_urb (serial, |
| 595 | port->bulk_out_endpointAddress, USB_DIR_OUT, port, | 671 | port->bulk_out_endpointAddress, USB_DIR_OUT, port, |
| 596 | portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); | 672 | portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); |
| 673 | } | ||
| 597 | } | 674 | } |
| 598 | } | 675 | } |
| 599 | 676 | ||
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index c96714bb1cb8..d88704387202 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c | |||
| @@ -314,7 +314,7 @@ static void pl2303_send(struct usb_serial_port *port) | |||
| 314 | // TODO: reschedule pl2303_send | 314 | // TODO: reschedule pl2303_send |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | schedule_work(&port->work); | 317 | usb_serial_port_softint(port); |
| 318 | } | 318 | } |
| 319 | 319 | ||
| 320 | static int pl2303_write_room(struct usb_serial_port *port) | 320 | static int pl2303_write_room(struct usb_serial_port *port) |
| @@ -600,7 +600,7 @@ static void pl2303_close (struct usb_serial_port *port, struct file *filp) | |||
| 600 | unsigned int c_cflag; | 600 | unsigned int c_cflag; |
| 601 | int bps; | 601 | int bps; |
| 602 | long timeout; | 602 | long timeout; |
| 603 | wait_queue_t wait; \ | 603 | wait_queue_t wait; |
| 604 | 604 | ||
| 605 | dbg("%s - port %d", __FUNCTION__, port->number); | 605 | dbg("%s - port %d", __FUNCTION__, port->number); |
| 606 | 606 | ||
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 9c36f0ece20f..a30135c7cfe6 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
| @@ -162,12 +162,19 @@ static void destroy_serial(struct kref *kref) | |||
| 162 | } | 162 | } |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | flush_scheduled_work(); /* port->work */ | ||
| 166 | |||
| 165 | usb_put_dev(serial->dev); | 167 | usb_put_dev(serial->dev); |
| 166 | 168 | ||
| 167 | /* free up any memory that we allocated */ | 169 | /* free up any memory that we allocated */ |
| 168 | kfree (serial); | 170 | kfree (serial); |
| 169 | } | 171 | } |
| 170 | 172 | ||
| 173 | void usb_serial_put(struct usb_serial *serial) | ||
| 174 | { | ||
| 175 | kref_put(&serial->kref, destroy_serial); | ||
| 176 | } | ||
| 177 | |||
| 171 | /***************************************************************************** | 178 | /***************************************************************************** |
| 172 | * Driver tty interface functions | 179 | * Driver tty interface functions |
| 173 | *****************************************************************************/ | 180 | *****************************************************************************/ |
| @@ -201,12 +208,12 @@ static int serial_open (struct tty_struct *tty, struct file * filp) | |||
| 201 | 208 | ||
| 202 | ++port->open_count; | 209 | ++port->open_count; |
| 203 | 210 | ||
| 204 | if (port->open_count == 1) { | 211 | /* set up our port structure making the tty driver |
| 212 | * remember our port object, and us it */ | ||
| 213 | tty->driver_data = port; | ||
| 214 | port->tty = tty; | ||
| 205 | 215 | ||
| 206 | /* set up our port structure making the tty driver | 216 | if (port->open_count == 1) { |
| 207 | * remember our port object, and us it */ | ||
| 208 | tty->driver_data = port; | ||
| 209 | port->tty = tty; | ||
| 210 | 217 | ||
| 211 | /* lock this module before we call it | 218 | /* lock this module before we call it |
| 212 | * this may fail, which means we must bail out, | 219 | * this may fail, which means we must bail out, |
| @@ -230,9 +237,11 @@ bailout_module_put: | |||
| 230 | module_put(serial->type->driver.owner); | 237 | module_put(serial->type->driver.owner); |
| 231 | bailout_mutex_unlock: | 238 | bailout_mutex_unlock: |
| 232 | port->open_count = 0; | 239 | port->open_count = 0; |
| 240 | tty->driver_data = NULL; | ||
| 241 | port->tty = NULL; | ||
| 233 | mutex_unlock(&port->mutex); | 242 | mutex_unlock(&port->mutex); |
| 234 | bailout_kref_put: | 243 | bailout_kref_put: |
| 235 | kref_put(&serial->kref, destroy_serial); | 244 | usb_serial_put(serial); |
| 236 | return retval; | 245 | return retval; |
| 237 | } | 246 | } |
| 238 | 247 | ||
| @@ -268,7 +277,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) | |||
| 268 | } | 277 | } |
| 269 | 278 | ||
| 270 | mutex_unlock(&port->mutex); | 279 | mutex_unlock(&port->mutex); |
| 271 | kref_put(&port->serial->kref, destroy_serial); | 280 | usb_serial_put(port->serial); |
| 272 | } | 281 | } |
| 273 | 282 | ||
| 274 | static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) | 283 | static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count) |
| @@ -276,7 +285,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int | |||
| 276 | struct usb_serial_port *port = tty->driver_data; | 285 | struct usb_serial_port *port = tty->driver_data; |
| 277 | int retval = -EINVAL; | 286 | int retval = -EINVAL; |
| 278 | 287 | ||
| 279 | if (!port) | 288 | if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) |
| 280 | goto exit; | 289 | goto exit; |
| 281 | 290 | ||
| 282 | dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); | 291 | dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count); |
| @@ -296,7 +305,7 @@ exit: | |||
| 296 | static int serial_write_room (struct tty_struct *tty) | 305 | static int serial_write_room (struct tty_struct *tty) |
| 297 | { | 306 | { |
| 298 | struct usb_serial_port *port = tty->driver_data; | 307 | struct usb_serial_port *port = tty->driver_data; |
| 299 | int retval = -EINVAL; | 308 | int retval = -ENODEV; |
| 300 | 309 | ||
| 301 | if (!port) | 310 | if (!port) |
| 302 | goto exit; | 311 | goto exit; |
| @@ -318,7 +327,7 @@ exit: | |||
| 318 | static int serial_chars_in_buffer (struct tty_struct *tty) | 327 | static int serial_chars_in_buffer (struct tty_struct *tty) |
| 319 | { | 328 | { |
| 320 | struct usb_serial_port *port = tty->driver_data; | 329 | struct usb_serial_port *port = tty->driver_data; |
| 321 | int retval = -EINVAL; | 330 | int retval = -ENODEV; |
| 322 | 331 | ||
| 323 | if (!port) | 332 | if (!port) |
| 324 | goto exit; | 333 | goto exit; |
| @@ -473,7 +482,7 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int | |||
| 473 | begin += length; | 482 | begin += length; |
| 474 | length = 0; | 483 | length = 0; |
| 475 | } | 484 | } |
| 476 | kref_put(&serial->kref, destroy_serial); | 485 | usb_serial_put(serial); |
| 477 | } | 486 | } |
| 478 | *eof = 1; | 487 | *eof = 1; |
| 479 | done: | 488 | done: |
| @@ -488,19 +497,18 @@ static int serial_tiocmget (struct tty_struct *tty, struct file *file) | |||
| 488 | struct usb_serial_port *port = tty->driver_data; | 497 | struct usb_serial_port *port = tty->driver_data; |
| 489 | 498 | ||
| 490 | if (!port) | 499 | if (!port) |
| 491 | goto exit; | 500 | return -ENODEV; |
| 492 | 501 | ||
| 493 | dbg("%s - port %d", __FUNCTION__, port->number); | 502 | dbg("%s - port %d", __FUNCTION__, port->number); |
| 494 | 503 | ||
| 495 | if (!port->open_count) { | 504 | if (!port->open_count) { |
| 496 | dbg("%s - port not open", __FUNCTION__); | 505 | dbg("%s - port not open", __FUNCTION__); |
| 497 | goto exit; | 506 | return -ENODEV; |
| 498 | } | 507 | } |
| 499 | 508 | ||
| 500 | if (port->serial->type->tiocmget) | 509 | if (port->serial->type->tiocmget) |
| 501 | return port->serial->type->tiocmget(port, file); | 510 | return port->serial->type->tiocmget(port, file); |
| 502 | 511 | ||
| 503 | exit: | ||
| 504 | return -EINVAL; | 512 | return -EINVAL; |
| 505 | } | 513 | } |
| 506 | 514 | ||
| @@ -510,23 +518,32 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file, | |||
| 510 | struct usb_serial_port *port = tty->driver_data; | 518 | struct usb_serial_port *port = tty->driver_data; |
| 511 | 519 | ||
| 512 | if (!port) | 520 | if (!port) |
| 513 | goto exit; | 521 | return -ENODEV; |
| 514 | 522 | ||
| 515 | dbg("%s - port %d", __FUNCTION__, port->number); | 523 | dbg("%s - port %d", __FUNCTION__, port->number); |
| 516 | 524 | ||
| 517 | if (!port->open_count) { | 525 | if (!port->open_count) { |
| 518 | dbg("%s - port not open", __FUNCTION__); | 526 | dbg("%s - port not open", __FUNCTION__); |
| 519 | goto exit; | 527 | return -ENODEV; |
| 520 | } | 528 | } |
| 521 | 529 | ||
| 522 | if (port->serial->type->tiocmset) | 530 | if (port->serial->type->tiocmset) |
| 523 | return port->serial->type->tiocmset(port, file, set, clear); | 531 | return port->serial->type->tiocmset(port, file, set, clear); |
| 524 | 532 | ||
| 525 | exit: | ||
| 526 | return -EINVAL; | 533 | return -EINVAL; |
| 527 | } | 534 | } |
| 528 | 535 | ||
| 529 | void usb_serial_port_softint(void *private) | 536 | /* |
| 537 | * We would be calling tty_wakeup here, but unfortunately some line | ||
| 538 | * disciplines have an annoying habit of calling tty->write from | ||
| 539 | * the write wakeup callback (e.g. n_hdlc.c). | ||
| 540 | */ | ||
| 541 | void usb_serial_port_softint(struct usb_serial_port *port) | ||
| 542 | { | ||
| 543 | schedule_work(&port->work); | ||
| 544 | } | ||
| 545 | |||
| 546 | static void usb_serial_port_work(void *private) | ||
| 530 | { | 547 | { |
| 531 | struct usb_serial_port *port = private; | 548 | struct usb_serial_port *port = private; |
| 532 | struct tty_struct *tty; | 549 | struct tty_struct *tty; |
| @@ -789,7 +806,7 @@ int usb_serial_probe(struct usb_interface *interface, | |||
| 789 | port->serial = serial; | 806 | port->serial = serial; |
| 790 | spin_lock_init(&port->lock); | 807 | spin_lock_init(&port->lock); |
| 791 | mutex_init(&port->mutex); | 808 | mutex_init(&port->mutex); |
| 792 | INIT_WORK(&port->work, usb_serial_port_softint, port); | 809 | INIT_WORK(&port->work, usb_serial_port_work, port); |
| 793 | serial->port[i] = port; | 810 | serial->port[i] = port; |
| 794 | } | 811 | } |
| 795 | 812 | ||
| @@ -985,6 +1002,7 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
| 985 | struct device *dev = &interface->dev; | 1002 | struct device *dev = &interface->dev; |
| 986 | struct usb_serial_port *port; | 1003 | struct usb_serial_port *port; |
| 987 | 1004 | ||
| 1005 | usb_serial_console_disconnect(serial); | ||
| 988 | dbg ("%s", __FUNCTION__); | 1006 | dbg ("%s", __FUNCTION__); |
| 989 | 1007 | ||
| 990 | usb_set_intfdata (interface, NULL); | 1008 | usb_set_intfdata (interface, NULL); |
| @@ -996,7 +1014,7 @@ void usb_serial_disconnect(struct usb_interface *interface) | |||
| 996 | } | 1014 | } |
| 997 | /* let the last holder of this object | 1015 | /* let the last holder of this object |
| 998 | * cause it to be cleaned up */ | 1016 | * cause it to be cleaned up */ |
| 999 | kref_put(&serial->kref, destroy_serial); | 1017 | usb_serial_put(serial); |
| 1000 | } | 1018 | } |
| 1001 | dev_info(dev, "device disconnected\n"); | 1019 | dev_info(dev, "device disconnected\n"); |
| 1002 | } | 1020 | } |
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index dc89d8710460..d53ea9b11e81 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h | |||
| @@ -236,7 +236,7 @@ struct usb_serial_driver { | |||
| 236 | 236 | ||
| 237 | extern int usb_serial_register(struct usb_serial_driver *driver); | 237 | extern int usb_serial_register(struct usb_serial_driver *driver); |
| 238 | extern void usb_serial_deregister(struct usb_serial_driver *driver); | 238 | extern void usb_serial_deregister(struct usb_serial_driver *driver); |
| 239 | extern void usb_serial_port_softint(void *private); | 239 | extern void usb_serial_port_softint(struct usb_serial_port *port); |
| 240 | 240 | ||
| 241 | extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id); | 241 | extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id); |
| 242 | extern void usb_serial_disconnect(struct usb_interface *iface); | 242 | extern void usb_serial_disconnect(struct usb_interface *iface); |
| @@ -248,13 +248,16 @@ extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit); | |||
| 248 | #ifdef CONFIG_USB_SERIAL_CONSOLE | 248 | #ifdef CONFIG_USB_SERIAL_CONSOLE |
| 249 | extern void usb_serial_console_init (int debug, int minor); | 249 | extern void usb_serial_console_init (int debug, int minor); |
| 250 | extern void usb_serial_console_exit (void); | 250 | extern void usb_serial_console_exit (void); |
| 251 | extern void usb_serial_console_disconnect(struct usb_serial *serial); | ||
| 251 | #else | 252 | #else |
| 252 | static inline void usb_serial_console_init (int debug, int minor) { } | 253 | static inline void usb_serial_console_init (int debug, int minor) { } |
| 253 | static inline void usb_serial_console_exit (void) { } | 254 | static inline void usb_serial_console_exit (void) { } |
| 255 | static inline void usb_serial_console_disconnect(struct usb_serial *serial) {} | ||
| 254 | #endif | 256 | #endif |
| 255 | 257 | ||
| 256 | /* Functions needed by other parts of the usbserial core */ | 258 | /* Functions needed by other parts of the usbserial core */ |
| 257 | extern struct usb_serial *usb_serial_get_by_index (unsigned int minor); | 259 | extern struct usb_serial *usb_serial_get_by_index (unsigned int minor); |
| 260 | extern void usb_serial_put(struct usb_serial *serial); | ||
| 258 | extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp); | 261 | extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp); |
| 259 | extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count); | 262 | extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count); |
| 260 | extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp); | 263 | extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp); |
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index f5c3841d4843..9e89b8d54f72 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c | |||
| @@ -480,7 +480,7 @@ static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs) | |||
| 480 | --priv->outstanding_urbs; | 480 | --priv->outstanding_urbs; |
| 481 | spin_unlock_irqrestore(&priv->lock, flags); | 481 | spin_unlock_irqrestore(&priv->lock, flags); |
| 482 | 482 | ||
| 483 | schedule_work(&port->work); | 483 | usb_serial_port_softint(port); |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | 486 | ||
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index f806553cd9a4..5b06fa366098 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c | |||
| @@ -388,7 +388,7 @@ static int whiteheat_attach (struct usb_serial *serial) | |||
| 388 | if (ret) { | 388 | if (ret) { |
| 389 | err("%s: Couldn't send command [%d]", serial->type->description, ret); | 389 | err("%s: Couldn't send command [%d]", serial->type->description, ret); |
| 390 | goto no_firmware; | 390 | goto no_firmware; |
| 391 | } else if (alen != sizeof(command)) { | 391 | } else if (alen != 2) { |
| 392 | err("%s: Send command incomplete [%d]", serial->type->description, alen); | 392 | err("%s: Send command incomplete [%d]", serial->type->description, alen); |
| 393 | goto no_firmware; | 393 | goto no_firmware; |
| 394 | } | 394 | } |
| @@ -400,7 +400,7 @@ static int whiteheat_attach (struct usb_serial *serial) | |||
| 400 | if (ret) { | 400 | if (ret) { |
| 401 | err("%s: Couldn't get results [%d]", serial->type->description, ret); | 401 | err("%s: Couldn't get results [%d]", serial->type->description, ret); |
| 402 | goto no_firmware; | 402 | goto no_firmware; |
| 403 | } else if (alen != sizeof(result)) { | 403 | } else if (alen != sizeof(*hw_info) + 1) { |
| 404 | err("%s: Get results incomplete [%d]", serial->type->description, alen); | 404 | err("%s: Get results incomplete [%d]", serial->type->description, alen); |
| 405 | goto no_firmware; | 405 | goto no_firmware; |
| 406 | } else if (result[0] != command[0]) { | 406 | } else if (result[0] != command[0]) { |
| @@ -1089,9 +1089,7 @@ static void whiteheat_write_callback(struct urb *urb, struct pt_regs *regs) | |||
| 1089 | return; | 1089 | return; |
| 1090 | } | 1090 | } |
| 1091 | 1091 | ||
| 1092 | usb_serial_port_softint((void *)port); | 1092 | usb_serial_port_softint(port); |
| 1093 | |||
| 1094 | schedule_work(&port->work); | ||
| 1095 | } | 1093 | } |
| 1096 | 1094 | ||
| 1097 | 1095 | ||
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 55ee2d36d585..026a587eb8dd 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c | |||
| @@ -34,9 +34,8 @@ | |||
| 34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| 35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
| 36 | #include <linux/module.h> | 36 | #include <linux/module.h> |
| 37 | #include <linux/usb.h> | ||
| 38 | #include <linux/usb_ch9.h> | 37 | #include <linux/usb_ch9.h> |
| 39 | #include <linux/usb_input.h> | 38 | #include <linux/usb/input.h> |
| 40 | #include "usb.h" | 39 | #include "usb.h" |
| 41 | #include "onetouch.h" | 40 | #include "onetouch.h" |
| 42 | #include "debug.h" | 41 | #include "debug.h" |
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 5f11e19eaae3..5715291ba540 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c | |||
| @@ -286,11 +286,7 @@ static int bus_reset(struct scsi_cmnd *srb) | |||
| 286 | int result; | 286 | int result; |
| 287 | 287 | ||
| 288 | US_DEBUGP("%s called\n", __FUNCTION__); | 288 | US_DEBUGP("%s called\n", __FUNCTION__); |
| 289 | |||
| 290 | mutex_lock(&(us->dev_mutex)); | ||
| 291 | result = usb_stor_port_reset(us); | 289 | result = usb_stor_port_reset(us); |
| 292 | mutex_unlock(&us->dev_mutex); | ||
| 293 | |||
| 294 | return result < 0 ? FAILED : SUCCESS; | 290 | return result < 0 ? FAILED : SUCCESS; |
| 295 | } | 291 | } |
| 296 | 292 | ||
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index f2bc5c9e23d5..8fcec01dc622 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c | |||
| @@ -131,28 +131,30 @@ static int usbat_write(struct us_data *us, | |||
| 131 | * Convenience function to perform a bulk read | 131 | * Convenience function to perform a bulk read |
| 132 | */ | 132 | */ |
| 133 | static int usbat_bulk_read(struct us_data *us, | 133 | static int usbat_bulk_read(struct us_data *us, |
| 134 | unsigned char *data, | 134 | unsigned char *data, |
| 135 | unsigned int len) | 135 | unsigned int len, |
| 136 | int use_sg) | ||
| 136 | { | 137 | { |
| 137 | if (len == 0) | 138 | if (len == 0) |
| 138 | return USB_STOR_XFER_GOOD; | 139 | return USB_STOR_XFER_GOOD; |
| 139 | 140 | ||
| 140 | US_DEBUGP("usbat_bulk_read: len = %d\n", len); | 141 | US_DEBUGP("usbat_bulk_read: len = %d\n", len); |
| 141 | return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, data, len, NULL); | 142 | return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, data, len, use_sg, NULL); |
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | /* | 145 | /* |
| 145 | * Convenience function to perform a bulk write | 146 | * Convenience function to perform a bulk write |
| 146 | */ | 147 | */ |
| 147 | static int usbat_bulk_write(struct us_data *us, | 148 | static int usbat_bulk_write(struct us_data *us, |
| 148 | unsigned char *data, | 149 | unsigned char *data, |
| 149 | unsigned int len) | 150 | unsigned int len, |
| 151 | int use_sg) | ||
| 150 | { | 152 | { |
| 151 | if (len == 0) | 153 | if (len == 0) |
| 152 | return USB_STOR_XFER_GOOD; | 154 | return USB_STOR_XFER_GOOD; |
| 153 | 155 | ||
| 154 | US_DEBUGP("usbat_bulk_write: len = %d\n", len); | 156 | US_DEBUGP("usbat_bulk_write: len = %d\n", len); |
| 155 | return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, data, len, NULL); | 157 | return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, data, len, use_sg, NULL); |
| 156 | } | 158 | } |
| 157 | 159 | ||
| 158 | /* | 160 | /* |
| @@ -317,7 +319,8 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes) | |||
| 317 | */ | 319 | */ |
| 318 | static int usbat_read_block(struct us_data *us, | 320 | static int usbat_read_block(struct us_data *us, |
| 319 | unsigned char *content, | 321 | unsigned char *content, |
| 320 | unsigned short len) | 322 | unsigned short len, |
| 323 | int use_sg) | ||
| 321 | { | 324 | { |
| 322 | int result; | 325 | int result; |
| 323 | unsigned char *command = us->iobuf; | 326 | unsigned char *command = us->iobuf; |
| @@ -338,7 +341,7 @@ static int usbat_read_block(struct us_data *us, | |||
| 338 | if (result != USB_STOR_XFER_GOOD) | 341 | if (result != USB_STOR_XFER_GOOD) |
| 339 | return USB_STOR_TRANSPORT_ERROR; | 342 | return USB_STOR_TRANSPORT_ERROR; |
| 340 | 343 | ||
| 341 | result = usbat_bulk_read(us, content, len); | 344 | result = usbat_bulk_read(us, content, len, use_sg); |
| 342 | return (result == USB_STOR_XFER_GOOD ? | 345 | return (result == USB_STOR_XFER_GOOD ? |
| 343 | USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); | 346 | USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); |
| 344 | } | 347 | } |
| @@ -350,7 +353,8 @@ static int usbat_write_block(struct us_data *us, | |||
| 350 | unsigned char access, | 353 | unsigned char access, |
| 351 | unsigned char *content, | 354 | unsigned char *content, |
| 352 | unsigned short len, | 355 | unsigned short len, |
| 353 | int minutes) | 356 | int minutes, |
| 357 | int use_sg) | ||
| 354 | { | 358 | { |
| 355 | int result; | 359 | int result; |
| 356 | unsigned char *command = us->iobuf; | 360 | unsigned char *command = us->iobuf; |
| @@ -372,7 +376,7 @@ static int usbat_write_block(struct us_data *us, | |||
| 372 | if (result != USB_STOR_XFER_GOOD) | 376 | if (result != USB_STOR_XFER_GOOD) |
| 373 | return USB_STOR_TRANSPORT_ERROR; | 377 | return USB_STOR_TRANSPORT_ERROR; |
| 374 | 378 | ||
| 375 | result = usbat_bulk_write(us, content, len); | 379 | result = usbat_bulk_write(us, content, len, use_sg); |
| 376 | if (result != USB_STOR_XFER_GOOD) | 380 | if (result != USB_STOR_XFER_GOOD) |
| 377 | return USB_STOR_TRANSPORT_ERROR; | 381 | return USB_STOR_TRANSPORT_ERROR; |
| 378 | 382 | ||
| @@ -465,7 +469,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, | |||
| 465 | data[1+(j<<1)] = data_out[j]; | 469 | data[1+(j<<1)] = data_out[j]; |
| 466 | } | 470 | } |
| 467 | 471 | ||
| 468 | result = usbat_bulk_write(us, data, num_registers*2); | 472 | result = usbat_bulk_write(us, data, num_registers*2, 0); |
| 469 | if (result != USB_STOR_XFER_GOOD) | 473 | if (result != USB_STOR_XFER_GOOD) |
| 470 | return USB_STOR_TRANSPORT_ERROR; | 474 | return USB_STOR_TRANSPORT_ERROR; |
| 471 | 475 | ||
| @@ -583,7 +587,7 @@ static int usbat_multiple_write(struct us_data *us, | |||
| 583 | } | 587 | } |
| 584 | 588 | ||
| 585 | /* Send the data */ | 589 | /* Send the data */ |
| 586 | result = usbat_bulk_write(us, data, num_registers*2); | 590 | result = usbat_bulk_write(us, data, num_registers*2, 0); |
| 587 | if (result != USB_STOR_XFER_GOOD) | 591 | if (result != USB_STOR_XFER_GOOD) |
| 588 | return USB_STOR_TRANSPORT_ERROR; | 592 | return USB_STOR_TRANSPORT_ERROR; |
| 589 | 593 | ||
| @@ -606,8 +610,9 @@ static int usbat_multiple_write(struct us_data *us, | |||
| 606 | * other related details) are defined beforehand with _set_shuttle_features(). | 610 | * other related details) are defined beforehand with _set_shuttle_features(). |
| 607 | */ | 611 | */ |
| 608 | static int usbat_read_blocks(struct us_data *us, | 612 | static int usbat_read_blocks(struct us_data *us, |
| 609 | unsigned char *buffer, | 613 | unsigned char *buffer, |
| 610 | int len) | 614 | int len, |
| 615 | int use_sg) | ||
| 611 | { | 616 | { |
| 612 | int result; | 617 | int result; |
| 613 | unsigned char *command = us->iobuf; | 618 | unsigned char *command = us->iobuf; |
| @@ -627,7 +632,7 @@ static int usbat_read_blocks(struct us_data *us, | |||
| 627 | return USB_STOR_TRANSPORT_FAILED; | 632 | return USB_STOR_TRANSPORT_FAILED; |
| 628 | 633 | ||
| 629 | /* Read the blocks we just asked for */ | 634 | /* Read the blocks we just asked for */ |
| 630 | result = usbat_bulk_read(us, buffer, len); | 635 | result = usbat_bulk_read(us, buffer, len, use_sg); |
| 631 | if (result != USB_STOR_XFER_GOOD) | 636 | if (result != USB_STOR_XFER_GOOD) |
| 632 | return USB_STOR_TRANSPORT_FAILED; | 637 | return USB_STOR_TRANSPORT_FAILED; |
| 633 | 638 | ||
| @@ -648,7 +653,8 @@ static int usbat_read_blocks(struct us_data *us, | |||
| 648 | */ | 653 | */ |
| 649 | static int usbat_write_blocks(struct us_data *us, | 654 | static int usbat_write_blocks(struct us_data *us, |
| 650 | unsigned char *buffer, | 655 | unsigned char *buffer, |
| 651 | int len) | 656 | int len, |
| 657 | int use_sg) | ||
| 652 | { | 658 | { |
| 653 | int result; | 659 | int result; |
| 654 | unsigned char *command = us->iobuf; | 660 | unsigned char *command = us->iobuf; |
| @@ -668,7 +674,7 @@ static int usbat_write_blocks(struct us_data *us, | |||
| 668 | return USB_STOR_TRANSPORT_FAILED; | 674 | return USB_STOR_TRANSPORT_FAILED; |
| 669 | 675 | ||
| 670 | /* Write the data */ | 676 | /* Write the data */ |
| 671 | result = usbat_bulk_write(us, buffer, len); | 677 | result = usbat_bulk_write(us, buffer, len, use_sg); |
| 672 | if (result != USB_STOR_XFER_GOOD) | 678 | if (result != USB_STOR_XFER_GOOD) |
| 673 | return USB_STOR_TRANSPORT_FAILED; | 679 | return USB_STOR_TRANSPORT_FAILED; |
| 674 | 680 | ||
| @@ -887,22 +893,28 @@ static int usbat_identify_device(struct us_data *us, | |||
| 887 | * Set the transport function based on the device type | 893 | * Set the transport function based on the device type |
| 888 | */ | 894 | */ |
| 889 | static int usbat_set_transport(struct us_data *us, | 895 | static int usbat_set_transport(struct us_data *us, |
| 890 | struct usbat_info *info) | 896 | struct usbat_info *info, |
| 897 | int devicetype) | ||
| 891 | { | 898 | { |
| 892 | int rc; | ||
| 893 | 899 | ||
| 894 | if (!info->devicetype) { | 900 | if (!info->devicetype) |
| 895 | rc = usbat_identify_device(us, info); | 901 | info->devicetype = devicetype; |
| 896 | if (rc != USB_STOR_TRANSPORT_GOOD) { | ||
| 897 | US_DEBUGP("usbat_set_transport: Could not identify device\n"); | ||
| 898 | return 1; | ||
| 899 | } | ||
| 900 | } | ||
| 901 | 902 | ||
| 902 | if (usbat_get_device_type(us) == USBAT_DEV_HP8200) | 903 | if (!info->devicetype) |
| 904 | usbat_identify_device(us, info); | ||
| 905 | |||
| 906 | switch (info->devicetype) { | ||
| 907 | default: | ||
| 908 | return USB_STOR_TRANSPORT_ERROR; | ||
| 909 | |||
| 910 | case USBAT_DEV_HP8200: | ||
| 903 | us->transport = usbat_hp8200e_transport; | 911 | us->transport = usbat_hp8200e_transport; |
| 904 | else if (usbat_get_device_type(us) == USBAT_DEV_FLASH) | 912 | break; |
| 913 | |||
| 914 | case USBAT_DEV_FLASH: | ||
| 905 | us->transport = usbat_flash_transport; | 915 | us->transport = usbat_flash_transport; |
| 916 | break; | ||
| 917 | } | ||
| 906 | 918 | ||
| 907 | return 0; | 919 | return 0; |
| 908 | } | 920 | } |
| @@ -947,7 +959,7 @@ static int usbat_flash_get_sector_count(struct us_data *us, | |||
| 947 | msleep(100); | 959 | msleep(100); |
| 948 | 960 | ||
| 949 | /* Read the device identification data */ | 961 | /* Read the device identification data */ |
| 950 | rc = usbat_read_block(us, reply, 512); | 962 | rc = usbat_read_block(us, reply, 512, 0); |
| 951 | if (rc != USB_STOR_TRANSPORT_GOOD) | 963 | if (rc != USB_STOR_TRANSPORT_GOOD) |
| 952 | goto leave; | 964 | goto leave; |
| 953 | 965 | ||
| @@ -1031,7 +1043,7 @@ static int usbat_flash_read_data(struct us_data *us, | |||
| 1031 | goto leave; | 1043 | goto leave; |
| 1032 | 1044 | ||
| 1033 | /* Read the data we just requested */ | 1045 | /* Read the data we just requested */ |
| 1034 | result = usbat_read_blocks(us, buffer, len); | 1046 | result = usbat_read_blocks(us, buffer, len, 0); |
| 1035 | if (result != USB_STOR_TRANSPORT_GOOD) | 1047 | if (result != USB_STOR_TRANSPORT_GOOD) |
| 1036 | goto leave; | 1048 | goto leave; |
| 1037 | 1049 | ||
| @@ -1125,7 +1137,7 @@ static int usbat_flash_write_data(struct us_data *us, | |||
| 1125 | goto leave; | 1137 | goto leave; |
| 1126 | 1138 | ||
| 1127 | /* Write the data */ | 1139 | /* Write the data */ |
| 1128 | result = usbat_write_blocks(us, buffer, len); | 1140 | result = usbat_write_blocks(us, buffer, len, 0); |
| 1129 | if (result != USB_STOR_TRANSPORT_GOOD) | 1141 | if (result != USB_STOR_TRANSPORT_GOOD) |
| 1130 | goto leave; | 1142 | goto leave; |
| 1131 | 1143 | ||
| @@ -1310,7 +1322,7 @@ static int usbat_select_and_test_registers(struct us_data *us) | |||
| 1310 | /* | 1322 | /* |
| 1311 | * Initialize the USBAT processor and the storage device | 1323 | * Initialize the USBAT processor and the storage device |
| 1312 | */ | 1324 | */ |
| 1313 | int init_usbat(struct us_data *us) | 1325 | static int init_usbat(struct us_data *us, int devicetype) |
| 1314 | { | 1326 | { |
| 1315 | int rc; | 1327 | int rc; |
| 1316 | struct usbat_info *info; | 1328 | struct usbat_info *info; |
| @@ -1392,7 +1404,7 @@ int init_usbat(struct us_data *us) | |||
| 1392 | US_DEBUGP("INIT 9\n"); | 1404 | US_DEBUGP("INIT 9\n"); |
| 1393 | 1405 | ||
| 1394 | /* At this point, we need to detect which device we are using */ | 1406 | /* At this point, we need to detect which device we are using */ |
| 1395 | if (usbat_set_transport(us, info)) | 1407 | if (usbat_set_transport(us, info, devicetype)) |
| 1396 | return USB_STOR_TRANSPORT_ERROR; | 1408 | return USB_STOR_TRANSPORT_ERROR; |
| 1397 | 1409 | ||
| 1398 | US_DEBUGP("INIT 10\n"); | 1410 | US_DEBUGP("INIT 10\n"); |
| @@ -1503,10 +1515,10 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) | |||
| 1503 | * AT SPEED 4 IS UNRELIABLE!!! | 1515 | * AT SPEED 4 IS UNRELIABLE!!! |
| 1504 | */ | 1516 | */ |
| 1505 | 1517 | ||
| 1506 | if ( (result = usbat_write_block(us, | 1518 | if ((result = usbat_write_block(us, |
| 1507 | USBAT_ATA, srb->cmnd, 12, | 1519 | USBAT_ATA, srb->cmnd, 12, |
| 1508 | srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) != | 1520 | (srb->cmnd[0]==GPCMD_BLANK ? 75 : 10), 0) != |
| 1509 | USB_STOR_TRANSPORT_GOOD) { | 1521 | USB_STOR_TRANSPORT_GOOD)) { |
| 1510 | return result; | 1522 | return result; |
| 1511 | } | 1523 | } |
| 1512 | 1524 | ||
| @@ -1533,7 +1545,7 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) | |||
| 1533 | len = *status; | 1545 | len = *status; |
| 1534 | 1546 | ||
| 1535 | 1547 | ||
| 1536 | result = usbat_read_block(us, srb->request_buffer, len); | 1548 | result = usbat_read_block(us, srb->request_buffer, len, srb->use_sg); |
| 1537 | 1549 | ||
| 1538 | /* Debug-print the first 32 bytes of the transfer */ | 1550 | /* Debug-print the first 32 bytes of the transfer */ |
| 1539 | 1551 | ||
| @@ -1695,6 +1707,22 @@ static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) | |||
| 1695 | return USB_STOR_TRANSPORT_FAILED; | 1707 | return USB_STOR_TRANSPORT_FAILED; |
| 1696 | } | 1708 | } |
| 1697 | 1709 | ||
| 1710 | int init_usbat_cd(struct us_data *us) | ||
| 1711 | { | ||
| 1712 | return init_usbat(us, USBAT_DEV_HP8200); | ||
| 1713 | } | ||
| 1714 | |||
| 1715 | |||
| 1716 | int init_usbat_flash(struct us_data *us) | ||
| 1717 | { | ||
| 1718 | return init_usbat(us, USBAT_DEV_FLASH); | ||
| 1719 | } | ||
| 1720 | |||
| 1721 | int init_usbat_probe(struct us_data *us) | ||
| 1722 | { | ||
| 1723 | return init_usbat(us, 0); | ||
| 1724 | } | ||
| 1725 | |||
| 1698 | /* | 1726 | /* |
| 1699 | * Default transport function. Attempts to detect which transport function | 1727 | * Default transport function. Attempts to detect which transport function |
| 1700 | * should be called, makes it the new default, and calls it. | 1728 | * should be called, makes it the new default, and calls it. |
| @@ -1708,9 +1736,8 @@ int usbat_transport(struct scsi_cmnd *srb, struct us_data *us) | |||
| 1708 | { | 1736 | { |
| 1709 | struct usbat_info *info = (struct usbat_info*) (us->extra); | 1737 | struct usbat_info *info = (struct usbat_info*) (us->extra); |
| 1710 | 1738 | ||
| 1711 | if (usbat_set_transport(us, info)) | 1739 | if (usbat_set_transport(us, info, 0)) |
| 1712 | return USB_STOR_TRANSPORT_ERROR; | 1740 | return USB_STOR_TRANSPORT_ERROR; |
| 1713 | 1741 | ||
| 1714 | return us->transport(srb, us); | 1742 | return us->transport(srb, us); |
| 1715 | } | 1743 | } |
| 1716 | |||
diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h index 25e7d8b340b8..3ddf143a1dec 100644 --- a/drivers/usb/storage/shuttle_usbat.h +++ b/drivers/usb/storage/shuttle_usbat.h | |||
| @@ -106,7 +106,9 @@ | |||
| 106 | #define USBAT_FEAT_ET2 0x01 | 106 | #define USBAT_FEAT_ET2 0x01 |
| 107 | 107 | ||
| 108 | extern int usbat_transport(struct scsi_cmnd *srb, struct us_data *us); | 108 | extern int usbat_transport(struct scsi_cmnd *srb, struct us_data *us); |
| 109 | extern int init_usbat(struct us_data *us); | 109 | extern int init_usbat_cd(struct us_data *us); |
| 110 | extern int init_usbat_flash(struct us_data *us); | ||
| 111 | extern int init_usbat_probe(struct us_data *us); | ||
| 110 | 112 | ||
| 111 | struct usbat_info { | 113 | struct usbat_info { |
| 112 | int devicetype; | 114 | int devicetype; |
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 7ca896a342e3..19b25c5cafd4 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c | |||
| @@ -115,19 +115,6 @@ static void usb_stor_blocking_completion(struct urb *urb, struct pt_regs *regs) | |||
| 115 | 115 | ||
| 116 | complete(urb_done_ptr); | 116 | complete(urb_done_ptr); |
| 117 | } | 117 | } |
| 118 | |||
| 119 | /* This is the timeout handler which will cancel an URB when its timeout | ||
| 120 | * expires. | ||
| 121 | */ | ||
| 122 | static void timeout_handler(unsigned long us_) | ||
| 123 | { | ||
| 124 | struct us_data *us = (struct us_data *) us_; | ||
| 125 | |||
| 126 | if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) { | ||
| 127 | US_DEBUGP("Timeout -- cancelling URB\n"); | ||
| 128 | usb_unlink_urb(us->current_urb); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | 118 | ||
| 132 | /* This is the common part of the URB message submission code | 119 | /* This is the common part of the URB message submission code |
| 133 | * | 120 | * |
| @@ -138,7 +125,7 @@ static void timeout_handler(unsigned long us_) | |||
| 138 | static int usb_stor_msg_common(struct us_data *us, int timeout) | 125 | static int usb_stor_msg_common(struct us_data *us, int timeout) |
| 139 | { | 126 | { |
| 140 | struct completion urb_done; | 127 | struct completion urb_done; |
| 141 | struct timer_list to_timer; | 128 | long timeleft; |
| 142 | int status; | 129 | int status; |
| 143 | 130 | ||
| 144 | /* don't submit URBs during abort/disconnect processing */ | 131 | /* don't submit URBs during abort/disconnect processing */ |
| @@ -185,22 +172,17 @@ static int usb_stor_msg_common(struct us_data *us, int timeout) | |||
| 185 | } | 172 | } |
| 186 | } | 173 | } |
| 187 | 174 | ||
| 188 | /* submit the timeout timer, if a timeout was requested */ | ||
| 189 | if (timeout > 0) { | ||
| 190 | init_timer(&to_timer); | ||
| 191 | to_timer.expires = jiffies + timeout; | ||
| 192 | to_timer.function = timeout_handler; | ||
| 193 | to_timer.data = (unsigned long) us; | ||
| 194 | add_timer(&to_timer); | ||
| 195 | } | ||
| 196 | |||
| 197 | /* wait for the completion of the URB */ | 175 | /* wait for the completion of the URB */ |
| 198 | wait_for_completion(&urb_done); | 176 | timeleft = wait_for_completion_interruptible_timeout( |
| 199 | clear_bit(US_FLIDX_URB_ACTIVE, &us->flags); | 177 | &urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT); |
| 200 | 178 | ||
| 201 | /* clean up the timeout timer */ | 179 | clear_bit(US_FLIDX_URB_ACTIVE, &us->flags); |
| 202 | if (timeout > 0) | 180 | |
| 203 | del_timer_sync(&to_timer); | 181 | if (timeleft <= 0) { |
| 182 | US_DEBUGP("%s -- cancelling URB\n", | ||
| 183 | timeleft == 0 ? "Timeout" : "Signal"); | ||
| 184 | usb_unlink_urb(us->current_urb); | ||
| 185 | } | ||
| 204 | 186 | ||
| 205 | /* return the URB status */ | 187 | /* return the URB status */ |
| 206 | return us->current_urb->status; | 188 | return us->current_urb->status; |
| @@ -721,16 +703,19 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) | |||
| 721 | * device reset. */ | 703 | * device reset. */ |
| 722 | Handle_Errors: | 704 | Handle_Errors: |
| 723 | 705 | ||
| 724 | /* Let the SCSI layer know we are doing a reset, set the | 706 | /* Set the RESETTING bit, and clear the ABORTING bit so that |
| 725 | * RESETTING bit, and clear the ABORTING bit so that the reset | 707 | * the reset may proceed. */ |
| 726 | * may proceed. */ | ||
| 727 | scsi_lock(us_to_host(us)); | 708 | scsi_lock(us_to_host(us)); |
| 728 | usb_stor_report_bus_reset(us); | ||
| 729 | set_bit(US_FLIDX_RESETTING, &us->flags); | 709 | set_bit(US_FLIDX_RESETTING, &us->flags); |
| 730 | clear_bit(US_FLIDX_ABORTING, &us->flags); | 710 | clear_bit(US_FLIDX_ABORTING, &us->flags); |
| 731 | scsi_unlock(us_to_host(us)); | 711 | scsi_unlock(us_to_host(us)); |
| 732 | 712 | ||
| 713 | /* We must release the device lock because the pre_reset routine | ||
| 714 | * will want to acquire it. */ | ||
| 715 | mutex_unlock(&us->dev_mutex); | ||
| 733 | result = usb_stor_port_reset(us); | 716 | result = usb_stor_port_reset(us); |
| 717 | mutex_lock(&us->dev_mutex); | ||
| 718 | |||
| 734 | if (result < 0) { | 719 | if (result < 0) { |
| 735 | scsi_lock(us_to_host(us)); | 720 | scsi_lock(us_to_host(us)); |
| 736 | usb_stor_report_device_reset(us); | 721 | usb_stor_report_device_reset(us); |
| @@ -1214,31 +1199,30 @@ int usb_stor_Bulk_reset(struct us_data *us) | |||
| 1214 | 0, us->ifnum, NULL, 0); | 1199 | 0, us->ifnum, NULL, 0); |
| 1215 | } | 1200 | } |
| 1216 | 1201 | ||
| 1217 | /* Issue a USB port reset to the device. But don't do anything if | 1202 | /* Issue a USB port reset to the device. The caller must not hold |
| 1218 | * there's more than one interface in the device, so that other users | 1203 | * us->dev_mutex. |
| 1219 | * are not affected. */ | 1204 | */ |
| 1220 | int usb_stor_port_reset(struct us_data *us) | 1205 | int usb_stor_port_reset(struct us_data *us) |
| 1221 | { | 1206 | { |
| 1222 | int result, rc; | 1207 | int result, rc_lock; |
| 1223 | 1208 | ||
| 1224 | if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { | 1209 | result = rc_lock = |
| 1225 | result = -EIO; | 1210 | usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); |
| 1226 | US_DEBUGP("No reset during disconnect\n"); | 1211 | if (result < 0) |
| 1227 | } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) { | 1212 | US_DEBUGP("unable to lock device for reset: %d\n", result); |
| 1228 | result = -EBUSY; | 1213 | else { |
| 1229 | US_DEBUGP("Refusing to reset a multi-interface device\n"); | 1214 | /* Were we disconnected while waiting for the lock? */ |
| 1230 | } else { | 1215 | if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) { |
| 1231 | result = rc = | 1216 | result = -EIO; |
| 1232 | usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); | 1217 | US_DEBUGP("No reset during disconnect\n"); |
| 1233 | if (result < 0) { | ||
| 1234 | US_DEBUGP("unable to lock device for reset: %d\n", | ||
| 1235 | result); | ||
| 1236 | } else { | 1218 | } else { |
| 1237 | result = usb_reset_device(us->pusb_dev); | 1219 | result = usb_reset_composite_device( |
| 1238 | if (rc) | 1220 | us->pusb_dev, us->pusb_intf); |
| 1239 | usb_unlock_device(us->pusb_dev); | 1221 | US_DEBUGP("usb_reset_composite_device returns %d\n", |
| 1240 | US_DEBUGP("usb_reset_device returns %d\n", result); | 1222 | result); |
| 1241 | } | 1223 | } |
| 1224 | if (rc_lock) | ||
| 1225 | usb_unlock_device(us->pusb_dev); | ||
| 1242 | } | 1226 | } |
| 1243 | return result; | 1227 | return result; |
| 1244 | } | 1228 | } |
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index aec5ea8682d5..543244d421c1 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h | |||
| @@ -78,12 +78,12 @@ UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200, | |||
| 78 | UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001, | 78 | UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001, |
| 79 | "HP", | 79 | "HP", |
| 80 | "CD-Writer+ 8200e", | 80 | "CD-Writer+ 8200e", |
| 81 | US_SC_8070, US_PR_USBAT, init_usbat, 0), | 81 | US_SC_8070, US_PR_USBAT, init_usbat_cd, 0), |
| 82 | 82 | ||
| 83 | UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001, | 83 | UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001, |
| 84 | "HP", | 84 | "HP", |
| 85 | "CD-Writer+ CD-4e", | 85 | "CD-Writer+ CD-4e", |
| 86 | US_SC_8070, US_PR_USBAT, init_usbat, 0), | 86 | US_SC_8070, US_PR_USBAT, init_usbat_cd, 0), |
| 87 | #endif | 87 | #endif |
| 88 | 88 | ||
| 89 | /* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net> | 89 | /* Reported by Sebastian Kapfer <sebastian_kapfer@gmx.net> |
| @@ -133,6 +133,14 @@ UNUSUAL_DEV( 0x0420, 0x0001, 0x0100, 0x0100, | |||
| 133 | US_SC_DEVICE, US_PR_DEVICE, NULL, | 133 | US_SC_DEVICE, US_PR_DEVICE, NULL, |
| 134 | US_FL_IGNORE_RESIDUE ), | 134 | US_FL_IGNORE_RESIDUE ), |
| 135 | 135 | ||
| 136 | /* Reported by Jiri Slaby <jirislaby@gmail.com> and | ||
| 137 | * Rene C. Castberg <Rene@Castberg.org> */ | ||
| 138 | UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100, | ||
| 139 | "Nokia", | ||
| 140 | "N80", | ||
| 141 | US_SC_DEVICE, US_PR_DEVICE, NULL, | ||
| 142 | US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), | ||
| 143 | |||
| 136 | /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */ | 144 | /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */ |
| 137 | UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, | 145 | UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, |
| 138 | "SMSC", | 146 | "SMSC", |
| @@ -216,6 +224,14 @@ UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001, | |||
| 216 | "DVD-CAM DZ-MV100A Camcorder", | 224 | "DVD-CAM DZ-MV100A Camcorder", |
| 217 | US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN), | 225 | US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN), |
| 218 | 226 | ||
| 227 | /* Patch for Nikon coolpix 2000 | ||
| 228 | * Submitted by Fabien Cosse <fabien.cosse@wanadoo.fr>*/ | ||
| 229 | UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010, | ||
| 230 | "NIKON", | ||
| 231 | "NIKON DSC E2000", | ||
| 232 | US_SC_DEVICE, US_PR_DEVICE,NULL, | ||
| 233 | US_FL_NOT_LOCKABLE ), | ||
| 234 | |||
| 219 | /* Reported by Andreas Bockhold <andreas@bockionline.de> */ | 235 | /* Reported by Andreas Bockhold <andreas@bockionline.de> */ |
| 220 | UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100, | 236 | UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100, |
| 221 | "NIKON", | 237 | "NIKON", |
| @@ -223,13 +239,12 @@ UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100, | |||
| 223 | US_SC_DEVICE, US_PR_DEVICE, NULL, | 239 | US_SC_DEVICE, US_PR_DEVICE, NULL, |
| 224 | US_FL_FIX_CAPACITY), | 240 | US_FL_FIX_CAPACITY), |
| 225 | 241 | ||
| 226 | /* Patch for Nikon coolpix 2000 | 242 | /* Reported by Jamie Kitson <jamie@staberinde.fsnet.co.uk> */ |
| 227 | * Submitted by Fabien Cosse <fabien.cosse@wanadoo.fr>*/ | 243 | UNUSUAL_DEV( 0x04b0, 0x040d, 0x0100, 0x0100, |
| 228 | UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010, | ||
| 229 | "NIKON", | 244 | "NIKON", |
| 230 | "NIKON DSC E2000", | 245 | "NIKON DSC D70s", |
| 231 | US_SC_DEVICE, US_PR_DEVICE,NULL, | 246 | US_SC_DEVICE, US_PR_DEVICE, NULL, |
| 232 | US_FL_NOT_LOCKABLE ), | 247 | US_FL_FIX_CAPACITY), |
| 233 | 248 | ||
| 234 | /* BENQ DC5330 | 249 | /* BENQ DC5330 |
| 235 | * Reported by Manuel Fombuena <mfombuena@ya.com> and | 250 | * Reported by Manuel Fombuena <mfombuena@ya.com> and |
| @@ -393,7 +408,7 @@ UNUSUAL_DEV( 0x04fc, 0x80c2, 0x0100, 0x0100, | |||
| 393 | UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999, | 408 | UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999, |
| 394 | "Shuttle/SCM", | 409 | "Shuttle/SCM", |
| 395 | "USBAT-02", | 410 | "USBAT-02", |
| 396 | US_SC_SCSI, US_PR_USBAT, init_usbat, | 411 | US_SC_SCSI, US_PR_USBAT, init_usbat_flash, |
| 397 | US_FL_SINGLE_LUN), | 412 | US_FL_SINGLE_LUN), |
| 398 | #endif | 413 | #endif |
| 399 | 414 | ||
| @@ -797,7 +812,7 @@ UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009, | |||
| 797 | UNUSUAL_DEV( 0x0781, 0x0005, 0x0005, 0x0005, | 812 | UNUSUAL_DEV( 0x0781, 0x0005, 0x0005, 0x0005, |
| 798 | "Sandisk", | 813 | "Sandisk", |
| 799 | "ImageMate SDDR-05b", | 814 | "ImageMate SDDR-05b", |
| 800 | US_SC_SCSI, US_PR_USBAT, init_usbat, | 815 | US_SC_SCSI, US_PR_USBAT, init_usbat_flash, |
| 801 | US_FL_SINGLE_LUN ), | 816 | US_FL_SINGLE_LUN ), |
| 802 | #endif | 817 | #endif |
| 803 | 818 | ||
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index dd108634348e..e232c7c89909 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c | |||
| @@ -221,6 +221,37 @@ static int storage_resume(struct usb_interface *iface) | |||
| 221 | #endif /* CONFIG_PM */ | 221 | #endif /* CONFIG_PM */ |
| 222 | 222 | ||
| 223 | /* | 223 | /* |
| 224 | * The next two routines get called just before and just after | ||
| 225 | * a USB port reset, whether from this driver or a different one. | ||
| 226 | */ | ||
| 227 | |||
| 228 | static void storage_pre_reset(struct usb_interface *iface) | ||
| 229 | { | ||
| 230 | struct us_data *us = usb_get_intfdata(iface); | ||
| 231 | |||
| 232 | US_DEBUGP("%s\n", __FUNCTION__); | ||
| 233 | |||
| 234 | /* Make sure no command runs during the reset */ | ||
| 235 | mutex_lock(&us->dev_mutex); | ||
| 236 | } | ||
| 237 | |||
| 238 | static void storage_post_reset(struct usb_interface *iface) | ||
| 239 | { | ||
| 240 | struct us_data *us = usb_get_intfdata(iface); | ||
| 241 | |||
| 242 | US_DEBUGP("%s\n", __FUNCTION__); | ||
| 243 | |||
| 244 | /* Report the reset to the SCSI core */ | ||
| 245 | scsi_lock(us_to_host(us)); | ||
| 246 | usb_stor_report_bus_reset(us); | ||
| 247 | scsi_unlock(us_to_host(us)); | ||
| 248 | |||
| 249 | /* FIXME: Notify the subdrivers that they need to reinitialize | ||
| 250 | * the device */ | ||
| 251 | mutex_unlock(&us->dev_mutex); | ||
| 252 | } | ||
| 253 | |||
| 254 | /* | ||
| 224 | * fill_inquiry_response takes an unsigned char array (which must | 255 | * fill_inquiry_response takes an unsigned char array (which must |
| 225 | * be at least 36 characters) and populates the vendor name, | 256 | * be at least 36 characters) and populates the vendor name, |
| 226 | * product name, and revision fields. Then the array is copied | 257 | * product name, and revision fields. Then the array is copied |
| @@ -593,6 +624,15 @@ static int get_transport(struct us_data *us) | |||
| 593 | break; | 624 | break; |
| 594 | #endif | 625 | #endif |
| 595 | 626 | ||
| 627 | #ifdef CONFIG_USB_STORAGE_ALAUDA | ||
| 628 | case US_PR_ALAUDA: | ||
| 629 | us->transport_name = "Alauda Control/Bulk"; | ||
| 630 | us->transport = alauda_transport; | ||
| 631 | us->transport_reset = usb_stor_Bulk_reset; | ||
| 632 | us->max_lun = 1; | ||
| 633 | break; | ||
| 634 | #endif | ||
| 635 | |||
| 596 | default: | 636 | default: |
| 597 | return -EIO; | 637 | return -EIO; |
| 598 | } | 638 | } |
| @@ -648,15 +688,6 @@ static int get_protocol(struct us_data *us) | |||
| 648 | break; | 688 | break; |
| 649 | #endif | 689 | #endif |
| 650 | 690 | ||
| 651 | #ifdef CONFIG_USB_STORAGE_ALAUDA | ||
| 652 | case US_PR_ALAUDA: | ||
| 653 | us->transport_name = "Alauda Control/Bulk"; | ||
| 654 | us->transport = alauda_transport; | ||
| 655 | us->transport_reset = usb_stor_Bulk_reset; | ||
| 656 | us->max_lun = 1; | ||
| 657 | break; | ||
| 658 | #endif | ||
| 659 | |||
| 660 | default: | 691 | default: |
| 661 | return -EIO; | 692 | return -EIO; |
| 662 | } | 693 | } |
| @@ -1002,6 +1033,8 @@ static struct usb_driver usb_storage_driver = { | |||
| 1002 | .suspend = storage_suspend, | 1033 | .suspend = storage_suspend, |
| 1003 | .resume = storage_resume, | 1034 | .resume = storage_resume, |
| 1004 | #endif | 1035 | #endif |
| 1036 | .pre_reset = storage_pre_reset, | ||
| 1037 | .post_reset = storage_post_reset, | ||
| 1005 | .id_table = storage_usb_ids, | 1038 | .id_table = storage_usb_ids, |
| 1006 | }; | 1039 | }; |
| 1007 | 1040 | ||
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index 989e4d49e5bb..7f939d066a5a 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c | |||
| @@ -313,8 +313,8 @@ static const char __init *mdacon_startup(void) | |||
| 313 | mda_num_columns = 80; | 313 | mda_num_columns = 80; |
| 314 | mda_num_lines = 25; | 314 | mda_num_lines = 25; |
| 315 | 315 | ||
| 316 | mda_vram_base = VGA_MAP_MEM(0xb0000); | ||
| 317 | mda_vram_len = 0x01000; | 316 | mda_vram_len = 0x01000; |
| 317 | mda_vram_base = VGA_MAP_MEM(0xb0000, mda_vram_len); | ||
| 318 | 318 | ||
| 319 | mda_index_port = 0x3b4; | 319 | mda_index_port = 0x3b4; |
| 320 | mda_value_port = 0x3b5; | 320 | mda_value_port = 0x3b5; |
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index d5a04b68c4d4..e64d42e2449e 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
| @@ -391,7 +391,7 @@ static const char __init *vgacon_startup(void) | |||
| 391 | static struct resource ega_console_resource = | 391 | static struct resource ega_console_resource = |
| 392 | { "ega", 0x3B0, 0x3BF }; | 392 | { "ega", 0x3B0, 0x3BF }; |
| 393 | vga_video_type = VIDEO_TYPE_EGAM; | 393 | vga_video_type = VIDEO_TYPE_EGAM; |
| 394 | vga_vram_end = 0xb8000; | 394 | vga_vram_size = 0x8000; |
| 395 | display_desc = "EGA+"; | 395 | display_desc = "EGA+"; |
| 396 | request_resource(&ioport_resource, | 396 | request_resource(&ioport_resource, |
| 397 | &ega_console_resource); | 397 | &ega_console_resource); |
| @@ -401,7 +401,7 @@ static const char __init *vgacon_startup(void) | |||
| 401 | static struct resource mda2_console_resource = | 401 | static struct resource mda2_console_resource = |
| 402 | { "mda", 0x3BF, 0x3BF }; | 402 | { "mda", 0x3BF, 0x3BF }; |
| 403 | vga_video_type = VIDEO_TYPE_MDA; | 403 | vga_video_type = VIDEO_TYPE_MDA; |
| 404 | vga_vram_end = 0xb2000; | 404 | vga_vram_size = 0x2000; |
| 405 | display_desc = "*MDA"; | 405 | display_desc = "*MDA"; |
| 406 | request_resource(&ioport_resource, | 406 | request_resource(&ioport_resource, |
| 407 | &mda1_console_resource); | 407 | &mda1_console_resource); |
| @@ -418,7 +418,7 @@ static const char __init *vgacon_startup(void) | |||
| 418 | if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { | 418 | if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) { |
| 419 | int i; | 419 | int i; |
| 420 | 420 | ||
| 421 | vga_vram_end = 0xc0000; | 421 | vga_vram_size = 0x8000; |
| 422 | 422 | ||
| 423 | if (!ORIG_VIDEO_ISVGA) { | 423 | if (!ORIG_VIDEO_ISVGA) { |
| 424 | static struct resource ega_console_resource | 424 | static struct resource ega_console_resource |
| @@ -443,7 +443,7 @@ static const char __init *vgacon_startup(void) | |||
| 443 | * and COE=1 isn't necessarily a good idea) | 443 | * and COE=1 isn't necessarily a good idea) |
| 444 | */ | 444 | */ |
| 445 | vga_vram_base = 0xa0000; | 445 | vga_vram_base = 0xa0000; |
| 446 | vga_vram_end = 0xb0000; | 446 | vga_vram_size = 0x10000; |
| 447 | outb_p(6, VGA_GFX_I); | 447 | outb_p(6, VGA_GFX_I); |
| 448 | outb_p(6, VGA_GFX_D); | 448 | outb_p(6, VGA_GFX_D); |
| 449 | #endif | 449 | #endif |
| @@ -475,7 +475,7 @@ static const char __init *vgacon_startup(void) | |||
| 475 | static struct resource cga_console_resource = | 475 | static struct resource cga_console_resource = |
| 476 | { "cga", 0x3D4, 0x3D5 }; | 476 | { "cga", 0x3D4, 0x3D5 }; |
| 477 | vga_video_type = VIDEO_TYPE_CGA; | 477 | vga_video_type = VIDEO_TYPE_CGA; |
| 478 | vga_vram_end = 0xba000; | 478 | vga_vram_size = 0x2000; |
| 479 | display_desc = "*CGA"; | 479 | display_desc = "*CGA"; |
| 480 | request_resource(&ioport_resource, | 480 | request_resource(&ioport_resource, |
| 481 | &cga_console_resource); | 481 | &cga_console_resource); |
| @@ -483,9 +483,8 @@ static const char __init *vgacon_startup(void) | |||
| 483 | } | 483 | } |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | vga_vram_base = VGA_MAP_MEM(vga_vram_base); | 486 | vga_vram_base = VGA_MAP_MEM(vga_vram_base, vga_vram_size); |
| 487 | vga_vram_end = VGA_MAP_MEM(vga_vram_end); | 487 | vga_vram_end = vga_vram_base + vga_vram_size; |
| 488 | vga_vram_size = vga_vram_end - vga_vram_base; | ||
| 489 | 488 | ||
| 490 | /* | 489 | /* |
| 491 | * Find out if there is a graphics card present. | 490 | * Find out if there is a graphics card present. |
| @@ -1020,14 +1019,14 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) | |||
| 1020 | char *charmap; | 1019 | char *charmap; |
| 1021 | 1020 | ||
| 1022 | if (vga_video_type != VIDEO_TYPE_EGAM) { | 1021 | if (vga_video_type != VIDEO_TYPE_EGAM) { |
| 1023 | charmap = (char *) VGA_MAP_MEM(colourmap); | 1022 | charmap = (char *) VGA_MAP_MEM(colourmap, 0); |
| 1024 | beg = 0x0e; | 1023 | beg = 0x0e; |
| 1025 | #ifdef VGA_CAN_DO_64KB | 1024 | #ifdef VGA_CAN_DO_64KB |
| 1026 | if (vga_video_type == VIDEO_TYPE_VGAC) | 1025 | if (vga_video_type == VIDEO_TYPE_VGAC) |
| 1027 | beg = 0x06; | 1026 | beg = 0x06; |
| 1028 | #endif | 1027 | #endif |
| 1029 | } else { | 1028 | } else { |
| 1030 | charmap = (char *) VGA_MAP_MEM(blackwmap); | 1029 | charmap = (char *) VGA_MAP_MEM(blackwmap, 0); |
| 1031 | beg = 0x0a; | 1030 | beg = 0x0a; |
| 1032 | } | 1031 | } |
| 1033 | 1032 | ||
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index f3f16fd9f231..4fd2a272e03d 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c | |||
| @@ -1351,7 +1351,7 @@ static int __init vga16fb_probe(struct device *device) | |||
| 1351 | } | 1351 | } |
| 1352 | 1352 | ||
| 1353 | /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ | 1353 | /* XXX share VGA_FB_PHYS and I/O region with vgacon and others */ |
| 1354 | info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS); | 1354 | info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0); |
| 1355 | 1355 | ||
| 1356 | if (!info->screen_base) { | 1356 | if (!info->screen_base) { |
| 1357 | printk(KERN_ERR "vga16fb: unable to map device\n"); | 1357 | printk(KERN_ERR "vga16fb: unable to map device\n"); |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 537893a16014..8a04216e8b4d 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
| @@ -759,7 +759,6 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 759 | 759 | ||
| 760 | /* Discard our unneeded old files struct */ | 760 | /* Discard our unneeded old files struct */ |
| 761 | if (files) { | 761 | if (files) { |
| 762 | steal_locks(files); | ||
| 763 | put_files_struct(files); | 762 | put_files_struct(files); |
| 764 | files = NULL; | 763 | files = NULL; |
| 765 | } | 764 | } |
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index d73d75591a39..599f36fd0f67 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c | |||
| @@ -203,7 +203,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
| 203 | goto _error; | 203 | goto _error; |
| 204 | 204 | ||
| 205 | if (files) { | 205 | if (files) { |
| 206 | steal_locks(files); | ||
| 207 | put_files_struct(files); | 206 | put_files_struct(files); |
| 208 | files = NULL; | 207 | files = NULL; |
| 209 | } | 208 | } |
diff --git a/fs/block_dev.c b/fs/block_dev.c index f5958f413bd1..44aaba202f78 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -414,21 +414,31 @@ EXPORT_SYMBOL(bdput); | |||
| 414 | static struct block_device *bd_acquire(struct inode *inode) | 414 | static struct block_device *bd_acquire(struct inode *inode) |
| 415 | { | 415 | { |
| 416 | struct block_device *bdev; | 416 | struct block_device *bdev; |
| 417 | |||
| 417 | spin_lock(&bdev_lock); | 418 | spin_lock(&bdev_lock); |
| 418 | bdev = inode->i_bdev; | 419 | bdev = inode->i_bdev; |
| 419 | if (bdev && igrab(bdev->bd_inode)) { | 420 | if (bdev) { |
| 421 | atomic_inc(&bdev->bd_inode->i_count); | ||
| 420 | spin_unlock(&bdev_lock); | 422 | spin_unlock(&bdev_lock); |
| 421 | return bdev; | 423 | return bdev; |
| 422 | } | 424 | } |
| 423 | spin_unlock(&bdev_lock); | 425 | spin_unlock(&bdev_lock); |
| 426 | |||
| 424 | bdev = bdget(inode->i_rdev); | 427 | bdev = bdget(inode->i_rdev); |
| 425 | if (bdev) { | 428 | if (bdev) { |
| 426 | spin_lock(&bdev_lock); | 429 | spin_lock(&bdev_lock); |
| 427 | if (inode->i_bdev) | 430 | if (!inode->i_bdev) { |
| 428 | __bd_forget(inode); | 431 | /* |
| 429 | inode->i_bdev = bdev; | 432 | * We take an additional bd_inode->i_count for inode, |
| 430 | inode->i_mapping = bdev->bd_inode->i_mapping; | 433 | * and it's released in clear_inode() of inode. |
| 431 | list_add(&inode->i_devices, &bdev->bd_inodes); | 434 | * So, we can access it via ->i_mapping always |
| 435 | * without igrab(). | ||
| 436 | */ | ||
| 437 | atomic_inc(&bdev->bd_inode->i_count); | ||
| 438 | inode->i_bdev = bdev; | ||
| 439 | inode->i_mapping = bdev->bd_inode->i_mapping; | ||
| 440 | list_add(&inode->i_devices, &bdev->bd_inodes); | ||
| 441 | } | ||
| 432 | spin_unlock(&bdev_lock); | 442 | spin_unlock(&bdev_lock); |
| 433 | } | 443 | } |
| 434 | return bdev; | 444 | return bdev; |
| @@ -438,10 +448,18 @@ static struct block_device *bd_acquire(struct inode *inode) | |||
| 438 | 448 | ||
| 439 | void bd_forget(struct inode *inode) | 449 | void bd_forget(struct inode *inode) |
| 440 | { | 450 | { |
| 451 | struct block_device *bdev = NULL; | ||
| 452 | |||
| 441 | spin_lock(&bdev_lock); | 453 | spin_lock(&bdev_lock); |
| 442 | if (inode->i_bdev) | 454 | if (inode->i_bdev) { |
| 455 | if (inode->i_sb != blockdev_superblock) | ||
| 456 | bdev = inode->i_bdev; | ||
| 443 | __bd_forget(inode); | 457 | __bd_forget(inode); |
| 458 | } | ||
| 444 | spin_unlock(&bdev_lock); | 459 | spin_unlock(&bdev_lock); |
| 460 | |||
| 461 | if (bdev) | ||
| 462 | iput(bdev->bd_inode); | ||
| 445 | } | 463 | } |
| 446 | 464 | ||
| 447 | int bd_claim(struct block_device *bdev, void *holder) | 465 | int bd_claim(struct block_device *bdev, void *holder) |
diff --git a/fs/dcache.c b/fs/dcache.c index 940d188e5d14..59dbc92c2079 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -359,12 +359,13 @@ restart: | |||
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | /* | 361 | /* |
| 362 | * Throw away a dentry - free the inode, dput the parent. | 362 | * Throw away a dentry - free the inode, dput the parent. This requires that |
| 363 | * This requires that the LRU list has already been | 363 | * the LRU list has already been removed. |
| 364 | * removed. | 364 | * |
| 365 | * Called with dcache_lock, drops it and then regains. | 365 | * Called with dcache_lock, drops it and then regains. |
| 366 | * Called with dentry->d_lock held, drops it. | ||
| 366 | */ | 367 | */ |
| 367 | static inline void prune_one_dentry(struct dentry * dentry) | 368 | static void prune_one_dentry(struct dentry * dentry) |
| 368 | { | 369 | { |
| 369 | struct dentry * parent; | 370 | struct dentry * parent; |
| 370 | 371 | ||
| @@ -382,6 +383,8 @@ static inline void prune_one_dentry(struct dentry * dentry) | |||
| 382 | /** | 383 | /** |
| 383 | * prune_dcache - shrink the dcache | 384 | * prune_dcache - shrink the dcache |
| 384 | * @count: number of entries to try and free | 385 | * @count: number of entries to try and free |
| 386 | * @sb: if given, ignore dentries for other superblocks | ||
| 387 | * which are being unmounted. | ||
| 385 | * | 388 | * |
| 386 | * Shrink the dcache. This is done when we need | 389 | * Shrink the dcache. This is done when we need |
| 387 | * more memory, or simply when we need to unmount | 390 | * more memory, or simply when we need to unmount |
| @@ -392,16 +395,29 @@ static inline void prune_one_dentry(struct dentry * dentry) | |||
| 392 | * all the dentries are in use. | 395 | * all the dentries are in use. |
| 393 | */ | 396 | */ |
| 394 | 397 | ||
| 395 | static void prune_dcache(int count) | 398 | static void prune_dcache(int count, struct super_block *sb) |
| 396 | { | 399 | { |
| 397 | spin_lock(&dcache_lock); | 400 | spin_lock(&dcache_lock); |
| 398 | for (; count ; count--) { | 401 | for (; count ; count--) { |
| 399 | struct dentry *dentry; | 402 | struct dentry *dentry; |
| 400 | struct list_head *tmp; | 403 | struct list_head *tmp; |
| 404 | struct rw_semaphore *s_umount; | ||
| 401 | 405 | ||
| 402 | cond_resched_lock(&dcache_lock); | 406 | cond_resched_lock(&dcache_lock); |
| 403 | 407 | ||
| 404 | tmp = dentry_unused.prev; | 408 | tmp = dentry_unused.prev; |
| 409 | if (unlikely(sb)) { | ||
| 410 | /* Try to find a dentry for this sb, but don't try | ||
| 411 | * too hard, if they aren't near the tail they will | ||
| 412 | * be moved down again soon | ||
| 413 | */ | ||
| 414 | int skip = count; | ||
| 415 | while (skip && tmp != &dentry_unused && | ||
| 416 | list_entry(tmp, struct dentry, d_lru)->d_sb != sb) { | ||
| 417 | skip--; | ||
| 418 | tmp = tmp->prev; | ||
| 419 | } | ||
| 420 | } | ||
| 405 | if (tmp == &dentry_unused) | 421 | if (tmp == &dentry_unused) |
| 406 | break; | 422 | break; |
| 407 | list_del_init(tmp); | 423 | list_del_init(tmp); |
| @@ -427,7 +443,45 @@ static void prune_dcache(int count) | |||
| 427 | spin_unlock(&dentry->d_lock); | 443 | spin_unlock(&dentry->d_lock); |
| 428 | continue; | 444 | continue; |
| 429 | } | 445 | } |
| 430 | prune_one_dentry(dentry); | 446 | /* |
| 447 | * If the dentry is not DCACHED_REFERENCED, it is time | ||
| 448 | * to remove it from the dcache, provided the super block is | ||
| 449 | * NULL (which means we are trying to reclaim memory) | ||
| 450 | * or this dentry belongs to the same super block that | ||
| 451 | * we want to shrink. | ||
| 452 | */ | ||
| 453 | /* | ||
| 454 | * If this dentry is for "my" filesystem, then I can prune it | ||
| 455 | * without taking the s_umount lock (I already hold it). | ||
| 456 | */ | ||
| 457 | if (sb && dentry->d_sb == sb) { | ||
| 458 | prune_one_dentry(dentry); | ||
| 459 | continue; | ||
| 460 | } | ||
| 461 | /* | ||
| 462 | * ...otherwise we need to be sure this filesystem isn't being | ||
| 463 | * unmounted, otherwise we could race with | ||
| 464 | * generic_shutdown_super(), and end up holding a reference to | ||
| 465 | * an inode while the filesystem is unmounted. | ||
| 466 | * So we try to get s_umount, and make sure s_root isn't NULL. | ||
| 467 | * (Take a local copy of s_umount to avoid a use-after-free of | ||
| 468 | * `dentry'). | ||
| 469 | */ | ||
| 470 | s_umount = &dentry->d_sb->s_umount; | ||
| 471 | if (down_read_trylock(s_umount)) { | ||
| 472 | if (dentry->d_sb->s_root != NULL) { | ||
| 473 | prune_one_dentry(dentry); | ||
| 474 | up_read(s_umount); | ||
| 475 | continue; | ||
| 476 | } | ||
| 477 | up_read(s_umount); | ||
| 478 | } | ||
| 479 | spin_unlock(&dentry->d_lock); | ||
| 480 | /* Cannot remove the first dentry, and it isn't appropriate | ||
| 481 | * to move it to the head of the list, so give up, and try | ||
| 482 | * later | ||
| 483 | */ | ||
| 484 | break; | ||
| 431 | } | 485 | } |
| 432 | spin_unlock(&dcache_lock); | 486 | spin_unlock(&dcache_lock); |
| 433 | } | 487 | } |
| @@ -630,7 +684,7 @@ void shrink_dcache_parent(struct dentry * parent) | |||
| 630 | int found; | 684 | int found; |
| 631 | 685 | ||
| 632 | while ((found = select_parent(parent)) != 0) | 686 | while ((found = select_parent(parent)) != 0) |
| 633 | prune_dcache(found); | 687 | prune_dcache(found, parent->d_sb); |
| 634 | } | 688 | } |
| 635 | 689 | ||
| 636 | /** | 690 | /** |
| @@ -643,9 +697,10 @@ void shrink_dcache_parent(struct dentry * parent) | |||
| 643 | * done under dcache_lock. | 697 | * done under dcache_lock. |
| 644 | * | 698 | * |
| 645 | */ | 699 | */ |
| 646 | void shrink_dcache_anon(struct hlist_head *head) | 700 | void shrink_dcache_anon(struct super_block *sb) |
| 647 | { | 701 | { |
| 648 | struct hlist_node *lp; | 702 | struct hlist_node *lp; |
| 703 | struct hlist_head *head = &sb->s_anon; | ||
| 649 | int found; | 704 | int found; |
| 650 | do { | 705 | do { |
| 651 | found = 0; | 706 | found = 0; |
| @@ -668,7 +723,7 @@ void shrink_dcache_anon(struct hlist_head *head) | |||
| 668 | } | 723 | } |
| 669 | } | 724 | } |
| 670 | spin_unlock(&dcache_lock); | 725 | spin_unlock(&dcache_lock); |
| 671 | prune_dcache(found); | 726 | prune_dcache(found, sb); |
| 672 | } while(found); | 727 | } while(found); |
| 673 | } | 728 | } |
| 674 | 729 | ||
| @@ -689,7 +744,7 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask) | |||
| 689 | if (nr) { | 744 | if (nr) { |
| 690 | if (!(gfp_mask & __GFP_FS)) | 745 | if (!(gfp_mask & __GFP_FS)) |
| 691 | return -1; | 746 | return -1; |
| 692 | prune_dcache(nr); | 747 | prune_dcache(nr, NULL); |
| 693 | } | 748 | } |
| 694 | return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; | 749 | return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; |
| 695 | } | 750 | } |
| @@ -866,7 +866,6 @@ int flush_old_exec(struct linux_binprm * bprm) | |||
| 866 | bprm->mm = NULL; /* We're using it now */ | 866 | bprm->mm = NULL; /* We're using it now */ |
| 867 | 867 | ||
| 868 | /* This is the point of no return */ | 868 | /* This is the point of no return */ |
| 869 | steal_locks(files); | ||
| 870 | put_files_struct(files); | 869 | put_files_struct(files); |
| 871 | 870 | ||
| 872 | current->sas_ss_sp = current->sas_ss_size = 0; | 871 | current->sas_ss_sp = current->sas_ss_size = 0; |
diff --git a/fs/locks.c b/fs/locks.c index ab61a8b54829..69435c68c1ed 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -2206,63 +2206,6 @@ int lock_may_write(struct inode *inode, loff_t start, unsigned long len) | |||
| 2206 | 2206 | ||
| 2207 | EXPORT_SYMBOL(lock_may_write); | 2207 | EXPORT_SYMBOL(lock_may_write); |
| 2208 | 2208 | ||
| 2209 | static inline void __steal_locks(struct file *file, fl_owner_t from) | ||
| 2210 | { | ||
| 2211 | struct inode *inode = file->f_dentry->d_inode; | ||
| 2212 | struct file_lock *fl = inode->i_flock; | ||
| 2213 | |||
| 2214 | while (fl) { | ||
| 2215 | if (fl->fl_file == file && fl->fl_owner == from) | ||
| 2216 | fl->fl_owner = current->files; | ||
| 2217 | fl = fl->fl_next; | ||
| 2218 | } | ||
| 2219 | } | ||
| 2220 | |||
| 2221 | /* When getting ready for executing a binary, we make sure that current | ||
| 2222 | * has a files_struct on its own. Before dropping the old files_struct, | ||
| 2223 | * we take over ownership of all locks for all file descriptors we own. | ||
| 2224 | * Note that we may accidentally steal a lock for a file that a sibling | ||
| 2225 | * has created since the unshare_files() call. | ||
| 2226 | */ | ||
| 2227 | void steal_locks(fl_owner_t from) | ||
| 2228 | { | ||
| 2229 | struct files_struct *files = current->files; | ||
| 2230 | int i, j; | ||
| 2231 | struct fdtable *fdt; | ||
| 2232 | |||
| 2233 | if (from == files) | ||
| 2234 | return; | ||
| 2235 | |||
| 2236 | lock_kernel(); | ||
| 2237 | j = 0; | ||
| 2238 | |||
| 2239 | /* | ||
| 2240 | * We are not taking a ref to the file structures, so | ||
| 2241 | * we need to acquire ->file_lock. | ||
| 2242 | */ | ||
| 2243 | spin_lock(&files->file_lock); | ||
| 2244 | fdt = files_fdtable(files); | ||
| 2245 | for (;;) { | ||
| 2246 | unsigned long set; | ||
| 2247 | i = j * __NFDBITS; | ||
| 2248 | if (i >= fdt->max_fdset || i >= fdt->max_fds) | ||
| 2249 | break; | ||
| 2250 | set = fdt->open_fds->fds_bits[j++]; | ||
| 2251 | while (set) { | ||
| 2252 | if (set & 1) { | ||
| 2253 | struct file *file = fdt->fd[i]; | ||
| 2254 | if (file) | ||
| 2255 | __steal_locks(file, from); | ||
| 2256 | } | ||
| 2257 | i++; | ||
| 2258 | set >>= 1; | ||
| 2259 | } | ||
| 2260 | } | ||
| 2261 | spin_unlock(&files->file_lock); | ||
| 2262 | unlock_kernel(); | ||
| 2263 | } | ||
| 2264 | EXPORT_SYMBOL(steal_locks); | ||
| 2265 | |||
| 2266 | static int __init filelock_init(void) | 2209 | static int __init filelock_init(void) |
| 2267 | { | 2210 | { |
| 2268 | filelock_cache = kmem_cache_create("file_lock_cache", | 2211 | filelock_cache = kmem_cache_create("file_lock_cache", |
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index c63a83e8da98..36e1e136bb0c 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
| @@ -1484,14 +1484,15 @@ static inline void ntfs_flush_dcache_pages(struct page **pages, | |||
| 1484 | unsigned nr_pages) | 1484 | unsigned nr_pages) |
| 1485 | { | 1485 | { |
| 1486 | BUG_ON(!nr_pages); | 1486 | BUG_ON(!nr_pages); |
| 1487 | /* | ||
| 1488 | * Warning: Do not do the decrement at the same time as the call to | ||
| 1489 | * flush_dcache_page() because it is a NULL macro on i386 and hence the | ||
| 1490 | * decrement never happens so the loop never terminates. | ||
| 1491 | */ | ||
| 1487 | do { | 1492 | do { |
| 1488 | /* | 1493 | --nr_pages; |
| 1489 | * Warning: Do not do the decrement at the same time as the | ||
| 1490 | * call because flush_dcache_page() is a NULL macro on i386 | ||
| 1491 | * and hence the decrement never happens. | ||
| 1492 | */ | ||
| 1493 | flush_dcache_page(pages[nr_pages]); | 1494 | flush_dcache_page(pages[nr_pages]); |
| 1494 | } while (--nr_pages > 0); | 1495 | } while (nr_pages > 0); |
| 1495 | } | 1496 | } |
| 1496 | 1497 | ||
| 1497 | /** | 1498 | /** |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 7ef1f094de91..8851b81e7c5a 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
| @@ -329,6 +329,7 @@ void delete_partition(struct gendisk *disk, int part) | |||
| 329 | p->ios[0] = p->ios[1] = 0; | 329 | p->ios[0] = p->ios[1] = 0; |
| 330 | p->sectors[0] = p->sectors[1] = 0; | 330 | p->sectors[0] = p->sectors[1] = 0; |
| 331 | devfs_remove("%s/part%d", disk->devfs_name, part); | 331 | devfs_remove("%s/part%d", disk->devfs_name, part); |
| 332 | sysfs_remove_link(&p->kobj, "subsystem"); | ||
| 332 | if (p->holder_dir) | 333 | if (p->holder_dir) |
| 333 | kobject_unregister(p->holder_dir); | 334 | kobject_unregister(p->holder_dir); |
| 334 | kobject_uevent(&p->kobj, KOBJ_REMOVE); | 335 | kobject_uevent(&p->kobj, KOBJ_REMOVE); |
| @@ -363,6 +364,7 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) | |||
| 363 | kobject_add(&p->kobj); | 364 | kobject_add(&p->kobj); |
| 364 | if (!disk->part_uevent_suppress) | 365 | if (!disk->part_uevent_suppress) |
| 365 | kobject_uevent(&p->kobj, KOBJ_ADD); | 366 | kobject_uevent(&p->kobj, KOBJ_ADD); |
| 367 | sysfs_create_link(&p->kobj, &block_subsys.kset.kobj, "subsystem"); | ||
| 366 | partition_sysfs_add_subdir(p); | 368 | partition_sysfs_add_subdir(p); |
| 367 | disk->part[part-1] = p; | 369 | disk->part[part-1] = p; |
| 368 | } | 370 | } |
| @@ -398,6 +400,7 @@ static void disk_sysfs_symlinks(struct gendisk *disk) | |||
| 398 | kfree(disk_name); | 400 | kfree(disk_name); |
| 399 | } | 401 | } |
| 400 | } | 402 | } |
| 403 | sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj, "subsystem"); | ||
| 401 | } | 404 | } |
| 402 | 405 | ||
| 403 | /* Not exported, helper to add_disk(). */ | 406 | /* Not exported, helper to add_disk(). */ |
| @@ -548,5 +551,6 @@ void del_gendisk(struct gendisk *disk) | |||
| 548 | put_device(disk->driverfs_dev); | 551 | put_device(disk->driverfs_dev); |
| 549 | disk->driverfs_dev = NULL; | 552 | disk->driverfs_dev = NULL; |
| 550 | } | 553 | } |
| 554 | sysfs_remove_link(&disk->kobj, "subsystem"); | ||
| 551 | kobject_del(&disk->kobj); | 555 | kobject_del(&disk->kobj); |
| 552 | } | 556 | } |
diff --git a/fs/super.c b/fs/super.c index a66f66bb8049..9d5c2add7228 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -231,7 +231,7 @@ void generic_shutdown_super(struct super_block *sb) | |||
| 231 | if (root) { | 231 | if (root) { |
| 232 | sb->s_root = NULL; | 232 | sb->s_root = NULL; |
| 233 | shrink_dcache_parent(root); | 233 | shrink_dcache_parent(root); |
| 234 | shrink_dcache_anon(&sb->s_anon); | 234 | shrink_dcache_anon(sb); |
| 235 | dput(root); | 235 | dput(root); |
| 236 | fsync_super(sb); | 236 | fsync_super(sb); |
| 237 | lock_super(sb); | 237 | lock_super(sb); |
diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig index bac27d66151d..26b364c9d62c 100644 --- a/fs/xfs/Kconfig +++ b/fs/xfs/Kconfig | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | config XFS_FS | 1 | config XFS_FS |
| 2 | tristate "XFS filesystem support" | 2 | tristate "XFS filesystem support" |
| 3 | select EXPORTFS if NFSD!=n | ||
| 4 | help | 3 | help |
| 5 | XFS is a high performance journaling filesystem which originated | 4 | XFS is a high performance journaling filesystem which originated |
| 6 | on the SGI IRIX platform. It is completely multi-threaded, can | 5 | on the SGI IRIX platform. It is completely multi-threaded, can |
| @@ -18,11 +17,6 @@ config XFS_FS | |||
| 18 | system of your root partition is compiled as a module, you'll need | 17 | system of your root partition is compiled as a module, you'll need |
| 19 | to use an initial ramdisk (initrd) to boot. | 18 | to use an initial ramdisk (initrd) to boot. |
| 20 | 19 | ||
| 21 | config XFS_EXPORT | ||
| 22 | bool | ||
| 23 | depends on XFS_FS && EXPORTFS | ||
| 24 | default y | ||
| 25 | |||
| 26 | config XFS_QUOTA | 20 | config XFS_QUOTA |
| 27 | bool "XFS Quota support" | 21 | bool "XFS Quota support" |
| 28 | depends on XFS_FS | 22 | depends on XFS_FS |
| @@ -65,18 +59,19 @@ config XFS_POSIX_ACL | |||
| 65 | If you don't know what Access Control Lists are, say N. | 59 | If you don't know what Access Control Lists are, say N. |
| 66 | 60 | ||
| 67 | config XFS_RT | 61 | config XFS_RT |
| 68 | bool "XFS Realtime support (EXPERIMENTAL)" | 62 | bool "XFS Realtime subvolume support" |
| 69 | depends on XFS_FS && EXPERIMENTAL | 63 | depends on XFS_FS |
| 70 | help | 64 | help |
| 71 | If you say Y here you will be able to mount and use XFS filesystems | 65 | If you say Y here you will be able to mount and use XFS filesystems |
| 72 | which contain a realtime subvolume. The realtime subvolume is a | 66 | which contain a realtime subvolume. The realtime subvolume is a |
| 73 | separate area of disk space where only file data is stored. The | 67 | separate area of disk space where only file data is stored. It was |
| 74 | realtime subvolume is designed to provide very deterministic | 68 | originally designed to provide deterministic data rates suitable |
| 75 | data rates suitable for media streaming applications. | 69 | for media streaming applications, but is also useful as a generic |
| 76 | 70 | mechanism for ensuring data and metadata/log I/Os are completely | |
| 77 | See the xfs man page in section 5 for a bit more information. | 71 | separated. Regular file I/Os are isolated to a separate device |
| 72 | from all other requests, and this can be done quite transparently | ||
| 73 | to applications via the inherit-realtime directory inode flag. | ||
| 78 | 74 | ||
| 79 | This feature is unsupported at this time, is not yet fully | 75 | See the xfs man page in section 5 for additional information. |
| 80 | functional, and may cause serious problems. | ||
| 81 | 76 | ||
| 82 | If unsure, say N. | 77 | If unsure, say N. |
diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6 index 5d73eaa1971f..9e7f85986d0d 100644 --- a/fs/xfs/Makefile-linux-2.6 +++ b/fs/xfs/Makefile-linux-2.6 | |||
| @@ -59,7 +59,6 @@ xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o | |||
| 59 | xfs-$(CONFIG_PROC_FS) += $(XFS_LINUX)/xfs_stats.o | 59 | xfs-$(CONFIG_PROC_FS) += $(XFS_LINUX)/xfs_stats.o |
| 60 | xfs-$(CONFIG_SYSCTL) += $(XFS_LINUX)/xfs_sysctl.o | 60 | xfs-$(CONFIG_SYSCTL) += $(XFS_LINUX)/xfs_sysctl.o |
| 61 | xfs-$(CONFIG_COMPAT) += $(XFS_LINUX)/xfs_ioctl32.o | 61 | xfs-$(CONFIG_COMPAT) += $(XFS_LINUX)/xfs_ioctl32.o |
| 62 | xfs-$(CONFIG_XFS_EXPORT) += $(XFS_LINUX)/xfs_export.o | ||
| 63 | 62 | ||
| 64 | 63 | ||
| 65 | xfs-y += xfs_alloc.o \ | 64 | xfs-y += xfs_alloc.o \ |
| @@ -73,14 +72,12 @@ xfs-y += xfs_alloc.o \ | |||
| 73 | xfs_btree.o \ | 72 | xfs_btree.o \ |
| 74 | xfs_buf_item.o \ | 73 | xfs_buf_item.o \ |
| 75 | xfs_da_btree.o \ | 74 | xfs_da_btree.o \ |
| 76 | xfs_dir.o \ | ||
| 77 | xfs_dir2.o \ | 75 | xfs_dir2.o \ |
| 78 | xfs_dir2_block.o \ | 76 | xfs_dir2_block.o \ |
| 79 | xfs_dir2_data.o \ | 77 | xfs_dir2_data.o \ |
| 80 | xfs_dir2_leaf.o \ | 78 | xfs_dir2_leaf.o \ |
| 81 | xfs_dir2_node.o \ | 79 | xfs_dir2_node.o \ |
| 82 | xfs_dir2_sf.o \ | 80 | xfs_dir2_sf.o \ |
| 83 | xfs_dir_leaf.o \ | ||
| 84 | xfs_error.o \ | 81 | xfs_error.o \ |
| 85 | xfs_extfree_item.o \ | 82 | xfs_extfree_item.o \ |
| 86 | xfs_fsops.o \ | 83 | xfs_fsops.o \ |
| @@ -117,6 +114,7 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \ | |||
| 117 | kmem.o \ | 114 | kmem.o \ |
| 118 | xfs_aops.o \ | 115 | xfs_aops.o \ |
| 119 | xfs_buf.o \ | 116 | xfs_buf.o \ |
| 117 | xfs_export.o \ | ||
| 120 | xfs_file.o \ | 118 | xfs_file.o \ |
| 121 | xfs_fs_subr.o \ | 119 | xfs_fs_subr.o \ |
| 122 | xfs_globals.o \ | 120 | xfs_globals.o \ |
diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index 2cfd33d4d8aa..939bd84bc7ee 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h | |||
| @@ -23,42 +23,6 @@ | |||
| 23 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
| 24 | 24 | ||
| 25 | /* | 25 | /* |
| 26 | * Process flags handling | ||
| 27 | */ | ||
| 28 | |||
| 29 | #define PFLAGS_TEST_NOIO() (current->flags & PF_NOIO) | ||
| 30 | #define PFLAGS_TEST_FSTRANS() (current->flags & PF_FSTRANS) | ||
| 31 | |||
| 32 | #define PFLAGS_SET_NOIO() do { \ | ||
| 33 | current->flags |= PF_NOIO; \ | ||
| 34 | } while (0) | ||
| 35 | |||
| 36 | #define PFLAGS_CLEAR_NOIO() do { \ | ||
| 37 | current->flags &= ~PF_NOIO; \ | ||
| 38 | } while (0) | ||
| 39 | |||
| 40 | /* these could be nested, so we save state */ | ||
| 41 | #define PFLAGS_SET_FSTRANS(STATEP) do { \ | ||
| 42 | *(STATEP) = current->flags; \ | ||
| 43 | current->flags |= PF_FSTRANS; \ | ||
| 44 | } while (0) | ||
| 45 | |||
| 46 | #define PFLAGS_CLEAR_FSTRANS(STATEP) do { \ | ||
| 47 | *(STATEP) = current->flags; \ | ||
| 48 | current->flags &= ~PF_FSTRANS; \ | ||
| 49 | } while (0) | ||
| 50 | |||
| 51 | /* Restore the PF_FSTRANS state to what was saved in STATEP */ | ||
| 52 | #define PFLAGS_RESTORE_FSTRANS(STATEP) do { \ | ||
| 53 | current->flags = ((current->flags & ~PF_FSTRANS) | \ | ||
| 54 | (*(STATEP) & PF_FSTRANS)); \ | ||
| 55 | } while (0) | ||
| 56 | |||
| 57 | #define PFLAGS_DUP(OSTATEP, NSTATEP) do { \ | ||
| 58 | *(NSTATEP) = *(OSTATEP); \ | ||
| 59 | } while (0) | ||
| 60 | |||
| 61 | /* | ||
| 62 | * General memory allocation interfaces | 26 | * General memory allocation interfaces |
| 63 | */ | 27 | */ |
| 64 | 28 | ||
| @@ -83,7 +47,7 @@ kmem_flags_convert(unsigned int __nocast flags) | |||
| 83 | lflags = GFP_ATOMIC | __GFP_NOWARN; | 47 | lflags = GFP_ATOMIC | __GFP_NOWARN; |
| 84 | } else { | 48 | } else { |
| 85 | lflags = GFP_KERNEL | __GFP_NOWARN; | 49 | lflags = GFP_KERNEL | __GFP_NOWARN; |
| 86 | if (PFLAGS_TEST_FSTRANS() || (flags & KM_NOFS)) | 50 | if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS)) |
| 87 | lflags &= ~__GFP_FS; | 51 | lflags &= ~__GFP_FS; |
| 88 | } | 52 | } |
| 89 | return lflags; | 53 | return lflags; |
diff --git a/fs/xfs/linux-2.6/mrlock.h b/fs/xfs/linux-2.6/mrlock.h index 1b262b790d9c..32e1ce0f04c9 100644 --- a/fs/xfs/linux-2.6/mrlock.h +++ b/fs/xfs/linux-2.6/mrlock.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -28,7 +28,7 @@ typedef struct { | |||
| 28 | } mrlock_t; | 28 | } mrlock_t; |
| 29 | 29 | ||
| 30 | #define mrinit(mrp, name) \ | 30 | #define mrinit(mrp, name) \ |
| 31 | ( (mrp)->mr_writer = 0, init_rwsem(&(mrp)->mr_lock) ) | 31 | do { (mrp)->mr_writer = 0; init_rwsem(&(mrp)->mr_lock); } while (0) |
| 32 | #define mrlock_init(mrp, t,n,s) mrinit(mrp, n) | 32 | #define mrlock_init(mrp, t,n,s) mrinit(mrp, n) |
| 33 | #define mrfree(mrp) do { } while (0) | 33 | #define mrfree(mrp) do { } while (0) |
| 34 | #define mraccess(mrp) mraccessf(mrp, 0) | 34 | #define mraccess(mrp) mraccessf(mrp, 0) |
diff --git a/fs/xfs/linux-2.6/sema.h b/fs/xfs/linux-2.6/sema.h index 194a84490bd1..b25090094cca 100644 --- a/fs/xfs/linux-2.6/sema.h +++ b/fs/xfs/linux-2.6/sema.h | |||
| @@ -34,20 +34,21 @@ typedef struct semaphore sema_t; | |||
| 34 | #define initnsema(sp, val, name) sema_init(sp, val) | 34 | #define initnsema(sp, val, name) sema_init(sp, val) |
| 35 | #define psema(sp, b) down(sp) | 35 | #define psema(sp, b) down(sp) |
| 36 | #define vsema(sp) up(sp) | 36 | #define vsema(sp) up(sp) |
| 37 | #define valusema(sp) (atomic_read(&(sp)->count)) | 37 | #define freesema(sema) do { } while (0) |
| 38 | #define freesema(sema) | 38 | |
| 39 | static inline int issemalocked(sema_t *sp) | ||
| 40 | { | ||
| 41 | return down_trylock(sp) || (up(sp), 0); | ||
| 42 | } | ||
| 39 | 43 | ||
| 40 | /* | 44 | /* |
| 41 | * Map cpsema (try to get the sema) to down_trylock. We need to switch | 45 | * Map cpsema (try to get the sema) to down_trylock. We need to switch |
| 42 | * the return values since cpsema returns 1 (acquired) 0 (failed) and | 46 | * the return values since cpsema returns 1 (acquired) 0 (failed) and |
| 43 | * down_trylock returns the reverse 0 (acquired) 1 (failed). | 47 | * down_trylock returns the reverse 0 (acquired) 1 (failed). |
| 44 | */ | 48 | */ |
| 45 | 49 | static inline int cpsema(sema_t *sp) | |
| 46 | #define cpsema(sp) (down_trylock(sp) ? 0 : 1) | 50 | { |
| 47 | 51 | return down_trylock(sp) ? 0 : 1; | |
| 48 | /* | 52 | } |
| 49 | * Didn't do cvsema(sp). Not sure how to map this to up/down/... | ||
| 50 | * It does a vsema if the values is < 0 other wise nothing. | ||
| 51 | */ | ||
| 52 | 53 | ||
| 53 | #endif /* __XFS_SUPPORT_SEMA_H__ */ | 54 | #endif /* __XFS_SUPPORT_SEMA_H__ */ |
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 4d191ef39b67..3e807b828e22 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include "xfs_inum.h" | 21 | #include "xfs_inum.h" |
| 22 | #include "xfs_sb.h" | 22 | #include "xfs_sb.h" |
| 23 | #include "xfs_ag.h" | 23 | #include "xfs_ag.h" |
| 24 | #include "xfs_dir.h" | ||
| 25 | #include "xfs_dir2.h" | 24 | #include "xfs_dir2.h" |
| 26 | #include "xfs_trans.h" | 25 | #include "xfs_trans.h" |
| 27 | #include "xfs_dmapi.h" | 26 | #include "xfs_dmapi.h" |
| @@ -29,7 +28,6 @@ | |||
| 29 | #include "xfs_bmap_btree.h" | 28 | #include "xfs_bmap_btree.h" |
| 30 | #include "xfs_alloc_btree.h" | 29 | #include "xfs_alloc_btree.h" |
| 31 | #include "xfs_ialloc_btree.h" | 30 | #include "xfs_ialloc_btree.h" |
| 32 | #include "xfs_dir_sf.h" | ||
| 33 | #include "xfs_dir2_sf.h" | 31 | #include "xfs_dir2_sf.h" |
| 34 | #include "xfs_attr_sf.h" | 32 | #include "xfs_attr_sf.h" |
| 35 | #include "xfs_dinode.h" | 33 | #include "xfs_dinode.h" |
| @@ -76,7 +74,7 @@ xfs_page_trace( | |||
| 76 | int mask) | 74 | int mask) |
| 77 | { | 75 | { |
| 78 | xfs_inode_t *ip; | 76 | xfs_inode_t *ip; |
| 79 | vnode_t *vp = vn_from_inode(inode); | 77 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 80 | loff_t isize = i_size_read(inode); | 78 | loff_t isize = i_size_read(inode); |
| 81 | loff_t offset = page_offset(page); | 79 | loff_t offset = page_offset(page); |
| 82 | int delalloc = -1, unmapped = -1, unwritten = -1; | 80 | int delalloc = -1, unmapped = -1, unwritten = -1; |
| @@ -136,9 +134,10 @@ xfs_destroy_ioend( | |||
| 136 | 134 | ||
| 137 | for (bh = ioend->io_buffer_head; bh; bh = next) { | 135 | for (bh = ioend->io_buffer_head; bh; bh = next) { |
| 138 | next = bh->b_private; | 136 | next = bh->b_private; |
| 139 | bh->b_end_io(bh, ioend->io_uptodate); | 137 | bh->b_end_io(bh, !ioend->io_error); |
| 140 | } | 138 | } |
| 141 | 139 | if (unlikely(ioend->io_error)) | |
| 140 | vn_ioerror(ioend->io_vnode, ioend->io_error, __FILE__,__LINE__); | ||
| 142 | vn_iowake(ioend->io_vnode); | 141 | vn_iowake(ioend->io_vnode); |
| 143 | mempool_free(ioend, xfs_ioend_pool); | 142 | mempool_free(ioend, xfs_ioend_pool); |
| 144 | } | 143 | } |
| @@ -180,13 +179,12 @@ xfs_end_bio_unwritten( | |||
| 180 | void *data) | 179 | void *data) |
| 181 | { | 180 | { |
| 182 | xfs_ioend_t *ioend = data; | 181 | xfs_ioend_t *ioend = data; |
| 183 | vnode_t *vp = ioend->io_vnode; | 182 | bhv_vnode_t *vp = ioend->io_vnode; |
| 184 | xfs_off_t offset = ioend->io_offset; | 183 | xfs_off_t offset = ioend->io_offset; |
| 185 | size_t size = ioend->io_size; | 184 | size_t size = ioend->io_size; |
| 186 | int error; | ||
| 187 | 185 | ||
| 188 | if (ioend->io_uptodate) | 186 | if (likely(!ioend->io_error)) |
| 189 | VOP_BMAP(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL, error); | 187 | bhv_vop_bmap(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL); |
| 190 | xfs_destroy_ioend(ioend); | 188 | xfs_destroy_ioend(ioend); |
| 191 | } | 189 | } |
| 192 | 190 | ||
| @@ -211,7 +209,7 @@ xfs_alloc_ioend( | |||
| 211 | * all the I/O from calling the completion routine too early. | 209 | * all the I/O from calling the completion routine too early. |
| 212 | */ | 210 | */ |
| 213 | atomic_set(&ioend->io_remaining, 1); | 211 | atomic_set(&ioend->io_remaining, 1); |
| 214 | ioend->io_uptodate = 1; /* cleared if any I/O fails */ | 212 | ioend->io_error = 0; |
| 215 | ioend->io_list = NULL; | 213 | ioend->io_list = NULL; |
| 216 | ioend->io_type = type; | 214 | ioend->io_type = type; |
| 217 | ioend->io_vnode = vn_from_inode(inode); | 215 | ioend->io_vnode = vn_from_inode(inode); |
| @@ -239,10 +237,10 @@ xfs_map_blocks( | |||
| 239 | xfs_iomap_t *mapp, | 237 | xfs_iomap_t *mapp, |
| 240 | int flags) | 238 | int flags) |
| 241 | { | 239 | { |
| 242 | vnode_t *vp = vn_from_inode(inode); | 240 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 243 | int error, nmaps = 1; | 241 | int error, nmaps = 1; |
| 244 | 242 | ||
| 245 | VOP_BMAP(vp, offset, count, flags, mapp, &nmaps, error); | 243 | error = bhv_vop_bmap(vp, offset, count, flags, mapp, &nmaps); |
| 246 | if (!error && (flags & (BMAPI_WRITE|BMAPI_ALLOCATE))) | 244 | if (!error && (flags & (BMAPI_WRITE|BMAPI_ALLOCATE))) |
| 247 | VMODIFY(vp); | 245 | VMODIFY(vp); |
| 248 | return -error; | 246 | return -error; |
| @@ -271,16 +269,14 @@ xfs_end_bio( | |||
| 271 | if (bio->bi_size) | 269 | if (bio->bi_size) |
| 272 | return 1; | 270 | return 1; |
| 273 | 271 | ||
| 274 | ASSERT(ioend); | ||
| 275 | ASSERT(atomic_read(&bio->bi_cnt) >= 1); | 272 | ASSERT(atomic_read(&bio->bi_cnt) >= 1); |
| 273 | ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error; | ||
| 276 | 274 | ||
| 277 | /* Toss bio and pass work off to an xfsdatad thread */ | 275 | /* Toss bio and pass work off to an xfsdatad thread */ |
| 278 | if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) | ||
| 279 | ioend->io_uptodate = 0; | ||
| 280 | bio->bi_private = NULL; | 276 | bio->bi_private = NULL; |
| 281 | bio->bi_end_io = NULL; | 277 | bio->bi_end_io = NULL; |
| 282 | |||
| 283 | bio_put(bio); | 278 | bio_put(bio); |
| 279 | |||
| 284 | xfs_finish_ioend(ioend); | 280 | xfs_finish_ioend(ioend); |
| 285 | return 0; | 281 | return 0; |
| 286 | } | 282 | } |
| @@ -1127,7 +1123,7 @@ xfs_vm_writepage( | |||
| 1127 | * then mark the page dirty again and leave the page | 1123 | * then mark the page dirty again and leave the page |
| 1128 | * as is. | 1124 | * as is. |
| 1129 | */ | 1125 | */ |
| 1130 | if (PFLAGS_TEST_FSTRANS() && need_trans) | 1126 | if (current_test_flags(PF_FSTRANS) && need_trans) |
| 1131 | goto out_fail; | 1127 | goto out_fail; |
| 1132 | 1128 | ||
| 1133 | /* | 1129 | /* |
| @@ -1158,6 +1154,18 @@ out_unlock: | |||
| 1158 | return error; | 1154 | return error; |
| 1159 | } | 1155 | } |
| 1160 | 1156 | ||
| 1157 | STATIC int | ||
| 1158 | xfs_vm_writepages( | ||
| 1159 | struct address_space *mapping, | ||
| 1160 | struct writeback_control *wbc) | ||
| 1161 | { | ||
| 1162 | struct bhv_vnode *vp = vn_from_inode(mapping->host); | ||
| 1163 | |||
| 1164 | if (VN_TRUNC(vp)) | ||
| 1165 | VUNTRUNCATE(vp); | ||
| 1166 | return generic_writepages(mapping, wbc); | ||
| 1167 | } | ||
| 1168 | |||
| 1161 | /* | 1169 | /* |
| 1162 | * Called to move a page into cleanable state - and from there | 1170 | * Called to move a page into cleanable state - and from there |
| 1163 | * to be released. Possibly the page is already clean. We always | 1171 | * to be released. Possibly the page is already clean. We always |
| @@ -1204,7 +1212,7 @@ xfs_vm_releasepage( | |||
| 1204 | /* If we are already inside a transaction or the thread cannot | 1212 | /* If we are already inside a transaction or the thread cannot |
| 1205 | * do I/O, we cannot release this page. | 1213 | * do I/O, we cannot release this page. |
| 1206 | */ | 1214 | */ |
| 1207 | if (PFLAGS_TEST_FSTRANS()) | 1215 | if (current_test_flags(PF_FSTRANS)) |
| 1208 | return 0; | 1216 | return 0; |
| 1209 | 1217 | ||
| 1210 | /* | 1218 | /* |
| @@ -1231,7 +1239,7 @@ __xfs_get_blocks( | |||
| 1231 | int direct, | 1239 | int direct, |
| 1232 | bmapi_flags_t flags) | 1240 | bmapi_flags_t flags) |
| 1233 | { | 1241 | { |
| 1234 | vnode_t *vp = vn_from_inode(inode); | 1242 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 1235 | xfs_iomap_t iomap; | 1243 | xfs_iomap_t iomap; |
| 1236 | xfs_off_t offset; | 1244 | xfs_off_t offset; |
| 1237 | ssize_t size; | 1245 | ssize_t size; |
| @@ -1241,8 +1249,8 @@ __xfs_get_blocks( | |||
| 1241 | offset = (xfs_off_t)iblock << inode->i_blkbits; | 1249 | offset = (xfs_off_t)iblock << inode->i_blkbits; |
| 1242 | ASSERT(bh_result->b_size >= (1 << inode->i_blkbits)); | 1250 | ASSERT(bh_result->b_size >= (1 << inode->i_blkbits)); |
| 1243 | size = bh_result->b_size; | 1251 | size = bh_result->b_size; |
| 1244 | VOP_BMAP(vp, offset, size, | 1252 | error = bhv_vop_bmap(vp, offset, size, |
| 1245 | create ? flags : BMAPI_READ, &iomap, &niomap, error); | 1253 | create ? flags : BMAPI_READ, &iomap, &niomap); |
| 1246 | if (error) | 1254 | if (error) |
| 1247 | return -error; | 1255 | return -error; |
| 1248 | if (niomap == 0) | 1256 | if (niomap == 0) |
| @@ -1370,13 +1378,13 @@ xfs_vm_direct_IO( | |||
| 1370 | { | 1378 | { |
| 1371 | struct file *file = iocb->ki_filp; | 1379 | struct file *file = iocb->ki_filp; |
| 1372 | struct inode *inode = file->f_mapping->host; | 1380 | struct inode *inode = file->f_mapping->host; |
| 1373 | vnode_t *vp = vn_from_inode(inode); | 1381 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 1374 | xfs_iomap_t iomap; | 1382 | xfs_iomap_t iomap; |
| 1375 | int maps = 1; | 1383 | int maps = 1; |
| 1376 | int error; | 1384 | int error; |
| 1377 | ssize_t ret; | 1385 | ssize_t ret; |
| 1378 | 1386 | ||
| 1379 | VOP_BMAP(vp, offset, 0, BMAPI_DEVICE, &iomap, &maps, error); | 1387 | error = bhv_vop_bmap(vp, offset, 0, BMAPI_DEVICE, &iomap, &maps); |
| 1380 | if (error) | 1388 | if (error) |
| 1381 | return -error; | 1389 | return -error; |
| 1382 | 1390 | ||
| @@ -1409,14 +1417,12 @@ xfs_vm_bmap( | |||
| 1409 | sector_t block) | 1417 | sector_t block) |
| 1410 | { | 1418 | { |
| 1411 | struct inode *inode = (struct inode *)mapping->host; | 1419 | struct inode *inode = (struct inode *)mapping->host; |
| 1412 | vnode_t *vp = vn_from_inode(inode); | 1420 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 1413 | int error; | ||
| 1414 | 1421 | ||
| 1415 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); | 1422 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); |
| 1416 | 1423 | bhv_vop_rwlock(vp, VRWLOCK_READ); | |
| 1417 | VOP_RWLOCK(vp, VRWLOCK_READ); | 1424 | bhv_vop_flush_pages(vp, (xfs_off_t)0, -1, 0, FI_REMAPF); |
| 1418 | VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error); | 1425 | bhv_vop_rwunlock(vp, VRWLOCK_READ); |
| 1419 | VOP_RWUNLOCK(vp, VRWLOCK_READ); | ||
| 1420 | return generic_block_bmap(mapping, block, xfs_get_blocks); | 1426 | return generic_block_bmap(mapping, block, xfs_get_blocks); |
| 1421 | } | 1427 | } |
| 1422 | 1428 | ||
| @@ -1452,6 +1458,7 @@ struct address_space_operations xfs_address_space_operations = { | |||
| 1452 | .readpage = xfs_vm_readpage, | 1458 | .readpage = xfs_vm_readpage, |
| 1453 | .readpages = xfs_vm_readpages, | 1459 | .readpages = xfs_vm_readpages, |
| 1454 | .writepage = xfs_vm_writepage, | 1460 | .writepage = xfs_vm_writepage, |
| 1461 | .writepages = xfs_vm_writepages, | ||
| 1455 | .sync_page = block_sync_page, | 1462 | .sync_page = block_sync_page, |
| 1456 | .releasepage = xfs_vm_releasepage, | 1463 | .releasepage = xfs_vm_releasepage, |
| 1457 | .invalidatepage = xfs_vm_invalidatepage, | 1464 | .invalidatepage = xfs_vm_invalidatepage, |
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/linux-2.6/xfs_aops.h index 60716543c68b..706d8c781b8a 100644 --- a/fs/xfs/linux-2.6/xfs_aops.h +++ b/fs/xfs/linux-2.6/xfs_aops.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2005-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -30,9 +30,9 @@ typedef void (*xfs_ioend_func_t)(void *); | |||
| 30 | typedef struct xfs_ioend { | 30 | typedef struct xfs_ioend { |
| 31 | struct xfs_ioend *io_list; /* next ioend in chain */ | 31 | struct xfs_ioend *io_list; /* next ioend in chain */ |
| 32 | unsigned int io_type; /* delalloc / unwritten */ | 32 | unsigned int io_type; /* delalloc / unwritten */ |
| 33 | unsigned int io_uptodate; /* I/O status register */ | 33 | int io_error; /* I/O error code */ |
| 34 | atomic_t io_remaining; /* hold count */ | 34 | atomic_t io_remaining; /* hold count */ |
| 35 | struct vnode *io_vnode; /* file being written to */ | 35 | struct bhv_vnode *io_vnode; /* file being written to */ |
| 36 | struct buffer_head *io_buffer_head;/* buffer linked list head */ | 36 | struct buffer_head *io_buffer_head;/* buffer linked list head */ |
| 37 | struct buffer_head *io_buffer_tail;/* buffer linked list tail */ | 37 | struct buffer_head *io_buffer_tail;/* buffer linked list tail */ |
| 38 | size_t io_size; /* size of the extent */ | 38 | size_t io_size; /* size of the extent */ |
| @@ -43,4 +43,4 @@ typedef struct xfs_ioend { | |||
| 43 | extern struct address_space_operations xfs_address_space_operations; | 43 | extern struct address_space_operations xfs_address_space_operations; |
| 44 | extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int); | 44 | extern int xfs_get_blocks(struct inode *, sector_t, struct buffer_head *, int); |
| 45 | 45 | ||
| 46 | #endif /* __XFS_IOPS_H__ */ | 46 | #endif /* __XFS_AOPS_H__ */ |
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c index b768ea910bbe..5fb75d9151f2 100644 --- a/fs/xfs/linux-2.6/xfs_export.c +++ b/fs/xfs/linux-2.6/xfs_export.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include "xfs_log.h" | 21 | #include "xfs_log.h" |
| 22 | #include "xfs_trans.h" | 22 | #include "xfs_trans.h" |
| 23 | #include "xfs_sb.h" | 23 | #include "xfs_sb.h" |
| 24 | #include "xfs_dir.h" | ||
| 25 | #include "xfs_mount.h" | 24 | #include "xfs_mount.h" |
| 26 | #include "xfs_export.h" | 25 | #include "xfs_export.h" |
| 27 | 26 | ||
| @@ -97,7 +96,7 @@ xfs_fs_encode_fh( | |||
| 97 | int len; | 96 | int len; |
| 98 | int is64 = 0; | 97 | int is64 = 0; |
| 99 | #if XFS_BIG_INUMS | 98 | #if XFS_BIG_INUMS |
| 100 | vfs_t *vfs = vfs_from_sb(inode->i_sb); | 99 | bhv_vfs_t *vfs = vfs_from_sb(inode->i_sb); |
| 101 | 100 | ||
| 102 | if (!(vfs->vfs_flag & VFS_32BITINODES)) { | 101 | if (!(vfs->vfs_flag & VFS_32BITINODES)) { |
| 103 | /* filesystem may contain 64bit inode numbers */ | 102 | /* filesystem may contain 64bit inode numbers */ |
| @@ -136,13 +135,13 @@ xfs_fs_get_dentry( | |||
| 136 | struct super_block *sb, | 135 | struct super_block *sb, |
| 137 | void *data) | 136 | void *data) |
| 138 | { | 137 | { |
| 139 | vnode_t *vp; | 138 | bhv_vnode_t *vp; |
| 140 | struct inode *inode; | 139 | struct inode *inode; |
| 141 | struct dentry *result; | 140 | struct dentry *result; |
| 142 | vfs_t *vfsp = vfs_from_sb(sb); | 141 | bhv_vfs_t *vfsp = vfs_from_sb(sb); |
| 143 | int error; | 142 | int error; |
| 144 | 143 | ||
| 145 | VFS_VGET(vfsp, &vp, (fid_t *)data, error); | 144 | error = bhv_vfs_vget(vfsp, &vp, (fid_t *)data); |
| 146 | if (error || vp == NULL) | 145 | if (error || vp == NULL) |
| 147 | return ERR_PTR(-ESTALE) ; | 146 | return ERR_PTR(-ESTALE) ; |
| 148 | 147 | ||
| @@ -160,12 +159,12 @@ xfs_fs_get_parent( | |||
| 160 | struct dentry *child) | 159 | struct dentry *child) |
| 161 | { | 160 | { |
| 162 | int error; | 161 | int error; |
| 163 | vnode_t *vp, *cvp; | 162 | bhv_vnode_t *vp, *cvp; |
| 164 | struct dentry *parent; | 163 | struct dentry *parent; |
| 165 | 164 | ||
| 166 | cvp = NULL; | 165 | cvp = NULL; |
| 167 | vp = vn_from_inode(child->d_inode); | 166 | vp = vn_from_inode(child->d_inode); |
| 168 | VOP_LOOKUP(vp, &dotdot, &cvp, 0, NULL, NULL, error); | 167 | error = bhv_vop_lookup(vp, &dotdot, &cvp, 0, NULL, NULL); |
| 169 | if (unlikely(error)) | 168 | if (unlikely(error)) |
| 170 | return ERR_PTR(-error); | 169 | return ERR_PTR(-error); |
| 171 | 170 | ||
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index c847416f6d10..70662371bb11 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | #include "xfs_inum.h" | 21 | #include "xfs_inum.h" |
| 22 | #include "xfs_sb.h" | 22 | #include "xfs_sb.h" |
| 23 | #include "xfs_ag.h" | 23 | #include "xfs_ag.h" |
| 24 | #include "xfs_dir.h" | ||
| 25 | #include "xfs_dir2.h" | 24 | #include "xfs_dir2.h" |
| 26 | #include "xfs_trans.h" | 25 | #include "xfs_trans.h" |
| 27 | #include "xfs_dmapi.h" | 26 | #include "xfs_dmapi.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_alloc.h" | 31 | #include "xfs_alloc.h" |
| 33 | #include "xfs_btree.h" | 32 | #include "xfs_btree.h" |
| 34 | #include "xfs_attr_sf.h" | 33 | #include "xfs_attr_sf.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| 38 | #include "xfs_inode.h" | 36 | #include "xfs_inode.h" |
| @@ -58,15 +56,12 @@ __xfs_file_read( | |||
| 58 | { | 56 | { |
| 59 | struct iovec iov = {buf, count}; | 57 | struct iovec iov = {buf, count}; |
| 60 | struct file *file = iocb->ki_filp; | 58 | struct file *file = iocb->ki_filp; |
| 61 | vnode_t *vp = vn_from_inode(file->f_dentry->d_inode); | 59 | bhv_vnode_t *vp = vn_from_inode(file->f_dentry->d_inode); |
| 62 | ssize_t rval; | ||
| 63 | 60 | ||
| 64 | BUG_ON(iocb->ki_pos != pos); | 61 | BUG_ON(iocb->ki_pos != pos); |
| 65 | |||
| 66 | if (unlikely(file->f_flags & O_DIRECT)) | 62 | if (unlikely(file->f_flags & O_DIRECT)) |
| 67 | ioflags |= IO_ISDIRECT; | 63 | ioflags |= IO_ISDIRECT; |
| 68 | VOP_READ(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, rval); | 64 | return bhv_vop_read(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL); |
| 69 | return rval; | ||
| 70 | } | 65 | } |
| 71 | 66 | ||
| 72 | STATIC ssize_t | 67 | STATIC ssize_t |
| @@ -100,15 +95,12 @@ __xfs_file_write( | |||
| 100 | struct iovec iov = {(void __user *)buf, count}; | 95 | struct iovec iov = {(void __user *)buf, count}; |
| 101 | struct file *file = iocb->ki_filp; | 96 | struct file *file = iocb->ki_filp; |
| 102 | struct inode *inode = file->f_mapping->host; | 97 | struct inode *inode = file->f_mapping->host; |
| 103 | vnode_t *vp = vn_from_inode(inode); | 98 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 104 | ssize_t rval; | ||
| 105 | 99 | ||
| 106 | BUG_ON(iocb->ki_pos != pos); | 100 | BUG_ON(iocb->ki_pos != pos); |
| 107 | if (unlikely(file->f_flags & O_DIRECT)) | 101 | if (unlikely(file->f_flags & O_DIRECT)) |
| 108 | ioflags |= IO_ISDIRECT; | 102 | ioflags |= IO_ISDIRECT; |
| 109 | 103 | return bhv_vop_write(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL); | |
| 110 | VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, rval); | ||
| 111 | return rval; | ||
| 112 | } | 104 | } |
| 113 | 105 | ||
| 114 | STATIC ssize_t | 106 | STATIC ssize_t |
| @@ -140,7 +132,7 @@ __xfs_file_readv( | |||
| 140 | loff_t *ppos) | 132 | loff_t *ppos) |
| 141 | { | 133 | { |
| 142 | struct inode *inode = file->f_mapping->host; | 134 | struct inode *inode = file->f_mapping->host; |
| 143 | vnode_t *vp = vn_from_inode(inode); | 135 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 144 | struct kiocb kiocb; | 136 | struct kiocb kiocb; |
| 145 | ssize_t rval; | 137 | ssize_t rval; |
| 146 | 138 | ||
| @@ -149,7 +141,8 @@ __xfs_file_readv( | |||
| 149 | 141 | ||
| 150 | if (unlikely(file->f_flags & O_DIRECT)) | 142 | if (unlikely(file->f_flags & O_DIRECT)) |
| 151 | ioflags |= IO_ISDIRECT; | 143 | ioflags |= IO_ISDIRECT; |
| 152 | VOP_READ(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, rval); | 144 | rval = bhv_vop_read(vp, &kiocb, iov, nr_segs, |
| 145 | &kiocb.ki_pos, ioflags, NULL); | ||
| 153 | 146 | ||
| 154 | *ppos = kiocb.ki_pos; | 147 | *ppos = kiocb.ki_pos; |
| 155 | return rval; | 148 | return rval; |
| @@ -184,7 +177,7 @@ __xfs_file_writev( | |||
| 184 | loff_t *ppos) | 177 | loff_t *ppos) |
| 185 | { | 178 | { |
| 186 | struct inode *inode = file->f_mapping->host; | 179 | struct inode *inode = file->f_mapping->host; |
| 187 | vnode_t *vp = vn_from_inode(inode); | 180 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 188 | struct kiocb kiocb; | 181 | struct kiocb kiocb; |
| 189 | ssize_t rval; | 182 | ssize_t rval; |
| 190 | 183 | ||
| @@ -193,7 +186,8 @@ __xfs_file_writev( | |||
| 193 | if (unlikely(file->f_flags & O_DIRECT)) | 186 | if (unlikely(file->f_flags & O_DIRECT)) |
| 194 | ioflags |= IO_ISDIRECT; | 187 | ioflags |= IO_ISDIRECT; |
| 195 | 188 | ||
| 196 | VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, rval); | 189 | rval = bhv_vop_write(vp, &kiocb, iov, nr_segs, |
| 190 | &kiocb.ki_pos, ioflags, NULL); | ||
| 197 | 191 | ||
| 198 | *ppos = kiocb.ki_pos; | 192 | *ppos = kiocb.ki_pos; |
| 199 | return rval; | 193 | return rval; |
| @@ -227,11 +221,8 @@ xfs_file_sendfile( | |||
| 227 | read_actor_t actor, | 221 | read_actor_t actor, |
| 228 | void *target) | 222 | void *target) |
| 229 | { | 223 | { |
| 230 | vnode_t *vp = vn_from_inode(filp->f_dentry->d_inode); | 224 | return bhv_vop_sendfile(vn_from_inode(filp->f_dentry->d_inode), |
| 231 | ssize_t rval; | 225 | filp, pos, 0, count, actor, target, NULL); |
| 232 | |||
| 233 | VOP_SENDFILE(vp, filp, pos, 0, count, actor, target, NULL, rval); | ||
| 234 | return rval; | ||
| 235 | } | 226 | } |
| 236 | 227 | ||
| 237 | STATIC ssize_t | 228 | STATIC ssize_t |
| @@ -242,11 +233,8 @@ xfs_file_sendfile_invis( | |||
| 242 | read_actor_t actor, | 233 | read_actor_t actor, |
| 243 | void *target) | 234 | void *target) |
| 244 | { | 235 | { |
| 245 | vnode_t *vp = vn_from_inode(filp->f_dentry->d_inode); | 236 | return bhv_vop_sendfile(vn_from_inode(filp->f_dentry->d_inode), |
| 246 | ssize_t rval; | 237 | filp, pos, IO_INVIS, count, actor, target, NULL); |
| 247 | |||
| 248 | VOP_SENDFILE(vp, filp, pos, IO_INVIS, count, actor, target, NULL, rval); | ||
| 249 | return rval; | ||
| 250 | } | 238 | } |
| 251 | 239 | ||
| 252 | STATIC ssize_t | 240 | STATIC ssize_t |
| @@ -257,11 +245,8 @@ xfs_file_splice_read( | |||
| 257 | size_t len, | 245 | size_t len, |
| 258 | unsigned int flags) | 246 | unsigned int flags) |
| 259 | { | 247 | { |
| 260 | vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); | 248 | return bhv_vop_splice_read(vn_from_inode(infilp->f_dentry->d_inode), |
| 261 | ssize_t rval; | 249 | infilp, ppos, pipe, len, flags, 0, NULL); |
| 262 | |||
| 263 | VOP_SPLICE_READ(vp, infilp, ppos, pipe, len, flags, 0, NULL, rval); | ||
| 264 | return rval; | ||
| 265 | } | 250 | } |
| 266 | 251 | ||
| 267 | STATIC ssize_t | 252 | STATIC ssize_t |
| @@ -272,11 +257,9 @@ xfs_file_splice_read_invis( | |||
| 272 | size_t len, | 257 | size_t len, |
| 273 | unsigned int flags) | 258 | unsigned int flags) |
| 274 | { | 259 | { |
| 275 | vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); | 260 | return bhv_vop_splice_read(vn_from_inode(infilp->f_dentry->d_inode), |
| 276 | ssize_t rval; | 261 | infilp, ppos, pipe, len, flags, IO_INVIS, |
| 277 | 262 | NULL); | |
| 278 | VOP_SPLICE_READ(vp, infilp, ppos, pipe, len, flags, IO_INVIS, NULL, rval); | ||
| 279 | return rval; | ||
| 280 | } | 263 | } |
| 281 | 264 | ||
| 282 | STATIC ssize_t | 265 | STATIC ssize_t |
| @@ -287,11 +270,8 @@ xfs_file_splice_write( | |||
| 287 | size_t len, | 270 | size_t len, |
| 288 | unsigned int flags) | 271 | unsigned int flags) |
| 289 | { | 272 | { |
| 290 | vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); | 273 | return bhv_vop_splice_write(vn_from_inode(outfilp->f_dentry->d_inode), |
| 291 | ssize_t rval; | 274 | pipe, outfilp, ppos, len, flags, 0, NULL); |
| 292 | |||
| 293 | VOP_SPLICE_WRITE(vp, pipe, outfilp, ppos, len, flags, 0, NULL, rval); | ||
| 294 | return rval; | ||
| 295 | } | 275 | } |
| 296 | 276 | ||
| 297 | STATIC ssize_t | 277 | STATIC ssize_t |
| @@ -302,11 +282,9 @@ xfs_file_splice_write_invis( | |||
| 302 | size_t len, | 282 | size_t len, |
| 303 | unsigned int flags) | 283 | unsigned int flags) |
| 304 | { | 284 | { |
| 305 | vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); | 285 | return bhv_vop_splice_write(vn_from_inode(outfilp->f_dentry->d_inode), |
| 306 | ssize_t rval; | 286 | pipe, outfilp, ppos, len, flags, IO_INVIS, |
| 307 | 287 | NULL); | |
| 308 | VOP_SPLICE_WRITE(vp, pipe, outfilp, ppos, len, flags, IO_INVIS, NULL, rval); | ||
| 309 | return rval; | ||
| 310 | } | 288 | } |
| 311 | 289 | ||
| 312 | STATIC int | 290 | STATIC int |
| @@ -314,13 +292,17 @@ xfs_file_open( | |||
| 314 | struct inode *inode, | 292 | struct inode *inode, |
| 315 | struct file *filp) | 293 | struct file *filp) |
| 316 | { | 294 | { |
| 317 | vnode_t *vp = vn_from_inode(inode); | ||
| 318 | int error; | ||
| 319 | |||
| 320 | if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) | 295 | if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) |
| 321 | return -EFBIG; | 296 | return -EFBIG; |
| 322 | VOP_OPEN(vp, NULL, error); | 297 | return -bhv_vop_open(vn_from_inode(inode), NULL); |
| 323 | return -error; | 298 | } |
| 299 | |||
| 300 | STATIC int | ||
| 301 | xfs_file_close( | ||
| 302 | struct file *filp) | ||
| 303 | { | ||
| 304 | return -bhv_vop_close(vn_from_inode(filp->f_dentry->d_inode), 0, | ||
| 305 | file_count(filp) > 1 ? L_FALSE : L_TRUE, NULL); | ||
| 324 | } | 306 | } |
| 325 | 307 | ||
| 326 | STATIC int | 308 | STATIC int |
| @@ -328,12 +310,11 @@ xfs_file_release( | |||
| 328 | struct inode *inode, | 310 | struct inode *inode, |
| 329 | struct file *filp) | 311 | struct file *filp) |
| 330 | { | 312 | { |
| 331 | vnode_t *vp = vn_from_inode(inode); | 313 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 332 | int error = 0; | ||
| 333 | 314 | ||
| 334 | if (vp) | 315 | if (vp) |
| 335 | VOP_RELEASE(vp, error); | 316 | return -bhv_vop_release(vp); |
| 336 | return -error; | 317 | return 0; |
| 337 | } | 318 | } |
| 338 | 319 | ||
| 339 | STATIC int | 320 | STATIC int |
| @@ -342,15 +323,14 @@ xfs_file_fsync( | |||
| 342 | struct dentry *dentry, | 323 | struct dentry *dentry, |
| 343 | int datasync) | 324 | int datasync) |
| 344 | { | 325 | { |
| 345 | struct inode *inode = dentry->d_inode; | 326 | bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); |
| 346 | vnode_t *vp = vn_from_inode(inode); | ||
| 347 | int error; | ||
| 348 | int flags = FSYNC_WAIT; | 327 | int flags = FSYNC_WAIT; |
| 349 | 328 | ||
| 350 | if (datasync) | 329 | if (datasync) |
| 351 | flags |= FSYNC_DATA; | 330 | flags |= FSYNC_DATA; |
| 352 | VOP_FSYNC(vp, flags, NULL, (xfs_off_t)0, (xfs_off_t)-1, error); | 331 | if (VN_TRUNC(vp)) |
| 353 | return -error; | 332 | VUNTRUNCATE(vp); |
| 333 | return -bhv_vop_fsync(vp, flags, NULL, (xfs_off_t)0, (xfs_off_t)-1); | ||
| 354 | } | 334 | } |
| 355 | 335 | ||
| 356 | #ifdef CONFIG_XFS_DMAPI | 336 | #ifdef CONFIG_XFS_DMAPI |
| @@ -361,16 +341,11 @@ xfs_vm_nopage( | |||
| 361 | int *type) | 341 | int *type) |
| 362 | { | 342 | { |
| 363 | struct inode *inode = area->vm_file->f_dentry->d_inode; | 343 | struct inode *inode = area->vm_file->f_dentry->d_inode; |
| 364 | vnode_t *vp = vn_from_inode(inode); | 344 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 365 | xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp); | ||
| 366 | int error; | ||
| 367 | 345 | ||
| 368 | ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI); | 346 | ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI); |
| 369 | 347 | if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), area, 0)) | |
| 370 | error = XFS_SEND_MMAP(mp, area, 0); | ||
| 371 | if (error) | ||
| 372 | return NULL; | 348 | return NULL; |
| 373 | |||
| 374 | return filemap_nopage(area, address, type); | 349 | return filemap_nopage(area, address, type); |
| 375 | } | 350 | } |
| 376 | #endif /* CONFIG_XFS_DMAPI */ | 351 | #endif /* CONFIG_XFS_DMAPI */ |
| @@ -382,7 +357,7 @@ xfs_file_readdir( | |||
| 382 | filldir_t filldir) | 357 | filldir_t filldir) |
| 383 | { | 358 | { |
| 384 | int error = 0; | 359 | int error = 0; |
| 385 | vnode_t *vp = vn_from_inode(filp->f_dentry->d_inode); | 360 | bhv_vnode_t *vp = vn_from_inode(filp->f_dentry->d_inode); |
| 386 | uio_t uio; | 361 | uio_t uio; |
| 387 | iovec_t iov; | 362 | iovec_t iov; |
| 388 | int eof = 0; | 363 | int eof = 0; |
| @@ -417,7 +392,7 @@ xfs_file_readdir( | |||
| 417 | 392 | ||
| 418 | start_offset = uio.uio_offset; | 393 | start_offset = uio.uio_offset; |
| 419 | 394 | ||
| 420 | VOP_READDIR(vp, &uio, NULL, &eof, error); | 395 | error = bhv_vop_readdir(vp, &uio, NULL, &eof); |
| 421 | if ((uio.uio_offset == start_offset) || error) { | 396 | if ((uio.uio_offset == start_offset) || error) { |
| 422 | size = 0; | 397 | size = 0; |
| 423 | break; | 398 | break; |
| @@ -456,38 +431,28 @@ xfs_file_mmap( | |||
| 456 | struct file *filp, | 431 | struct file *filp, |
| 457 | struct vm_area_struct *vma) | 432 | struct vm_area_struct *vma) |
| 458 | { | 433 | { |
| 459 | struct inode *ip = filp->f_dentry->d_inode; | ||
| 460 | vnode_t *vp = vn_from_inode(ip); | ||
| 461 | vattr_t vattr; | ||
| 462 | int error; | ||
| 463 | |||
| 464 | vma->vm_ops = &xfs_file_vm_ops; | 434 | vma->vm_ops = &xfs_file_vm_ops; |
| 465 | 435 | ||
| 466 | #ifdef CONFIG_XFS_DMAPI | 436 | #ifdef CONFIG_XFS_DMAPI |
| 467 | if (vp->v_vfsp->vfs_flag & VFS_DMI) { | 437 | if (vn_from_inode(filp->f_dentry->d_inode)->v_vfsp->vfs_flag & VFS_DMI) |
| 468 | vma->vm_ops = &xfs_dmapi_file_vm_ops; | 438 | vma->vm_ops = &xfs_dmapi_file_vm_ops; |
| 469 | } | ||
| 470 | #endif /* CONFIG_XFS_DMAPI */ | 439 | #endif /* CONFIG_XFS_DMAPI */ |
| 471 | 440 | ||
| 472 | vattr.va_mask = XFS_AT_UPDATIME; | 441 | file_accessed(filp); |
| 473 | VOP_SETATTR(vp, &vattr, XFS_AT_UPDATIME, NULL, error); | ||
| 474 | if (likely(!error)) | ||
| 475 | __vn_revalidate(vp, &vattr); /* update flags */ | ||
| 476 | return 0; | 442 | return 0; |
| 477 | } | 443 | } |
| 478 | 444 | ||
| 479 | |||
| 480 | STATIC long | 445 | STATIC long |
| 481 | xfs_file_ioctl( | 446 | xfs_file_ioctl( |
| 482 | struct file *filp, | 447 | struct file *filp, |
| 483 | unsigned int cmd, | 448 | unsigned int cmd, |
| 484 | unsigned long arg) | 449 | unsigned long p) |
| 485 | { | 450 | { |
| 486 | int error; | 451 | int error; |
| 487 | struct inode *inode = filp->f_dentry->d_inode; | 452 | struct inode *inode = filp->f_dentry->d_inode; |
| 488 | vnode_t *vp = vn_from_inode(inode); | 453 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 489 | 454 | ||
| 490 | VOP_IOCTL(vp, inode, filp, 0, cmd, (void __user *)arg, error); | 455 | error = bhv_vop_ioctl(vp, inode, filp, 0, cmd, (void __user *)p); |
| 491 | VMODIFY(vp); | 456 | VMODIFY(vp); |
| 492 | 457 | ||
| 493 | /* NOTE: some of the ioctl's return positive #'s as a | 458 | /* NOTE: some of the ioctl's return positive #'s as a |
| @@ -503,13 +468,13 @@ STATIC long | |||
| 503 | xfs_file_ioctl_invis( | 468 | xfs_file_ioctl_invis( |
| 504 | struct file *filp, | 469 | struct file *filp, |
| 505 | unsigned int cmd, | 470 | unsigned int cmd, |
| 506 | unsigned long arg) | 471 | unsigned long p) |
| 507 | { | 472 | { |
| 508 | struct inode *inode = filp->f_dentry->d_inode; | ||
| 509 | vnode_t *vp = vn_from_inode(inode); | ||
| 510 | int error; | 473 | int error; |
| 474 | struct inode *inode = filp->f_dentry->d_inode; | ||
| 475 | bhv_vnode_t *vp = vn_from_inode(inode); | ||
| 511 | 476 | ||
| 512 | VOP_IOCTL(vp, inode, filp, IO_INVIS, cmd, (void __user *)arg, error); | 477 | error = bhv_vop_ioctl(vp, inode, filp, IO_INVIS, cmd, (void __user *)p); |
| 513 | VMODIFY(vp); | 478 | VMODIFY(vp); |
| 514 | 479 | ||
| 515 | /* NOTE: some of the ioctl's return positive #'s as a | 480 | /* NOTE: some of the ioctl's return positive #'s as a |
| @@ -528,7 +493,7 @@ xfs_vm_mprotect( | |||
| 528 | struct vm_area_struct *vma, | 493 | struct vm_area_struct *vma, |
| 529 | unsigned int newflags) | 494 | unsigned int newflags) |
| 530 | { | 495 | { |
| 531 | vnode_t *vp = vn_from_inode(vma->vm_file->f_dentry->d_inode); | 496 | bhv_vnode_t *vp = vn_from_inode(vma->vm_file->f_dentry->d_inode); |
| 532 | int error = 0; | 497 | int error = 0; |
| 533 | 498 | ||
| 534 | if (vp->v_vfsp->vfs_flag & VFS_DMI) { | 499 | if (vp->v_vfsp->vfs_flag & VFS_DMI) { |
| @@ -554,24 +519,19 @@ STATIC int | |||
| 554 | xfs_file_open_exec( | 519 | xfs_file_open_exec( |
| 555 | struct inode *inode) | 520 | struct inode *inode) |
| 556 | { | 521 | { |
| 557 | vnode_t *vp = vn_from_inode(inode); | 522 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 558 | xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp); | ||
| 559 | int error = 0; | ||
| 560 | xfs_inode_t *ip; | ||
| 561 | 523 | ||
| 562 | if (vp->v_vfsp->vfs_flag & VFS_DMI) { | 524 | if (unlikely(vp->v_vfsp->vfs_flag & VFS_DMI)) { |
| 563 | ip = xfs_vtoi(vp); | 525 | xfs_mount_t *mp = XFS_VFSTOM(vp->v_vfsp); |
| 564 | if (!ip) { | 526 | xfs_inode_t *ip = xfs_vtoi(vp); |
| 565 | error = -EINVAL; | 527 | |
| 566 | goto open_exec_out; | 528 | if (!ip) |
| 567 | } | 529 | return -EINVAL; |
| 568 | if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ)) { | 530 | if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ)) |
| 569 | error = -XFS_SEND_DATA(mp, DM_EVENT_READ, vp, | 531 | return -XFS_SEND_DATA(mp, DM_EVENT_READ, vp, |
| 570 | 0, 0, 0, NULL); | 532 | 0, 0, 0, NULL); |
| 571 | } | ||
| 572 | } | 533 | } |
| 573 | open_exec_out: | 534 | return 0; |
| 574 | return error; | ||
| 575 | } | 535 | } |
| 576 | #endif /* HAVE_FOP_OPEN_EXEC */ | 536 | #endif /* HAVE_FOP_OPEN_EXEC */ |
| 577 | 537 | ||
| @@ -592,6 +552,7 @@ const struct file_operations xfs_file_operations = { | |||
| 592 | #endif | 552 | #endif |
| 593 | .mmap = xfs_file_mmap, | 553 | .mmap = xfs_file_mmap, |
| 594 | .open = xfs_file_open, | 554 | .open = xfs_file_open, |
| 555 | .flush = xfs_file_close, | ||
| 595 | .release = xfs_file_release, | 556 | .release = xfs_file_release, |
| 596 | .fsync = xfs_file_fsync, | 557 | .fsync = xfs_file_fsync, |
| 597 | #ifdef HAVE_FOP_OPEN_EXEC | 558 | #ifdef HAVE_FOP_OPEN_EXEC |
| @@ -616,6 +577,7 @@ const struct file_operations xfs_invis_file_operations = { | |||
| 616 | #endif | 577 | #endif |
| 617 | .mmap = xfs_file_mmap, | 578 | .mmap = xfs_file_mmap, |
| 618 | .open = xfs_file_open, | 579 | .open = xfs_file_open, |
| 580 | .flush = xfs_file_close, | ||
| 619 | .release = xfs_file_release, | 581 | .release = xfs_file_release, |
| 620 | .fsync = xfs_file_fsync, | 582 | .fsync = xfs_file_fsync, |
| 621 | }; | 583 | }; |
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/linux-2.6/xfs_fs_subr.c index 575f2a790f31..dc0562828e76 100644 --- a/fs/xfs/linux-2.6/xfs_fs_subr.c +++ b/fs/xfs/linux-2.6/xfs_fs_subr.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2002,2005-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -15,40 +15,12 @@ | |||
| 15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 17 | */ | 17 | */ |
| 18 | |||
| 19 | #include "xfs.h" | 18 | #include "xfs.h" |
| 20 | 19 | ||
| 21 | /* | 20 | int fs_noerr(void) { return 0; } |
| 22 | * Stub for no-op vnode operations that return error status. | 21 | int fs_nosys(void) { return ENOSYS; } |
| 23 | */ | 22 | void fs_noval(void) { return; } |
| 24 | int | ||
| 25 | fs_noerr(void) | ||
| 26 | { | ||
| 27 | return 0; | ||
| 28 | } | ||
| 29 | 23 | ||
| 30 | /* | ||
| 31 | * Operation unsupported under this file system. | ||
| 32 | */ | ||
| 33 | int | ||
| 34 | fs_nosys(void) | ||
| 35 | { | ||
| 36 | return ENOSYS; | ||
| 37 | } | ||
| 38 | |||
| 39 | /* | ||
| 40 | * Stub for inactive, strategy, and read/write lock/unlock. Does nothing. | ||
| 41 | */ | ||
| 42 | /* ARGSUSED */ | ||
| 43 | void | ||
| 44 | fs_noval(void) | ||
| 45 | { | ||
| 46 | } | ||
| 47 | |||
| 48 | /* | ||
| 49 | * vnode pcache layer for vnode_tosspages. | ||
| 50 | * 'last' parameter unused but left in for IRIX compatibility | ||
| 51 | */ | ||
| 52 | void | 24 | void |
| 53 | fs_tosspages( | 25 | fs_tosspages( |
| 54 | bhv_desc_t *bdp, | 26 | bhv_desc_t *bdp, |
| @@ -56,18 +28,13 @@ fs_tosspages( | |||
| 56 | xfs_off_t last, | 28 | xfs_off_t last, |
| 57 | int fiopt) | 29 | int fiopt) |
| 58 | { | 30 | { |
| 59 | vnode_t *vp = BHV_TO_VNODE(bdp); | 31 | bhv_vnode_t *vp = BHV_TO_VNODE(bdp); |
| 60 | struct inode *ip = vn_to_inode(vp); | 32 | struct inode *ip = vn_to_inode(vp); |
| 61 | 33 | ||
| 62 | if (VN_CACHED(vp)) | 34 | if (VN_CACHED(vp)) |
| 63 | truncate_inode_pages(ip->i_mapping, first); | 35 | truncate_inode_pages(ip->i_mapping, first); |
| 64 | } | 36 | } |
| 65 | 37 | ||
| 66 | |||
| 67 | /* | ||
| 68 | * vnode pcache layer for vnode_flushinval_pages. | ||
| 69 | * 'last' parameter unused but left in for IRIX compatibility | ||
| 70 | */ | ||
| 71 | void | 38 | void |
| 72 | fs_flushinval_pages( | 39 | fs_flushinval_pages( |
| 73 | bhv_desc_t *bdp, | 40 | bhv_desc_t *bdp, |
| @@ -75,20 +42,17 @@ fs_flushinval_pages( | |||
| 75 | xfs_off_t last, | 42 | xfs_off_t last, |
| 76 | int fiopt) | 43 | int fiopt) |
| 77 | { | 44 | { |
| 78 | vnode_t *vp = BHV_TO_VNODE(bdp); | 45 | bhv_vnode_t *vp = BHV_TO_VNODE(bdp); |
| 79 | struct inode *ip = vn_to_inode(vp); | 46 | struct inode *ip = vn_to_inode(vp); |
| 80 | 47 | ||
| 81 | if (VN_CACHED(vp)) { | 48 | if (VN_CACHED(vp)) { |
| 49 | if (VN_TRUNC(vp)) | ||
| 50 | VUNTRUNCATE(vp); | ||
| 82 | filemap_write_and_wait(ip->i_mapping); | 51 | filemap_write_and_wait(ip->i_mapping); |
| 83 | |||
| 84 | truncate_inode_pages(ip->i_mapping, first); | 52 | truncate_inode_pages(ip->i_mapping, first); |
| 85 | } | 53 | } |
| 86 | } | 54 | } |
| 87 | 55 | ||
| 88 | /* | ||
| 89 | * vnode pcache layer for vnode_flush_pages. | ||
| 90 | * 'last' parameter unused but left in for IRIX compatibility | ||
| 91 | */ | ||
| 92 | int | 56 | int |
| 93 | fs_flush_pages( | 57 | fs_flush_pages( |
| 94 | bhv_desc_t *bdp, | 58 | bhv_desc_t *bdp, |
| @@ -97,15 +61,16 @@ fs_flush_pages( | |||
| 97 | uint64_t flags, | 61 | uint64_t flags, |
| 98 | int fiopt) | 62 | int fiopt) |
| 99 | { | 63 | { |
| 100 | vnode_t *vp = BHV_TO_VNODE(bdp); | 64 | bhv_vnode_t *vp = BHV_TO_VNODE(bdp); |
| 101 | struct inode *ip = vn_to_inode(vp); | 65 | struct inode *ip = vn_to_inode(vp); |
| 102 | 66 | ||
| 103 | if (VN_CACHED(vp)) { | 67 | if (VN_DIRTY(vp)) { |
| 68 | if (VN_TRUNC(vp)) | ||
| 69 | VUNTRUNCATE(vp); | ||
| 104 | filemap_fdatawrite(ip->i_mapping); | 70 | filemap_fdatawrite(ip->i_mapping); |
| 105 | if (flags & XFS_B_ASYNC) | 71 | if (flags & XFS_B_ASYNC) |
| 106 | return 0; | 72 | return 0; |
| 107 | filemap_fdatawait(ip->i_mapping); | 73 | filemap_fdatawait(ip->i_mapping); |
| 108 | } | 74 | } |
| 109 | |||
| 110 | return 0; | 75 | return 0; |
| 111 | } | 76 | } |
diff --git a/fs/xfs/linux-2.6/xfs_globals.c b/fs/xfs/linux-2.6/xfs_globals.c index 6e8085f34635..6c162c3dde7e 100644 --- a/fs/xfs/linux-2.6/xfs_globals.c +++ b/fs/xfs/linux-2.6/xfs_globals.c | |||
| @@ -45,6 +45,7 @@ xfs_param_t xfs_params = { | |||
| 45 | .xfs_buf_age = { 1*100, 15*100, 7200*100}, | 45 | .xfs_buf_age = { 1*100, 15*100, 7200*100}, |
| 46 | .inherit_nosym = { 0, 0, 1 }, | 46 | .inherit_nosym = { 0, 0, 1 }, |
| 47 | .rotorstep = { 1, 1, 255 }, | 47 | .rotorstep = { 1, 1, 255 }, |
| 48 | .inherit_nodfrg = { 0, 1, 1 }, | ||
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | /* | 51 | /* |
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 84478491609b..6e52a5dd38d8 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_alloc.h" | 27 | #include "xfs_alloc.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| @@ -31,7 +30,6 @@ | |||
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_attr_sf.h" | 33 | #include "xfs_attr_sf.h" |
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -78,7 +76,7 @@ xfs_find_handle( | |||
| 78 | xfs_handle_t handle; | 76 | xfs_handle_t handle; |
| 79 | xfs_fsop_handlereq_t hreq; | 77 | xfs_fsop_handlereq_t hreq; |
| 80 | struct inode *inode; | 78 | struct inode *inode; |
| 81 | struct vnode *vp; | 79 | bhv_vnode_t *vp; |
| 82 | 80 | ||
| 83 | if (copy_from_user(&hreq, arg, sizeof(hreq))) | 81 | if (copy_from_user(&hreq, arg, sizeof(hreq))) |
| 84 | return -XFS_ERROR(EFAULT); | 82 | return -XFS_ERROR(EFAULT); |
| @@ -192,7 +190,7 @@ xfs_vget_fsop_handlereq( | |||
| 192 | xfs_mount_t *mp, | 190 | xfs_mount_t *mp, |
| 193 | struct inode *parinode, /* parent inode pointer */ | 191 | struct inode *parinode, /* parent inode pointer */ |
| 194 | xfs_fsop_handlereq_t *hreq, | 192 | xfs_fsop_handlereq_t *hreq, |
| 195 | vnode_t **vp, | 193 | bhv_vnode_t **vp, |
| 196 | struct inode **inode) | 194 | struct inode **inode) |
| 197 | { | 195 | { |
| 198 | void __user *hanp; | 196 | void __user *hanp; |
| @@ -202,7 +200,7 @@ xfs_vget_fsop_handlereq( | |||
| 202 | xfs_handle_t handle; | 200 | xfs_handle_t handle; |
| 203 | xfs_inode_t *ip; | 201 | xfs_inode_t *ip; |
| 204 | struct inode *inodep; | 202 | struct inode *inodep; |
| 205 | vnode_t *vpp; | 203 | bhv_vnode_t *vpp; |
| 206 | xfs_ino_t ino; | 204 | xfs_ino_t ino; |
| 207 | __u32 igen; | 205 | __u32 igen; |
| 208 | int error; | 206 | int error; |
| @@ -277,7 +275,7 @@ xfs_open_by_handle( | |||
| 277 | struct file *filp; | 275 | struct file *filp; |
| 278 | struct inode *inode; | 276 | struct inode *inode; |
| 279 | struct dentry *dentry; | 277 | struct dentry *dentry; |
| 280 | vnode_t *vp; | 278 | bhv_vnode_t *vp; |
| 281 | xfs_fsop_handlereq_t hreq; | 279 | xfs_fsop_handlereq_t hreq; |
| 282 | 280 | ||
| 283 | if (!capable(CAP_SYS_ADMIN)) | 281 | if (!capable(CAP_SYS_ADMIN)) |
| @@ -362,7 +360,7 @@ xfs_readlink_by_handle( | |||
| 362 | struct uio auio; | 360 | struct uio auio; |
| 363 | struct inode *inode; | 361 | struct inode *inode; |
| 364 | xfs_fsop_handlereq_t hreq; | 362 | xfs_fsop_handlereq_t hreq; |
| 365 | vnode_t *vp; | 363 | bhv_vnode_t *vp; |
| 366 | __u32 olen; | 364 | __u32 olen; |
| 367 | 365 | ||
| 368 | if (!capable(CAP_SYS_ADMIN)) | 366 | if (!capable(CAP_SYS_ADMIN)) |
| @@ -393,9 +391,11 @@ xfs_readlink_by_handle( | |||
| 393 | auio.uio_segflg = UIO_USERSPACE; | 391 | auio.uio_segflg = UIO_USERSPACE; |
| 394 | auio.uio_resid = olen; | 392 | auio.uio_resid = olen; |
| 395 | 393 | ||
| 396 | VOP_READLINK(vp, &auio, IO_INVIS, NULL, error); | 394 | error = bhv_vop_readlink(vp, &auio, IO_INVIS, NULL); |
| 397 | |||
| 398 | VN_RELE(vp); | 395 | VN_RELE(vp); |
| 396 | if (error) | ||
| 397 | return -error; | ||
| 398 | |||
| 399 | return (olen - auio.uio_resid); | 399 | return (olen - auio.uio_resid); |
| 400 | } | 400 | } |
| 401 | 401 | ||
| @@ -411,7 +411,7 @@ xfs_fssetdm_by_handle( | |||
| 411 | xfs_fsop_setdm_handlereq_t dmhreq; | 411 | xfs_fsop_setdm_handlereq_t dmhreq; |
| 412 | struct inode *inode; | 412 | struct inode *inode; |
| 413 | bhv_desc_t *bdp; | 413 | bhv_desc_t *bdp; |
| 414 | vnode_t *vp; | 414 | bhv_vnode_t *vp; |
| 415 | 415 | ||
| 416 | if (!capable(CAP_MKNOD)) | 416 | if (!capable(CAP_MKNOD)) |
| 417 | return -XFS_ERROR(EPERM); | 417 | return -XFS_ERROR(EPERM); |
| @@ -452,7 +452,7 @@ xfs_attrlist_by_handle( | |||
| 452 | attrlist_cursor_kern_t *cursor; | 452 | attrlist_cursor_kern_t *cursor; |
| 453 | xfs_fsop_attrlist_handlereq_t al_hreq; | 453 | xfs_fsop_attrlist_handlereq_t al_hreq; |
| 454 | struct inode *inode; | 454 | struct inode *inode; |
| 455 | vnode_t *vp; | 455 | bhv_vnode_t *vp; |
| 456 | char *kbuf; | 456 | char *kbuf; |
| 457 | 457 | ||
| 458 | if (!capable(CAP_SYS_ADMIN)) | 458 | if (!capable(CAP_SYS_ADMIN)) |
| @@ -472,8 +472,8 @@ xfs_attrlist_by_handle( | |||
| 472 | goto out_vn_rele; | 472 | goto out_vn_rele; |
| 473 | 473 | ||
| 474 | cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; | 474 | cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; |
| 475 | VOP_ATTR_LIST(vp, kbuf, al_hreq.buflen, al_hreq.flags, | 475 | error = bhv_vop_attr_list(vp, kbuf, al_hreq.buflen, al_hreq.flags, |
| 476 | cursor, NULL, error); | 476 | cursor, NULL); |
| 477 | if (error) | 477 | if (error) |
| 478 | goto out_kfree; | 478 | goto out_kfree; |
| 479 | 479 | ||
| @@ -490,7 +490,7 @@ xfs_attrlist_by_handle( | |||
| 490 | 490 | ||
| 491 | STATIC int | 491 | STATIC int |
| 492 | xfs_attrmulti_attr_get( | 492 | xfs_attrmulti_attr_get( |
| 493 | struct vnode *vp, | 493 | bhv_vnode_t *vp, |
| 494 | char *name, | 494 | char *name, |
| 495 | char __user *ubuf, | 495 | char __user *ubuf, |
| 496 | __uint32_t *len, | 496 | __uint32_t *len, |
| @@ -505,7 +505,7 @@ xfs_attrmulti_attr_get( | |||
| 505 | if (!kbuf) | 505 | if (!kbuf) |
| 506 | return ENOMEM; | 506 | return ENOMEM; |
| 507 | 507 | ||
| 508 | VOP_ATTR_GET(vp, name, kbuf, len, flags, NULL, error); | 508 | error = bhv_vop_attr_get(vp, name, kbuf, len, flags, NULL); |
| 509 | if (error) | 509 | if (error) |
| 510 | goto out_kfree; | 510 | goto out_kfree; |
| 511 | 511 | ||
| @@ -519,7 +519,7 @@ xfs_attrmulti_attr_get( | |||
| 519 | 519 | ||
| 520 | STATIC int | 520 | STATIC int |
| 521 | xfs_attrmulti_attr_set( | 521 | xfs_attrmulti_attr_set( |
| 522 | struct vnode *vp, | 522 | bhv_vnode_t *vp, |
| 523 | char *name, | 523 | char *name, |
| 524 | const char __user *ubuf, | 524 | const char __user *ubuf, |
| 525 | __uint32_t len, | 525 | __uint32_t len, |
| @@ -542,7 +542,7 @@ xfs_attrmulti_attr_set( | |||
| 542 | if (copy_from_user(kbuf, ubuf, len)) | 542 | if (copy_from_user(kbuf, ubuf, len)) |
| 543 | goto out_kfree; | 543 | goto out_kfree; |
| 544 | 544 | ||
| 545 | VOP_ATTR_SET(vp, name, kbuf, len, flags, NULL, error); | 545 | error = bhv_vop_attr_set(vp, name, kbuf, len, flags, NULL); |
| 546 | 546 | ||
| 547 | out_kfree: | 547 | out_kfree: |
| 548 | kfree(kbuf); | 548 | kfree(kbuf); |
| @@ -551,20 +551,15 @@ xfs_attrmulti_attr_set( | |||
| 551 | 551 | ||
| 552 | STATIC int | 552 | STATIC int |
| 553 | xfs_attrmulti_attr_remove( | 553 | xfs_attrmulti_attr_remove( |
| 554 | struct vnode *vp, | 554 | bhv_vnode_t *vp, |
| 555 | char *name, | 555 | char *name, |
| 556 | __uint32_t flags) | 556 | __uint32_t flags) |
| 557 | { | 557 | { |
| 558 | int error; | ||
| 559 | |||
| 560 | |||
| 561 | if (IS_RDONLY(&vp->v_inode)) | 558 | if (IS_RDONLY(&vp->v_inode)) |
| 562 | return -EROFS; | 559 | return -EROFS; |
| 563 | if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode)) | 560 | if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode)) |
| 564 | return EPERM; | 561 | return EPERM; |
| 565 | 562 | return bhv_vop_attr_remove(vp, name, flags, NULL); | |
| 566 | VOP_ATTR_REMOVE(vp, name, flags, NULL, error); | ||
| 567 | return error; | ||
| 568 | } | 563 | } |
| 569 | 564 | ||
| 570 | STATIC int | 565 | STATIC int |
| @@ -578,7 +573,7 @@ xfs_attrmulti_by_handle( | |||
| 578 | xfs_attr_multiop_t *ops; | 573 | xfs_attr_multiop_t *ops; |
| 579 | xfs_fsop_attrmulti_handlereq_t am_hreq; | 574 | xfs_fsop_attrmulti_handlereq_t am_hreq; |
| 580 | struct inode *inode; | 575 | struct inode *inode; |
| 581 | vnode_t *vp; | 576 | bhv_vnode_t *vp; |
| 582 | unsigned int i, size; | 577 | unsigned int i, size; |
| 583 | char *attr_name; | 578 | char *attr_name; |
| 584 | 579 | ||
| @@ -658,7 +653,7 @@ xfs_attrmulti_by_handle( | |||
| 658 | STATIC int | 653 | STATIC int |
| 659 | xfs_ioc_space( | 654 | xfs_ioc_space( |
| 660 | bhv_desc_t *bdp, | 655 | bhv_desc_t *bdp, |
| 661 | vnode_t *vp, | 656 | bhv_vnode_t *vp, |
| 662 | struct file *filp, | 657 | struct file *filp, |
| 663 | int flags, | 658 | int flags, |
| 664 | unsigned int cmd, | 659 | unsigned int cmd, |
| @@ -682,7 +677,7 @@ xfs_ioc_fsgeometry( | |||
| 682 | 677 | ||
| 683 | STATIC int | 678 | STATIC int |
| 684 | xfs_ioc_xattr( | 679 | xfs_ioc_xattr( |
| 685 | vnode_t *vp, | 680 | bhv_vnode_t *vp, |
| 686 | xfs_inode_t *ip, | 681 | xfs_inode_t *ip, |
| 687 | struct file *filp, | 682 | struct file *filp, |
| 688 | unsigned int cmd, | 683 | unsigned int cmd, |
| @@ -711,7 +706,7 @@ xfs_ioctl( | |||
| 711 | void __user *arg) | 706 | void __user *arg) |
| 712 | { | 707 | { |
| 713 | int error; | 708 | int error; |
| 714 | vnode_t *vp; | 709 | bhv_vnode_t *vp; |
| 715 | xfs_inode_t *ip; | 710 | xfs_inode_t *ip; |
| 716 | xfs_mount_t *mp; | 711 | xfs_mount_t *mp; |
| 717 | 712 | ||
| @@ -962,7 +957,7 @@ xfs_ioctl( | |||
| 962 | STATIC int | 957 | STATIC int |
| 963 | xfs_ioc_space( | 958 | xfs_ioc_space( |
| 964 | bhv_desc_t *bdp, | 959 | bhv_desc_t *bdp, |
| 965 | vnode_t *vp, | 960 | bhv_vnode_t *vp, |
| 966 | struct file *filp, | 961 | struct file *filp, |
| 967 | int ioflags, | 962 | int ioflags, |
| 968 | unsigned int cmd, | 963 | unsigned int cmd, |
| @@ -1153,14 +1148,14 @@ xfs_di2lxflags( | |||
| 1153 | 1148 | ||
| 1154 | STATIC int | 1149 | STATIC int |
| 1155 | xfs_ioc_xattr( | 1150 | xfs_ioc_xattr( |
| 1156 | vnode_t *vp, | 1151 | bhv_vnode_t *vp, |
| 1157 | xfs_inode_t *ip, | 1152 | xfs_inode_t *ip, |
| 1158 | struct file *filp, | 1153 | struct file *filp, |
| 1159 | unsigned int cmd, | 1154 | unsigned int cmd, |
| 1160 | void __user *arg) | 1155 | void __user *arg) |
| 1161 | { | 1156 | { |
| 1162 | struct fsxattr fa; | 1157 | struct fsxattr fa; |
| 1163 | struct vattr *vattr; | 1158 | struct bhv_vattr *vattr; |
| 1164 | int error = 0; | 1159 | int error = 0; |
| 1165 | int attr_flags; | 1160 | int attr_flags; |
| 1166 | unsigned int flags; | 1161 | unsigned int flags; |
| @@ -1173,7 +1168,7 @@ xfs_ioc_xattr( | |||
| 1173 | case XFS_IOC_FSGETXATTR: { | 1168 | case XFS_IOC_FSGETXATTR: { |
| 1174 | vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ | 1169 | vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ |
| 1175 | XFS_AT_NEXTENTS | XFS_AT_PROJID; | 1170 | XFS_AT_NEXTENTS | XFS_AT_PROJID; |
| 1176 | VOP_GETATTR(vp, vattr, 0, NULL, error); | 1171 | error = bhv_vop_getattr(vp, vattr, 0, NULL); |
| 1177 | if (unlikely(error)) { | 1172 | if (unlikely(error)) { |
| 1178 | error = -error; | 1173 | error = -error; |
| 1179 | break; | 1174 | break; |
| @@ -1206,7 +1201,7 @@ xfs_ioc_xattr( | |||
| 1206 | vattr->va_extsize = fa.fsx_extsize; | 1201 | vattr->va_extsize = fa.fsx_extsize; |
| 1207 | vattr->va_projid = fa.fsx_projid; | 1202 | vattr->va_projid = fa.fsx_projid; |
| 1208 | 1203 | ||
| 1209 | VOP_SETATTR(vp, vattr, attr_flags, NULL, error); | 1204 | error = bhv_vop_setattr(vp, vattr, attr_flags, NULL); |
| 1210 | if (likely(!error)) | 1205 | if (likely(!error)) |
| 1211 | __vn_revalidate(vp, vattr); /* update flags */ | 1206 | __vn_revalidate(vp, vattr); /* update flags */ |
| 1212 | error = -error; | 1207 | error = -error; |
| @@ -1216,7 +1211,7 @@ xfs_ioc_xattr( | |||
| 1216 | case XFS_IOC_FSGETXATTRA: { | 1211 | case XFS_IOC_FSGETXATTRA: { |
| 1217 | vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ | 1212 | vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ |
| 1218 | XFS_AT_ANEXTENTS | XFS_AT_PROJID; | 1213 | XFS_AT_ANEXTENTS | XFS_AT_PROJID; |
| 1219 | VOP_GETATTR(vp, vattr, 0, NULL, error); | 1214 | error = bhv_vop_getattr(vp, vattr, 0, NULL); |
| 1220 | if (unlikely(error)) { | 1215 | if (unlikely(error)) { |
| 1221 | error = -error; | 1216 | error = -error; |
| 1222 | break; | 1217 | break; |
| @@ -1262,7 +1257,7 @@ xfs_ioc_xattr( | |||
| 1262 | vattr->va_xflags = xfs_merge_ioc_xflags(flags, | 1257 | vattr->va_xflags = xfs_merge_ioc_xflags(flags, |
| 1263 | xfs_ip2xflags(ip)); | 1258 | xfs_ip2xflags(ip)); |
| 1264 | 1259 | ||
| 1265 | VOP_SETATTR(vp, vattr, attr_flags, NULL, error); | 1260 | error = bhv_vop_setattr(vp, vattr, attr_flags, NULL); |
| 1266 | if (likely(!error)) | 1261 | if (likely(!error)) |
| 1267 | __vn_revalidate(vp, vattr); /* update flags */ | 1262 | __vn_revalidate(vp, vattr); /* update flags */ |
| 1268 | error = -error; | 1263 | error = -error; |
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 251bfe451a3f..601f01c92f7f 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c | |||
| @@ -114,7 +114,7 @@ xfs_compat_ioctl( | |||
| 114 | unsigned long arg) | 114 | unsigned long arg) |
| 115 | { | 115 | { |
| 116 | struct inode *inode = file->f_dentry->d_inode; | 116 | struct inode *inode = file->f_dentry->d_inode; |
| 117 | vnode_t *vp = vn_from_inode(inode); | 117 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 118 | int error; | 118 | int error; |
| 119 | 119 | ||
| 120 | switch (cmd) { | 120 | switch (cmd) { |
| @@ -193,7 +193,7 @@ xfs_compat_ioctl( | |||
| 193 | return -ENOIOCTLCMD; | 193 | return -ENOIOCTLCMD; |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | VOP_IOCTL(vp, inode, file, mode, cmd, (void __user *)arg, error); | 196 | error = bhv_vop_ioctl(vp, inode, file, mode, cmd, (void __user *)arg); |
| 197 | VMODIFY(vp); | 197 | VMODIFY(vp); |
| 198 | 198 | ||
| 199 | return error; | 199 | return error; |
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 2e2e275c786f..12810baeb5d4 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_alloc.h" | 27 | #include "xfs_alloc.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| @@ -61,7 +59,7 @@ | |||
| 61 | */ | 59 | */ |
| 62 | xfs_inode_t * | 60 | xfs_inode_t * |
| 63 | xfs_vtoi( | 61 | xfs_vtoi( |
| 64 | struct vnode *vp) | 62 | bhv_vnode_t *vp) |
| 65 | { | 63 | { |
| 66 | bhv_desc_t *bdp; | 64 | bhv_desc_t *bdp; |
| 67 | 65 | ||
| @@ -80,7 +78,7 @@ void | |||
| 80 | xfs_synchronize_atime( | 78 | xfs_synchronize_atime( |
| 81 | xfs_inode_t *ip) | 79 | xfs_inode_t *ip) |
| 82 | { | 80 | { |
| 83 | vnode_t *vp; | 81 | bhv_vnode_t *vp; |
| 84 | 82 | ||
| 85 | vp = XFS_ITOV_NULL(ip); | 83 | vp = XFS_ITOV_NULL(ip); |
| 86 | if (vp) { | 84 | if (vp) { |
| @@ -200,14 +198,10 @@ xfs_ichgtime_fast( | |||
| 200 | STATIC void | 198 | STATIC void |
| 201 | xfs_validate_fields( | 199 | xfs_validate_fields( |
| 202 | struct inode *ip, | 200 | struct inode *ip, |
| 203 | struct vattr *vattr) | 201 | bhv_vattr_t *vattr) |
| 204 | { | 202 | { |
| 205 | vnode_t *vp = vn_from_inode(ip); | ||
| 206 | int error; | ||
| 207 | |||
| 208 | vattr->va_mask = XFS_AT_NLINK|XFS_AT_SIZE|XFS_AT_NBLOCKS; | 203 | vattr->va_mask = XFS_AT_NLINK|XFS_AT_SIZE|XFS_AT_NBLOCKS; |
| 209 | VOP_GETATTR(vp, vattr, ATTR_LAZY, NULL, error); | 204 | if (!bhv_vop_getattr(vn_from_inode(ip), vattr, ATTR_LAZY, NULL)) { |
| 210 | if (likely(!error)) { | ||
| 211 | ip->i_nlink = vattr->va_nlink; | 205 | ip->i_nlink = vattr->va_nlink; |
| 212 | ip->i_blocks = vattr->va_nblocks; | 206 | ip->i_blocks = vattr->va_nblocks; |
| 213 | 207 | ||
| @@ -225,7 +219,7 @@ xfs_validate_fields( | |||
| 225 | */ | 219 | */ |
| 226 | STATIC int | 220 | STATIC int |
| 227 | xfs_init_security( | 221 | xfs_init_security( |
| 228 | struct vnode *vp, | 222 | bhv_vnode_t *vp, |
| 229 | struct inode *dir) | 223 | struct inode *dir) |
| 230 | { | 224 | { |
| 231 | struct inode *ip = vn_to_inode(vp); | 225 | struct inode *ip = vn_to_inode(vp); |
| @@ -241,7 +235,7 @@ xfs_init_security( | |||
| 241 | return -error; | 235 | return -error; |
| 242 | } | 236 | } |
| 243 | 237 | ||
| 244 | VOP_ATTR_SET(vp, name, value, length, ATTR_SECURE, NULL, error); | 238 | error = bhv_vop_attr_set(vp, name, value, length, ATTR_SECURE, NULL); |
| 245 | if (!error) | 239 | if (!error) |
| 246 | VMODIFY(vp); | 240 | VMODIFY(vp); |
| 247 | 241 | ||
| @@ -264,13 +258,12 @@ xfs_has_fs_struct(struct task_struct *task) | |||
| 264 | 258 | ||
| 265 | STATIC inline void | 259 | STATIC inline void |
| 266 | xfs_cleanup_inode( | 260 | xfs_cleanup_inode( |
| 267 | vnode_t *dvp, | 261 | bhv_vnode_t *dvp, |
| 268 | vnode_t *vp, | 262 | bhv_vnode_t *vp, |
| 269 | struct dentry *dentry, | 263 | struct dentry *dentry, |
| 270 | int mode) | 264 | int mode) |
| 271 | { | 265 | { |
| 272 | struct dentry teardown = {}; | 266 | struct dentry teardown = {}; |
| 273 | int error; | ||
| 274 | 267 | ||
| 275 | /* Oh, the horror. | 268 | /* Oh, the horror. |
| 276 | * If we can't add the ACL or we fail in | 269 | * If we can't add the ACL or we fail in |
| @@ -281,9 +274,9 @@ xfs_cleanup_inode( | |||
| 281 | teardown.d_name = dentry->d_name; | 274 | teardown.d_name = dentry->d_name; |
| 282 | 275 | ||
| 283 | if (S_ISDIR(mode)) | 276 | if (S_ISDIR(mode)) |
| 284 | VOP_RMDIR(dvp, &teardown, NULL, error); | 277 | bhv_vop_rmdir(dvp, &teardown, NULL); |
| 285 | else | 278 | else |
| 286 | VOP_REMOVE(dvp, &teardown, NULL, error); | 279 | bhv_vop_remove(dvp, &teardown, NULL); |
| 287 | VN_RELE(vp); | 280 | VN_RELE(vp); |
| 288 | } | 281 | } |
| 289 | 282 | ||
| @@ -295,8 +288,8 @@ xfs_vn_mknod( | |||
| 295 | dev_t rdev) | 288 | dev_t rdev) |
| 296 | { | 289 | { |
| 297 | struct inode *ip; | 290 | struct inode *ip; |
| 298 | vattr_t vattr = { 0 }; | 291 | bhv_vattr_t vattr = { 0 }; |
| 299 | vnode_t *vp = NULL, *dvp = vn_from_inode(dir); | 292 | bhv_vnode_t *vp = NULL, *dvp = vn_from_inode(dir); |
| 300 | xfs_acl_t *default_acl = NULL; | 293 | xfs_acl_t *default_acl = NULL; |
| 301 | attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS; | 294 | attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS; |
| 302 | int error; | 295 | int error; |
| @@ -330,10 +323,10 @@ xfs_vn_mknod( | |||
| 330 | vattr.va_mask |= XFS_AT_RDEV; | 323 | vattr.va_mask |= XFS_AT_RDEV; |
| 331 | /*FALLTHROUGH*/ | 324 | /*FALLTHROUGH*/ |
| 332 | case S_IFREG: | 325 | case S_IFREG: |
| 333 | VOP_CREATE(dvp, dentry, &vattr, &vp, NULL, error); | 326 | error = bhv_vop_create(dvp, dentry, &vattr, &vp, NULL); |
| 334 | break; | 327 | break; |
| 335 | case S_IFDIR: | 328 | case S_IFDIR: |
| 336 | VOP_MKDIR(dvp, dentry, &vattr, &vp, NULL, error); | 329 | error = bhv_vop_mkdir(dvp, dentry, &vattr, &vp, NULL); |
| 337 | break; | 330 | break; |
| 338 | default: | 331 | default: |
| 339 | error = EINVAL; | 332 | error = EINVAL; |
| @@ -396,14 +389,14 @@ xfs_vn_lookup( | |||
| 396 | struct dentry *dentry, | 389 | struct dentry *dentry, |
| 397 | struct nameidata *nd) | 390 | struct nameidata *nd) |
| 398 | { | 391 | { |
| 399 | struct vnode *vp = vn_from_inode(dir), *cvp; | 392 | bhv_vnode_t *vp = vn_from_inode(dir), *cvp; |
| 400 | int error; | 393 | int error; |
| 401 | 394 | ||
| 402 | if (dentry->d_name.len >= MAXNAMELEN) | 395 | if (dentry->d_name.len >= MAXNAMELEN) |
| 403 | return ERR_PTR(-ENAMETOOLONG); | 396 | return ERR_PTR(-ENAMETOOLONG); |
| 404 | 397 | ||
| 405 | VOP_LOOKUP(vp, dentry, &cvp, 0, NULL, NULL, error); | 398 | error = bhv_vop_lookup(vp, dentry, &cvp, 0, NULL, NULL); |
| 406 | if (error) { | 399 | if (unlikely(error)) { |
| 407 | if (unlikely(error != ENOENT)) | 400 | if (unlikely(error != ENOENT)) |
| 408 | return ERR_PTR(-error); | 401 | return ERR_PTR(-error); |
| 409 | d_add(dentry, NULL); | 402 | d_add(dentry, NULL); |
| @@ -420,9 +413,9 @@ xfs_vn_link( | |||
| 420 | struct dentry *dentry) | 413 | struct dentry *dentry) |
| 421 | { | 414 | { |
| 422 | struct inode *ip; /* inode of guy being linked to */ | 415 | struct inode *ip; /* inode of guy being linked to */ |
| 423 | vnode_t *tdvp; /* target directory for new name/link */ | 416 | bhv_vnode_t *tdvp; /* target directory for new name/link */ |
| 424 | vnode_t *vp; /* vp of name being linked */ | 417 | bhv_vnode_t *vp; /* vp of name being linked */ |
| 425 | vattr_t vattr; | 418 | bhv_vattr_t vattr; |
| 426 | int error; | 419 | int error; |
| 427 | 420 | ||
| 428 | ip = old_dentry->d_inode; /* inode being linked to */ | 421 | ip = old_dentry->d_inode; /* inode being linked to */ |
| @@ -432,7 +425,7 @@ xfs_vn_link( | |||
| 432 | tdvp = vn_from_inode(dir); | 425 | tdvp = vn_from_inode(dir); |
| 433 | vp = vn_from_inode(ip); | 426 | vp = vn_from_inode(ip); |
| 434 | 427 | ||
| 435 | VOP_LINK(tdvp, vp, dentry, NULL, error); | 428 | error = bhv_vop_link(tdvp, vp, dentry, NULL); |
| 436 | if (likely(!error)) { | 429 | if (likely(!error)) { |
| 437 | VMODIFY(tdvp); | 430 | VMODIFY(tdvp); |
| 438 | VN_HOLD(vp); | 431 | VN_HOLD(vp); |
| @@ -448,14 +441,14 @@ xfs_vn_unlink( | |||
| 448 | struct dentry *dentry) | 441 | struct dentry *dentry) |
| 449 | { | 442 | { |
| 450 | struct inode *inode; | 443 | struct inode *inode; |
| 451 | vnode_t *dvp; /* directory containing name to remove */ | 444 | bhv_vnode_t *dvp; /* directory containing name to remove */ |
| 452 | vattr_t vattr; | 445 | bhv_vattr_t vattr; |
| 453 | int error; | 446 | int error; |
| 454 | 447 | ||
| 455 | inode = dentry->d_inode; | 448 | inode = dentry->d_inode; |
| 456 | dvp = vn_from_inode(dir); | 449 | dvp = vn_from_inode(dir); |
| 457 | 450 | ||
| 458 | VOP_REMOVE(dvp, dentry, NULL, error); | 451 | error = bhv_vop_remove(dvp, dentry, NULL); |
| 459 | if (likely(!error)) { | 452 | if (likely(!error)) { |
| 460 | xfs_validate_fields(dir, &vattr); /* size needs update */ | 453 | xfs_validate_fields(dir, &vattr); /* size needs update */ |
| 461 | xfs_validate_fields(inode, &vattr); | 454 | xfs_validate_fields(inode, &vattr); |
| @@ -470,27 +463,26 @@ xfs_vn_symlink( | |||
| 470 | const char *symname) | 463 | const char *symname) |
| 471 | { | 464 | { |
| 472 | struct inode *ip; | 465 | struct inode *ip; |
| 473 | vattr_t vattr = { 0 }; | 466 | bhv_vattr_t va = { 0 }; |
| 474 | vnode_t *dvp; /* directory containing name of symlink */ | 467 | bhv_vnode_t *dvp; /* directory containing name of symlink */ |
| 475 | vnode_t *cvp; /* used to lookup symlink to put in dentry */ | 468 | bhv_vnode_t *cvp; /* used to lookup symlink to put in dentry */ |
| 476 | int error; | 469 | int error; |
| 477 | 470 | ||
| 478 | dvp = vn_from_inode(dir); | 471 | dvp = vn_from_inode(dir); |
| 479 | cvp = NULL; | 472 | cvp = NULL; |
| 480 | 473 | ||
| 481 | vattr.va_mode = S_IFLNK | | 474 | va.va_mode = S_IFLNK | |
| 482 | (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO); | 475 | (irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO); |
| 483 | vattr.va_mask = XFS_AT_TYPE|XFS_AT_MODE; | 476 | va.va_mask = XFS_AT_TYPE|XFS_AT_MODE; |
| 484 | 477 | ||
| 485 | error = 0; | 478 | error = bhv_vop_symlink(dvp, dentry, &va, (char *)symname, &cvp, NULL); |
| 486 | VOP_SYMLINK(dvp, dentry, &vattr, (char *)symname, &cvp, NULL, error); | ||
| 487 | if (likely(!error && cvp)) { | 479 | if (likely(!error && cvp)) { |
| 488 | error = xfs_init_security(cvp, dir); | 480 | error = xfs_init_security(cvp, dir); |
| 489 | if (likely(!error)) { | 481 | if (likely(!error)) { |
| 490 | ip = vn_to_inode(cvp); | 482 | ip = vn_to_inode(cvp); |
| 491 | d_instantiate(dentry, ip); | 483 | d_instantiate(dentry, ip); |
| 492 | xfs_validate_fields(dir, &vattr); | 484 | xfs_validate_fields(dir, &va); |
| 493 | xfs_validate_fields(ip, &vattr); | 485 | xfs_validate_fields(ip, &va); |
| 494 | } else { | 486 | } else { |
| 495 | xfs_cleanup_inode(dvp, cvp, dentry, 0); | 487 | xfs_cleanup_inode(dvp, cvp, dentry, 0); |
| 496 | } | 488 | } |
| @@ -504,11 +496,11 @@ xfs_vn_rmdir( | |||
| 504 | struct dentry *dentry) | 496 | struct dentry *dentry) |
| 505 | { | 497 | { |
| 506 | struct inode *inode = dentry->d_inode; | 498 | struct inode *inode = dentry->d_inode; |
| 507 | vnode_t *dvp = vn_from_inode(dir); | 499 | bhv_vnode_t *dvp = vn_from_inode(dir); |
| 508 | vattr_t vattr; | 500 | bhv_vattr_t vattr; |
| 509 | int error; | 501 | int error; |
| 510 | 502 | ||
| 511 | VOP_RMDIR(dvp, dentry, NULL, error); | 503 | error = bhv_vop_rmdir(dvp, dentry, NULL); |
| 512 | if (likely(!error)) { | 504 | if (likely(!error)) { |
| 513 | xfs_validate_fields(inode, &vattr); | 505 | xfs_validate_fields(inode, &vattr); |
| 514 | xfs_validate_fields(dir, &vattr); | 506 | xfs_validate_fields(dir, &vattr); |
| @@ -524,15 +516,15 @@ xfs_vn_rename( | |||
| 524 | struct dentry *ndentry) | 516 | struct dentry *ndentry) |
| 525 | { | 517 | { |
| 526 | struct inode *new_inode = ndentry->d_inode; | 518 | struct inode *new_inode = ndentry->d_inode; |
| 527 | vnode_t *fvp; /* from directory */ | 519 | bhv_vnode_t *fvp; /* from directory */ |
| 528 | vnode_t *tvp; /* target directory */ | 520 | bhv_vnode_t *tvp; /* target directory */ |
| 529 | vattr_t vattr; | 521 | bhv_vattr_t vattr; |
| 530 | int error; | 522 | int error; |
| 531 | 523 | ||
| 532 | fvp = vn_from_inode(odir); | 524 | fvp = vn_from_inode(odir); |
| 533 | tvp = vn_from_inode(ndir); | 525 | tvp = vn_from_inode(ndir); |
| 534 | 526 | ||
| 535 | VOP_RENAME(fvp, odentry, tvp, ndentry, NULL, error); | 527 | error = bhv_vop_rename(fvp, odentry, tvp, ndentry, NULL); |
| 536 | if (likely(!error)) { | 528 | if (likely(!error)) { |
| 537 | if (new_inode) | 529 | if (new_inode) |
| 538 | xfs_validate_fields(new_inode, &vattr); | 530 | xfs_validate_fields(new_inode, &vattr); |
| @@ -553,7 +545,7 @@ xfs_vn_follow_link( | |||
| 553 | struct dentry *dentry, | 545 | struct dentry *dentry, |
| 554 | struct nameidata *nd) | 546 | struct nameidata *nd) |
| 555 | { | 547 | { |
| 556 | vnode_t *vp; | 548 | bhv_vnode_t *vp; |
| 557 | uio_t *uio; | 549 | uio_t *uio; |
| 558 | iovec_t iov; | 550 | iovec_t iov; |
| 559 | int error; | 551 | int error; |
| @@ -586,8 +578,8 @@ xfs_vn_follow_link( | |||
| 586 | uio->uio_resid = MAXPATHLEN; | 578 | uio->uio_resid = MAXPATHLEN; |
| 587 | uio->uio_iovcnt = 1; | 579 | uio->uio_iovcnt = 1; |
| 588 | 580 | ||
| 589 | VOP_READLINK(vp, uio, 0, NULL, error); | 581 | error = bhv_vop_readlink(vp, uio, 0, NULL); |
| 590 | if (error) { | 582 | if (unlikely(error)) { |
| 591 | kfree(link); | 583 | kfree(link); |
| 592 | link = ERR_PTR(-error); | 584 | link = ERR_PTR(-error); |
| 593 | } else { | 585 | } else { |
| @@ -618,12 +610,7 @@ xfs_vn_permission( | |||
| 618 | int mode, | 610 | int mode, |
| 619 | struct nameidata *nd) | 611 | struct nameidata *nd) |
| 620 | { | 612 | { |
| 621 | vnode_t *vp = vn_from_inode(inode); | 613 | return -bhv_vop_access(vn_from_inode(inode), mode << 6, NULL); |
| 622 | int error; | ||
| 623 | |||
| 624 | mode <<= 6; /* convert from linux to vnode access bits */ | ||
| 625 | VOP_ACCESS(vp, mode, NULL, error); | ||
| 626 | return -error; | ||
| 627 | } | 614 | } |
| 628 | #else | 615 | #else |
| 629 | #define xfs_vn_permission NULL | 616 | #define xfs_vn_permission NULL |
| @@ -636,14 +623,14 @@ xfs_vn_getattr( | |||
| 636 | struct kstat *stat) | 623 | struct kstat *stat) |
| 637 | { | 624 | { |
| 638 | struct inode *inode = dentry->d_inode; | 625 | struct inode *inode = dentry->d_inode; |
| 639 | vnode_t *vp = vn_from_inode(inode); | 626 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 640 | int error = 0; | 627 | int error = 0; |
| 641 | 628 | ||
| 642 | if (unlikely(vp->v_flag & VMODIFIED)) | 629 | if (unlikely(vp->v_flag & VMODIFIED)) |
| 643 | error = vn_revalidate(vp); | 630 | error = vn_revalidate(vp); |
| 644 | if (!error) | 631 | if (!error) |
| 645 | generic_fillattr(inode, stat); | 632 | generic_fillattr(inode, stat); |
| 646 | return 0; | 633 | return -error; |
| 647 | } | 634 | } |
| 648 | 635 | ||
| 649 | STATIC int | 636 | STATIC int |
| @@ -653,8 +640,8 @@ xfs_vn_setattr( | |||
| 653 | { | 640 | { |
| 654 | struct inode *inode = dentry->d_inode; | 641 | struct inode *inode = dentry->d_inode; |
| 655 | unsigned int ia_valid = attr->ia_valid; | 642 | unsigned int ia_valid = attr->ia_valid; |
| 656 | vnode_t *vp = vn_from_inode(inode); | 643 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 657 | vattr_t vattr = { 0 }; | 644 | bhv_vattr_t vattr = { 0 }; |
| 658 | int flags = 0; | 645 | int flags = 0; |
| 659 | int error; | 646 | int error; |
| 660 | 647 | ||
| @@ -697,7 +684,7 @@ xfs_vn_setattr( | |||
| 697 | flags |= ATTR_NONBLOCK; | 684 | flags |= ATTR_NONBLOCK; |
| 698 | #endif | 685 | #endif |
| 699 | 686 | ||
| 700 | VOP_SETATTR(vp, &vattr, flags, NULL, error); | 687 | error = bhv_vop_setattr(vp, &vattr, flags, NULL); |
| 701 | if (likely(!error)) | 688 | if (likely(!error)) |
| 702 | __vn_revalidate(vp, &vattr); | 689 | __vn_revalidate(vp, &vattr); |
| 703 | return -error; | 690 | return -error; |
| @@ -718,7 +705,7 @@ xfs_vn_setxattr( | |||
| 718 | size_t size, | 705 | size_t size, |
| 719 | int flags) | 706 | int flags) |
| 720 | { | 707 | { |
| 721 | vnode_t *vp = vn_from_inode(dentry->d_inode); | 708 | bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); |
| 722 | char *attr = (char *)name; | 709 | char *attr = (char *)name; |
| 723 | attrnames_t *namesp; | 710 | attrnames_t *namesp; |
| 724 | int xflags = 0; | 711 | int xflags = 0; |
| @@ -748,7 +735,7 @@ xfs_vn_getxattr( | |||
| 748 | void *data, | 735 | void *data, |
| 749 | size_t size) | 736 | size_t size) |
| 750 | { | 737 | { |
| 751 | vnode_t *vp = vn_from_inode(dentry->d_inode); | 738 | bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); |
| 752 | char *attr = (char *)name; | 739 | char *attr = (char *)name; |
| 753 | attrnames_t *namesp; | 740 | attrnames_t *namesp; |
| 754 | int xflags = 0; | 741 | int xflags = 0; |
| @@ -777,7 +764,7 @@ xfs_vn_listxattr( | |||
| 777 | char *data, | 764 | char *data, |
| 778 | size_t size) | 765 | size_t size) |
| 779 | { | 766 | { |
| 780 | vnode_t *vp = vn_from_inode(dentry->d_inode); | 767 | bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); |
| 781 | int error, xflags = ATTR_KERNAMELS; | 768 | int error, xflags = ATTR_KERNAMELS; |
| 782 | ssize_t result; | 769 | ssize_t result; |
| 783 | 770 | ||
| @@ -796,7 +783,7 @@ xfs_vn_removexattr( | |||
| 796 | struct dentry *dentry, | 783 | struct dentry *dentry, |
| 797 | const char *name) | 784 | const char *name) |
| 798 | { | 785 | { |
| 799 | vnode_t *vp = vn_from_inode(dentry->d_inode); | 786 | bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); |
| 800 | char *attr = (char *)name; | 787 | char *attr = (char *)name; |
| 801 | attrnames_t *namesp; | 788 | attrnames_t *namesp; |
| 802 | int xflags = 0; | 789 | int xflags = 0; |
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index e9fe43d74768..aa26ab906c88 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h | |||
| @@ -134,14 +134,21 @@ BUFFER_FNS(PrivateStart, unwritten); | |||
| 134 | #define xfs_buf_age_centisecs xfs_params.xfs_buf_age.val | 134 | #define xfs_buf_age_centisecs xfs_params.xfs_buf_age.val |
| 135 | #define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val | 135 | #define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val |
| 136 | #define xfs_rotorstep xfs_params.rotorstep.val | 136 | #define xfs_rotorstep xfs_params.rotorstep.val |
| 137 | #define xfs_inherit_nodefrag xfs_params.inherit_nodfrg.val | ||
| 137 | 138 | ||
| 138 | #ifndef raw_smp_processor_id | 139 | #define current_cpu() (raw_smp_processor_id()) |
| 139 | #define raw_smp_processor_id() smp_processor_id() | ||
| 140 | #endif | ||
| 141 | #define current_cpu() raw_smp_processor_id() | ||
| 142 | #define current_pid() (current->pid) | 140 | #define current_pid() (current->pid) |
| 143 | #define current_fsuid(cred) (current->fsuid) | 141 | #define current_fsuid(cred) (current->fsuid) |
| 144 | #define current_fsgid(cred) (current->fsgid) | 142 | #define current_fsgid(cred) (current->fsgid) |
| 143 | #define current_set_flags(f) (current->flags |= (f)) | ||
| 144 | #define current_test_flags(f) (current->flags & (f)) | ||
| 145 | #define current_clear_flags(f) (current->flags & ~(f)) | ||
| 146 | #define current_set_flags_nested(sp, f) \ | ||
| 147 | (*(sp) = current->flags, current->flags |= (f)) | ||
| 148 | #define current_clear_flags_nested(sp, f) \ | ||
| 149 | (*(sp) = current->flags, current->flags &= ~(f)) | ||
| 150 | #define current_restore_flags_nested(sp, f) \ | ||
| 151 | (current->flags = ((current->flags & ~(f)) | (*(sp) & (f)))) | ||
| 145 | 152 | ||
| 146 | #define NBPP PAGE_SIZE | 153 | #define NBPP PAGE_SIZE |
| 147 | #define DPPSHFT (PAGE_SHIFT - 9) | 154 | #define DPPSHFT (PAGE_SHIFT - 9) |
| @@ -187,25 +194,9 @@ BUFFER_FNS(PrivateStart, unwritten); | |||
| 187 | /* bytes to clicks */ | 194 | /* bytes to clicks */ |
| 188 | #define btoc(x) (((__psunsigned_t)(x)+(NBPC-1))>>BPCSHIFT) | 195 | #define btoc(x) (((__psunsigned_t)(x)+(NBPC-1))>>BPCSHIFT) |
| 189 | 196 | ||
| 190 | #ifndef ENOATTR | ||
| 191 | #define ENOATTR ENODATA /* Attribute not found */ | 197 | #define ENOATTR ENODATA /* Attribute not found */ |
| 192 | #endif | 198 | #define EWRONGFS EINVAL /* Mount with wrong filesystem type */ |
| 193 | 199 | #define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ | |
| 194 | /* Note: EWRONGFS never visible outside the kernel */ | ||
| 195 | #define EWRONGFS EINVAL /* Mount with wrong filesystem type */ | ||
| 196 | |||
| 197 | /* | ||
| 198 | * XXX EFSCORRUPTED needs a real value in errno.h. asm-i386/errno.h won't | ||
| 199 | * return codes out of its known range in errno. | ||
| 200 | * XXX Also note: needs to be < 1000 and fairly unique on Linux (mustn't | ||
| 201 | * conflict with any code we use already or any code a driver may use) | ||
| 202 | * XXX Some options (currently we do #2): | ||
| 203 | * 1/ New error code ["Filesystem is corrupted", _after_ glibc updated] | ||
| 204 | * 2/ 990 ["Unknown error 990"] | ||
| 205 | * 3/ EUCLEAN ["Structure needs cleaning"] | ||
| 206 | * 4/ Convert EFSCORRUPTED to EIO [just prior to return into userspace] | ||
| 207 | */ | ||
| 208 | #define EFSCORRUPTED 990 /* Filesystem is corrupted */ | ||
| 209 | 200 | ||
| 210 | #define SYNCHRONIZE() barrier() | 201 | #define SYNCHRONIZE() barrier() |
| 211 | #define __return_address __builtin_return_address(0) | 202 | #define __return_address __builtin_return_address(0) |
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 67efe3308980..5d9cfd91ad08 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_alloc.h" | 27 | #include "xfs_alloc.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| @@ -206,7 +204,7 @@ xfs_read( | |||
| 206 | xfs_fsize_t n; | 204 | xfs_fsize_t n; |
| 207 | xfs_inode_t *ip; | 205 | xfs_inode_t *ip; |
| 208 | xfs_mount_t *mp; | 206 | xfs_mount_t *mp; |
| 209 | vnode_t *vp; | 207 | bhv_vnode_t *vp; |
| 210 | unsigned long seg; | 208 | unsigned long seg; |
| 211 | 209 | ||
| 212 | ip = XFS_BHVTOI(bdp); | 210 | ip = XFS_BHVTOI(bdp); |
| @@ -258,7 +256,7 @@ xfs_read( | |||
| 258 | 256 | ||
| 259 | if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && | 257 | if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) && |
| 260 | !(ioflags & IO_INVIS)) { | 258 | !(ioflags & IO_INVIS)) { |
| 261 | vrwlock_t locktype = VRWLOCK_READ; | 259 | bhv_vrwlock_t locktype = VRWLOCK_READ; |
| 262 | int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags); | 260 | int dmflags = FILP_DELAY_FLAG(file) | DM_SEM_FLAG_RD(ioflags); |
| 263 | 261 | ||
| 264 | ret = -XFS_SEND_DATA(mp, DM_EVENT_READ, | 262 | ret = -XFS_SEND_DATA(mp, DM_EVENT_READ, |
| @@ -271,7 +269,7 @@ xfs_read( | |||
| 271 | } | 269 | } |
| 272 | 270 | ||
| 273 | if (unlikely((ioflags & IO_ISDIRECT) && VN_CACHED(vp))) | 271 | if (unlikely((ioflags & IO_ISDIRECT) && VN_CACHED(vp))) |
| 274 | VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(*offset)), | 272 | bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)), |
| 275 | -1, FI_REMAPF_LOCKED); | 273 | -1, FI_REMAPF_LOCKED); |
| 276 | 274 | ||
| 277 | xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, | 275 | xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore, |
| @@ -313,7 +311,7 @@ xfs_sendfile( | |||
| 313 | 311 | ||
| 314 | if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) && | 312 | if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) && |
| 315 | (!(ioflags & IO_INVIS))) { | 313 | (!(ioflags & IO_INVIS))) { |
| 316 | vrwlock_t locktype = VRWLOCK_READ; | 314 | bhv_vrwlock_t locktype = VRWLOCK_READ; |
| 317 | int error; | 315 | int error; |
| 318 | 316 | ||
| 319 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), | 317 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), |
| @@ -357,7 +355,7 @@ xfs_splice_read( | |||
| 357 | 355 | ||
| 358 | if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) && | 356 | if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) && |
| 359 | (!(ioflags & IO_INVIS))) { | 357 | (!(ioflags & IO_INVIS))) { |
| 360 | vrwlock_t locktype = VRWLOCK_READ; | 358 | bhv_vrwlock_t locktype = VRWLOCK_READ; |
| 361 | int error; | 359 | int error; |
| 362 | 360 | ||
| 363 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), | 361 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), |
| @@ -401,7 +399,7 @@ xfs_splice_write( | |||
| 401 | 399 | ||
| 402 | if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_WRITE) && | 400 | if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_WRITE) && |
| 403 | (!(ioflags & IO_INVIS))) { | 401 | (!(ioflags & IO_INVIS))) { |
| 404 | vrwlock_t locktype = VRWLOCK_WRITE; | 402 | bhv_vrwlock_t locktype = VRWLOCK_WRITE; |
| 405 | int error; | 403 | int error; |
| 406 | 404 | ||
| 407 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, BHV_TO_VNODE(bdp), | 405 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, BHV_TO_VNODE(bdp), |
| @@ -458,7 +456,7 @@ xfs_zero_last_block( | |||
| 458 | last_fsb = XFS_B_TO_FSBT(mp, isize); | 456 | last_fsb = XFS_B_TO_FSBT(mp, isize); |
| 459 | nimaps = 1; | 457 | nimaps = 1; |
| 460 | error = XFS_BMAPI(mp, NULL, io, last_fsb, 1, 0, NULL, 0, &imap, | 458 | error = XFS_BMAPI(mp, NULL, io, last_fsb, 1, 0, NULL, 0, &imap, |
| 461 | &nimaps, NULL); | 459 | &nimaps, NULL, NULL); |
| 462 | if (error) { | 460 | if (error) { |
| 463 | return error; | 461 | return error; |
| 464 | } | 462 | } |
| @@ -499,7 +497,7 @@ xfs_zero_last_block( | |||
| 499 | 497 | ||
| 500 | int /* error (positive) */ | 498 | int /* error (positive) */ |
| 501 | xfs_zero_eof( | 499 | xfs_zero_eof( |
| 502 | vnode_t *vp, | 500 | bhv_vnode_t *vp, |
| 503 | xfs_iocore_t *io, | 501 | xfs_iocore_t *io, |
| 504 | xfs_off_t offset, /* starting I/O offset */ | 502 | xfs_off_t offset, /* starting I/O offset */ |
| 505 | xfs_fsize_t isize, /* current inode size */ | 503 | xfs_fsize_t isize, /* current inode size */ |
| @@ -510,7 +508,6 @@ xfs_zero_eof( | |||
| 510 | xfs_fileoff_t end_zero_fsb; | 508 | xfs_fileoff_t end_zero_fsb; |
| 511 | xfs_fileoff_t zero_count_fsb; | 509 | xfs_fileoff_t zero_count_fsb; |
| 512 | xfs_fileoff_t last_fsb; | 510 | xfs_fileoff_t last_fsb; |
| 513 | xfs_extlen_t buf_len_fsb; | ||
| 514 | xfs_mount_t *mp = io->io_mount; | 511 | xfs_mount_t *mp = io->io_mount; |
| 515 | int nimaps; | 512 | int nimaps; |
| 516 | int error = 0; | 513 | int error = 0; |
| @@ -556,7 +553,7 @@ xfs_zero_eof( | |||
| 556 | nimaps = 1; | 553 | nimaps = 1; |
| 557 | zero_count_fsb = end_zero_fsb - start_zero_fsb + 1; | 554 | zero_count_fsb = end_zero_fsb - start_zero_fsb + 1; |
| 558 | error = XFS_BMAPI(mp, NULL, io, start_zero_fsb, zero_count_fsb, | 555 | error = XFS_BMAPI(mp, NULL, io, start_zero_fsb, zero_count_fsb, |
| 559 | 0, NULL, 0, &imap, &nimaps, NULL); | 556 | 0, NULL, 0, &imap, &nimaps, NULL, NULL); |
| 560 | if (error) { | 557 | if (error) { |
| 561 | ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); | 558 | ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); |
| 562 | ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); | 559 | ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); |
| @@ -579,16 +576,7 @@ xfs_zero_eof( | |||
| 579 | } | 576 | } |
| 580 | 577 | ||
| 581 | /* | 578 | /* |
| 582 | * There are blocks in the range requested. | 579 | * There are blocks we need to zero. |
| 583 | * Zero them a single write at a time. We actually | ||
| 584 | * don't zero the entire range returned if it is | ||
| 585 | * too big and simply loop around to get the rest. | ||
| 586 | * That is not the most efficient thing to do, but it | ||
| 587 | * is simple and this path should not be exercised often. | ||
| 588 | */ | ||
| 589 | buf_len_fsb = XFS_FILBLKS_MIN(imap.br_blockcount, | ||
| 590 | mp->m_writeio_blocks << 8); | ||
| 591 | /* | ||
| 592 | * Drop the inode lock while we're doing the I/O. | 580 | * Drop the inode lock while we're doing the I/O. |
| 593 | * We'll still have the iolock to protect us. | 581 | * We'll still have the iolock to protect us. |
| 594 | */ | 582 | */ |
| @@ -596,14 +584,13 @@ xfs_zero_eof( | |||
| 596 | 584 | ||
| 597 | error = xfs_iozero(ip, | 585 | error = xfs_iozero(ip, |
| 598 | XFS_FSB_TO_B(mp, start_zero_fsb), | 586 | XFS_FSB_TO_B(mp, start_zero_fsb), |
| 599 | XFS_FSB_TO_B(mp, buf_len_fsb), | 587 | XFS_FSB_TO_B(mp, imap.br_blockcount), |
| 600 | end_size); | 588 | end_size); |
| 601 | |||
| 602 | if (error) { | 589 | if (error) { |
| 603 | goto out_lock; | 590 | goto out_lock; |
| 604 | } | 591 | } |
| 605 | 592 | ||
| 606 | start_zero_fsb = imap.br_startoff + buf_len_fsb; | 593 | start_zero_fsb = imap.br_startoff + imap.br_blockcount; |
| 607 | ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); | 594 | ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); |
| 608 | 595 | ||
| 609 | XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); | 596 | XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); |
| @@ -637,11 +624,11 @@ xfs_write( | |||
| 637 | ssize_t ret = 0, error = 0; | 624 | ssize_t ret = 0, error = 0; |
| 638 | xfs_fsize_t isize, new_size; | 625 | xfs_fsize_t isize, new_size; |
| 639 | xfs_iocore_t *io; | 626 | xfs_iocore_t *io; |
| 640 | vnode_t *vp; | 627 | bhv_vnode_t *vp; |
| 641 | unsigned long seg; | 628 | unsigned long seg; |
| 642 | int iolock; | 629 | int iolock; |
| 643 | int eventsent = 0; | 630 | int eventsent = 0; |
| 644 | vrwlock_t locktype; | 631 | bhv_vrwlock_t locktype; |
| 645 | size_t ocount = 0, count; | 632 | size_t ocount = 0, count; |
| 646 | loff_t pos; | 633 | loff_t pos; |
| 647 | int need_i_mutex = 1, need_flush = 0; | 634 | int need_i_mutex = 1, need_flush = 0; |
| @@ -679,11 +666,11 @@ xfs_write( | |||
| 679 | io = &xip->i_iocore; | 666 | io = &xip->i_iocore; |
| 680 | mp = io->io_mount; | 667 | mp = io->io_mount; |
| 681 | 668 | ||
| 669 | vfs_wait_for_freeze(vp->v_vfsp, SB_FREEZE_WRITE); | ||
| 670 | |||
| 682 | if (XFS_FORCED_SHUTDOWN(mp)) | 671 | if (XFS_FORCED_SHUTDOWN(mp)) |
| 683 | return -EIO; | 672 | return -EIO; |
| 684 | 673 | ||
| 685 | fs_check_frozen(vp->v_vfsp, SB_FREEZE_WRITE); | ||
| 686 | |||
| 687 | if (ioflags & IO_ISDIRECT) { | 674 | if (ioflags & IO_ISDIRECT) { |
| 688 | xfs_buftarg_t *target = | 675 | xfs_buftarg_t *target = |
| 689 | (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? | 676 | (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? |
| @@ -814,7 +801,7 @@ retry: | |||
| 814 | if (need_flush) { | 801 | if (need_flush) { |
| 815 | xfs_inval_cached_trace(io, pos, -1, | 802 | xfs_inval_cached_trace(io, pos, -1, |
| 816 | ctooff(offtoct(pos)), -1); | 803 | ctooff(offtoct(pos)), -1); |
| 817 | VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(pos)), | 804 | bhv_vop_flushinval_pages(vp, ctooff(offtoct(pos)), |
| 818 | -1, FI_REMAPF_LOCKED); | 805 | -1, FI_REMAPF_LOCKED); |
| 819 | } | 806 | } |
| 820 | 807 | ||
| @@ -903,79 +890,9 @@ retry: | |||
| 903 | 890 | ||
| 904 | /* Handle various SYNC-type writes */ | 891 | /* Handle various SYNC-type writes */ |
| 905 | if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) { | 892 | if ((file->f_flags & O_SYNC) || IS_SYNC(inode)) { |
| 906 | /* | 893 | error = xfs_write_sync_logforce(mp, xip); |
| 907 | * If we're treating this as O_DSYNC and we have not updated the | 894 | if (error) |
| 908 | * size, force the log. | 895 | goto out_unlock_internal; |
| 909 | */ | ||
| 910 | if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC) && | ||
| 911 | !(xip->i_update_size)) { | ||
| 912 | xfs_inode_log_item_t *iip = xip->i_itemp; | ||
| 913 | |||
| 914 | /* | ||
| 915 | * If an allocation transaction occurred | ||
| 916 | * without extending the size, then we have to force | ||
| 917 | * the log up the proper point to ensure that the | ||
| 918 | * allocation is permanent. We can't count on | ||
| 919 | * the fact that buffered writes lock out direct I/O | ||
| 920 | * writes - the direct I/O write could have extended | ||
| 921 | * the size nontransactionally, then finished before | ||
| 922 | * we started. xfs_write_file will think that the file | ||
| 923 | * didn't grow but the update isn't safe unless the | ||
| 924 | * size change is logged. | ||
| 925 | * | ||
| 926 | * Force the log if we've committed a transaction | ||
| 927 | * against the inode or if someone else has and | ||
| 928 | * the commit record hasn't gone to disk (e.g. | ||
| 929 | * the inode is pinned). This guarantees that | ||
| 930 | * all changes affecting the inode are permanent | ||
| 931 | * when we return. | ||
| 932 | */ | ||
| 933 | if (iip && iip->ili_last_lsn) { | ||
| 934 | xfs_log_force(mp, iip->ili_last_lsn, | ||
| 935 | XFS_LOG_FORCE | XFS_LOG_SYNC); | ||
| 936 | } else if (xfs_ipincount(xip) > 0) { | ||
| 937 | xfs_log_force(mp, (xfs_lsn_t)0, | ||
| 938 | XFS_LOG_FORCE | XFS_LOG_SYNC); | ||
| 939 | } | ||
| 940 | |||
| 941 | } else { | ||
| 942 | xfs_trans_t *tp; | ||
| 943 | |||
| 944 | /* | ||
| 945 | * O_SYNC or O_DSYNC _with_ a size update are handled | ||
| 946 | * the same way. | ||
| 947 | * | ||
| 948 | * If the write was synchronous then we need to make | ||
| 949 | * sure that the inode modification time is permanent. | ||
| 950 | * We'll have updated the timestamp above, so here | ||
| 951 | * we use a synchronous transaction to log the inode. | ||
| 952 | * It's not fast, but it's necessary. | ||
| 953 | * | ||
| 954 | * If this a dsync write and the size got changed | ||
| 955 | * non-transactionally, then we need to ensure that | ||
| 956 | * the size change gets logged in a synchronous | ||
| 957 | * transaction. | ||
| 958 | */ | ||
| 959 | |||
| 960 | tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC); | ||
| 961 | if ((error = xfs_trans_reserve(tp, 0, | ||
| 962 | XFS_SWRITE_LOG_RES(mp), | ||
| 963 | 0, 0, 0))) { | ||
| 964 | /* Transaction reserve failed */ | ||
| 965 | xfs_trans_cancel(tp, 0); | ||
| 966 | } else { | ||
| 967 | /* Transaction reserve successful */ | ||
| 968 | xfs_ilock(xip, XFS_ILOCK_EXCL); | ||
| 969 | xfs_trans_ijoin(tp, xip, XFS_ILOCK_EXCL); | ||
| 970 | xfs_trans_ihold(tp, xip); | ||
| 971 | xfs_trans_log_inode(tp, xip, XFS_ILOG_CORE); | ||
| 972 | xfs_trans_set_sync(tp); | ||
| 973 | error = xfs_trans_commit(tp, 0, NULL); | ||
| 974 | xfs_iunlock(xip, XFS_ILOCK_EXCL); | ||
| 975 | } | ||
| 976 | if (error) | ||
| 977 | goto out_unlock_internal; | ||
| 978 | } | ||
| 979 | 896 | ||
| 980 | xfs_rwunlock(bdp, locktype); | 897 | xfs_rwunlock(bdp, locktype); |
| 981 | if (need_i_mutex) | 898 | if (need_i_mutex) |
diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index 8f4539952350..c77e62efb742 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h | |||
| @@ -18,8 +18,8 @@ | |||
| 18 | #ifndef __XFS_LRW_H__ | 18 | #ifndef __XFS_LRW_H__ |
| 19 | #define __XFS_LRW_H__ | 19 | #define __XFS_LRW_H__ |
| 20 | 20 | ||
| 21 | struct vnode; | ||
| 22 | struct bhv_desc; | 21 | struct bhv_desc; |
| 22 | struct bhv_vnode; | ||
| 23 | struct xfs_mount; | 23 | struct xfs_mount; |
| 24 | struct xfs_iocore; | 24 | struct xfs_iocore; |
| 25 | struct xfs_inode; | 25 | struct xfs_inode; |
| @@ -49,7 +49,7 @@ struct xfs_iomap; | |||
| 49 | #define XFS_CTRUNC4 14 | 49 | #define XFS_CTRUNC4 14 |
| 50 | #define XFS_CTRUNC5 15 | 50 | #define XFS_CTRUNC5 15 |
| 51 | #define XFS_CTRUNC6 16 | 51 | #define XFS_CTRUNC6 16 |
| 52 | #define XFS_BUNMAPI 17 | 52 | #define XFS_BUNMAP 17 |
| 53 | #define XFS_INVAL_CACHED 18 | 53 | #define XFS_INVAL_CACHED 18 |
| 54 | #define XFS_DIORD_ENTER 19 | 54 | #define XFS_DIORD_ENTER 19 |
| 55 | #define XFS_DIOWR_ENTER 20 | 55 | #define XFS_DIOWR_ENTER 20 |
| @@ -82,7 +82,7 @@ extern int xfsbdstrat(struct xfs_mount *, struct xfs_buf *); | |||
| 82 | extern int xfs_bdstrat_cb(struct xfs_buf *); | 82 | extern int xfs_bdstrat_cb(struct xfs_buf *); |
| 83 | extern int xfs_dev_is_read_only(struct xfs_mount *, char *); | 83 | extern int xfs_dev_is_read_only(struct xfs_mount *, char *); |
| 84 | 84 | ||
| 85 | extern int xfs_zero_eof(struct vnode *, struct xfs_iocore *, xfs_off_t, | 85 | extern int xfs_zero_eof(struct bhv_vnode *, struct xfs_iocore *, xfs_off_t, |
| 86 | xfs_fsize_t, xfs_fsize_t); | 86 | xfs_fsize_t, xfs_fsize_t); |
| 87 | extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *, | 87 | extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *, |
| 88 | const struct iovec *, unsigned int, | 88 | const struct iovec *, unsigned int, |
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 68f4793e8a11..f2a0778536f4 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_alloc.h" | 27 | #include "xfs_alloc.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| @@ -151,7 +149,7 @@ xfs_set_inodeops( | |||
| 151 | STATIC __inline__ void | 149 | STATIC __inline__ void |
| 152 | xfs_revalidate_inode( | 150 | xfs_revalidate_inode( |
| 153 | xfs_mount_t *mp, | 151 | xfs_mount_t *mp, |
| 154 | vnode_t *vp, | 152 | bhv_vnode_t *vp, |
| 155 | xfs_inode_t *ip) | 153 | xfs_inode_t *ip) |
| 156 | { | 154 | { |
| 157 | struct inode *inode = vn_to_inode(vp); | 155 | struct inode *inode = vn_to_inode(vp); |
| @@ -206,7 +204,7 @@ xfs_revalidate_inode( | |||
| 206 | void | 204 | void |
| 207 | xfs_initialize_vnode( | 205 | xfs_initialize_vnode( |
| 208 | bhv_desc_t *bdp, | 206 | bhv_desc_t *bdp, |
| 209 | vnode_t *vp, | 207 | bhv_vnode_t *vp, |
| 210 | bhv_desc_t *inode_bhv, | 208 | bhv_desc_t *inode_bhv, |
| 211 | int unlock) | 209 | int unlock) |
| 212 | { | 210 | { |
| @@ -336,7 +334,7 @@ STATIC struct inode * | |||
| 336 | xfs_fs_alloc_inode( | 334 | xfs_fs_alloc_inode( |
| 337 | struct super_block *sb) | 335 | struct super_block *sb) |
| 338 | { | 336 | { |
| 339 | vnode_t *vp; | 337 | bhv_vnode_t *vp; |
| 340 | 338 | ||
| 341 | vp = kmem_zone_alloc(xfs_vnode_zone, KM_SLEEP); | 339 | vp = kmem_zone_alloc(xfs_vnode_zone, KM_SLEEP); |
| 342 | if (unlikely(!vp)) | 340 | if (unlikely(!vp)) |
| @@ -359,13 +357,13 @@ xfs_fs_inode_init_once( | |||
| 359 | { | 357 | { |
| 360 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | 358 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == |
| 361 | SLAB_CTOR_CONSTRUCTOR) | 359 | SLAB_CTOR_CONSTRUCTOR) |
| 362 | inode_init_once(vn_to_inode((vnode_t *)vnode)); | 360 | inode_init_once(vn_to_inode((bhv_vnode_t *)vnode)); |
| 363 | } | 361 | } |
| 364 | 362 | ||
| 365 | STATIC int | 363 | STATIC int |
| 366 | xfs_init_zones(void) | 364 | xfs_init_zones(void) |
| 367 | { | 365 | { |
| 368 | xfs_vnode_zone = kmem_zone_init_flags(sizeof(vnode_t), "xfs_vnode_t", | 366 | xfs_vnode_zone = kmem_zone_init_flags(sizeof(bhv_vnode_t), "xfs_vnode", |
| 369 | KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | | 367 | KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | |
| 370 | KM_ZONE_SPREAD, | 368 | KM_ZONE_SPREAD, |
| 371 | xfs_fs_inode_init_once); | 369 | xfs_fs_inode_init_once); |
| @@ -409,22 +407,17 @@ xfs_fs_write_inode( | |||
| 409 | struct inode *inode, | 407 | struct inode *inode, |
| 410 | int sync) | 408 | int sync) |
| 411 | { | 409 | { |
| 412 | vnode_t *vp = vn_from_inode(inode); | 410 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 413 | int error = 0, flags = FLUSH_INODE; | 411 | int error = 0, flags = FLUSH_INODE; |
| 414 | 412 | ||
| 415 | if (vp) { | 413 | if (vp) { |
| 416 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); | 414 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); |
| 417 | if (sync) | 415 | if (sync) |
| 418 | flags |= FLUSH_SYNC; | 416 | flags |= FLUSH_SYNC; |
| 419 | VOP_IFLUSH(vp, flags, error); | 417 | error = bhv_vop_iflush(vp, flags); |
| 420 | if (error == EAGAIN) { | 418 | if (error == EAGAIN) |
| 421 | if (sync) | 419 | error = sync? bhv_vop_iflush(vp, flags | FLUSH_LOG) : 0; |
| 422 | VOP_IFLUSH(vp, flags | FLUSH_LOG, error); | ||
| 423 | else | ||
| 424 | error = 0; | ||
| 425 | } | ||
| 426 | } | 420 | } |
| 427 | |||
| 428 | return -error; | 421 | return -error; |
| 429 | } | 422 | } |
| 430 | 423 | ||
| @@ -432,8 +425,7 @@ STATIC void | |||
| 432 | xfs_fs_clear_inode( | 425 | xfs_fs_clear_inode( |
| 433 | struct inode *inode) | 426 | struct inode *inode) |
| 434 | { | 427 | { |
| 435 | vnode_t *vp = vn_from_inode(inode); | 428 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 436 | int error, cache; | ||
| 437 | 429 | ||
| 438 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); | 430 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); |
| 439 | 431 | ||
| @@ -446,20 +438,18 @@ xfs_fs_clear_inode( | |||
| 446 | * This can happen because xfs_iget_core calls xfs_idestroy if we | 438 | * This can happen because xfs_iget_core calls xfs_idestroy if we |
| 447 | * find an inode with di_mode == 0 but without IGET_CREATE set. | 439 | * find an inode with di_mode == 0 but without IGET_CREATE set. |
| 448 | */ | 440 | */ |
| 449 | if (vp->v_fbhv) | 441 | if (VNHEAD(vp)) |
| 450 | VOP_INACTIVE(vp, NULL, cache); | 442 | bhv_vop_inactive(vp, NULL); |
| 451 | 443 | ||
| 452 | VN_LOCK(vp); | 444 | VN_LOCK(vp); |
| 453 | vp->v_flag &= ~VMODIFIED; | 445 | vp->v_flag &= ~VMODIFIED; |
| 454 | VN_UNLOCK(vp, 0); | 446 | VN_UNLOCK(vp, 0); |
| 455 | 447 | ||
| 456 | if (vp->v_fbhv) { | 448 | if (VNHEAD(vp)) |
| 457 | VOP_RECLAIM(vp, error); | 449 | if (bhv_vop_reclaim(vp)) |
| 458 | if (error) | 450 | panic("%s: cannot reclaim 0x%p\n", __FUNCTION__, vp); |
| 459 | panic("vn_purge: cannot reclaim"); | ||
| 460 | } | ||
| 461 | 451 | ||
| 462 | ASSERT(vp->v_fbhv == NULL); | 452 | ASSERT(VNHEAD(vp) == NULL); |
| 463 | 453 | ||
| 464 | #ifdef XFS_VNODE_TRACE | 454 | #ifdef XFS_VNODE_TRACE |
| 465 | ktrace_free(vp->v_trace); | 455 | ktrace_free(vp->v_trace); |
| @@ -475,13 +465,13 @@ xfs_fs_clear_inode( | |||
| 475 | */ | 465 | */ |
| 476 | STATIC void | 466 | STATIC void |
| 477 | xfs_syncd_queue_work( | 467 | xfs_syncd_queue_work( |
| 478 | struct vfs *vfs, | 468 | struct bhv_vfs *vfs, |
| 479 | void *data, | 469 | void *data, |
| 480 | void (*syncer)(vfs_t *, void *)) | 470 | void (*syncer)(bhv_vfs_t *, void *)) |
| 481 | { | 471 | { |
| 482 | vfs_sync_work_t *work; | 472 | struct bhv_vfs_sync_work *work; |
| 483 | 473 | ||
| 484 | work = kmem_alloc(sizeof(struct vfs_sync_work), KM_SLEEP); | 474 | work = kmem_alloc(sizeof(struct bhv_vfs_sync_work), KM_SLEEP); |
| 485 | INIT_LIST_HEAD(&work->w_list); | 475 | INIT_LIST_HEAD(&work->w_list); |
| 486 | work->w_syncer = syncer; | 476 | work->w_syncer = syncer; |
| 487 | work->w_data = data; | 477 | work->w_data = data; |
| @@ -500,7 +490,7 @@ xfs_syncd_queue_work( | |||
| 500 | */ | 490 | */ |
| 501 | STATIC void | 491 | STATIC void |
| 502 | xfs_flush_inode_work( | 492 | xfs_flush_inode_work( |
| 503 | vfs_t *vfs, | 493 | bhv_vfs_t *vfs, |
| 504 | void *inode) | 494 | void *inode) |
| 505 | { | 495 | { |
| 506 | filemap_flush(((struct inode *)inode)->i_mapping); | 496 | filemap_flush(((struct inode *)inode)->i_mapping); |
| @@ -512,7 +502,7 @@ xfs_flush_inode( | |||
| 512 | xfs_inode_t *ip) | 502 | xfs_inode_t *ip) |
| 513 | { | 503 | { |
| 514 | struct inode *inode = vn_to_inode(XFS_ITOV(ip)); | 504 | struct inode *inode = vn_to_inode(XFS_ITOV(ip)); |
| 515 | struct vfs *vfs = XFS_MTOVFS(ip->i_mount); | 505 | struct bhv_vfs *vfs = XFS_MTOVFS(ip->i_mount); |
| 516 | 506 | ||
| 517 | igrab(inode); | 507 | igrab(inode); |
| 518 | xfs_syncd_queue_work(vfs, inode, xfs_flush_inode_work); | 508 | xfs_syncd_queue_work(vfs, inode, xfs_flush_inode_work); |
| @@ -525,7 +515,7 @@ xfs_flush_inode( | |||
| 525 | */ | 515 | */ |
| 526 | STATIC void | 516 | STATIC void |
| 527 | xfs_flush_device_work( | 517 | xfs_flush_device_work( |
| 528 | vfs_t *vfs, | 518 | bhv_vfs_t *vfs, |
| 529 | void *inode) | 519 | void *inode) |
| 530 | { | 520 | { |
| 531 | sync_blockdev(vfs->vfs_super->s_bdev); | 521 | sync_blockdev(vfs->vfs_super->s_bdev); |
| @@ -537,7 +527,7 @@ xfs_flush_device( | |||
| 537 | xfs_inode_t *ip) | 527 | xfs_inode_t *ip) |
| 538 | { | 528 | { |
| 539 | struct inode *inode = vn_to_inode(XFS_ITOV(ip)); | 529 | struct inode *inode = vn_to_inode(XFS_ITOV(ip)); |
| 540 | struct vfs *vfs = XFS_MTOVFS(ip->i_mount); | 530 | struct bhv_vfs *vfs = XFS_MTOVFS(ip->i_mount); |
| 541 | 531 | ||
| 542 | igrab(inode); | 532 | igrab(inode); |
| 543 | xfs_syncd_queue_work(vfs, inode, xfs_flush_device_work); | 533 | xfs_syncd_queue_work(vfs, inode, xfs_flush_device_work); |
| @@ -545,16 +535,16 @@ xfs_flush_device( | |||
| 545 | xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); | 535 | xfs_log_force(ip->i_mount, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); |
| 546 | } | 536 | } |
| 547 | 537 | ||
| 548 | #define SYNCD_FLAGS (SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR|SYNC_REFCACHE) | ||
| 549 | STATIC void | 538 | STATIC void |
| 550 | vfs_sync_worker( | 539 | vfs_sync_worker( |
| 551 | vfs_t *vfsp, | 540 | bhv_vfs_t *vfsp, |
| 552 | void *unused) | 541 | void *unused) |
| 553 | { | 542 | { |
| 554 | int error; | 543 | int error; |
| 555 | 544 | ||
| 556 | if (!(vfsp->vfs_flag & VFS_RDONLY)) | 545 | if (!(vfsp->vfs_flag & VFS_RDONLY)) |
| 557 | VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error); | 546 | error = bhv_vfs_sync(vfsp, SYNC_FSDATA | SYNC_BDFLUSH | \ |
| 547 | SYNC_ATTR | SYNC_REFCACHE, NULL); | ||
| 558 | vfsp->vfs_sync_seq++; | 548 | vfsp->vfs_sync_seq++; |
| 559 | wmb(); | 549 | wmb(); |
| 560 | wake_up(&vfsp->vfs_wait_single_sync_task); | 550 | wake_up(&vfsp->vfs_wait_single_sync_task); |
| @@ -565,8 +555,8 @@ xfssyncd( | |||
| 565 | void *arg) | 555 | void *arg) |
| 566 | { | 556 | { |
| 567 | long timeleft; | 557 | long timeleft; |
| 568 | vfs_t *vfsp = (vfs_t *) arg; | 558 | bhv_vfs_t *vfsp = (bhv_vfs_t *) arg; |
| 569 | struct vfs_sync_work *work, *n; | 559 | bhv_vfs_sync_work_t *work, *n; |
| 570 | LIST_HEAD (tmp); | 560 | LIST_HEAD (tmp); |
| 571 | 561 | ||
| 572 | timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); | 562 | timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); |
| @@ -600,7 +590,7 @@ xfssyncd( | |||
| 600 | list_del(&work->w_list); | 590 | list_del(&work->w_list); |
| 601 | if (work == &vfsp->vfs_sync_work) | 591 | if (work == &vfsp->vfs_sync_work) |
| 602 | continue; | 592 | continue; |
| 603 | kmem_free(work, sizeof(struct vfs_sync_work)); | 593 | kmem_free(work, sizeof(struct bhv_vfs_sync_work)); |
| 604 | } | 594 | } |
| 605 | } | 595 | } |
| 606 | 596 | ||
| @@ -609,7 +599,7 @@ xfssyncd( | |||
| 609 | 599 | ||
| 610 | STATIC int | 600 | STATIC int |
| 611 | xfs_fs_start_syncd( | 601 | xfs_fs_start_syncd( |
| 612 | vfs_t *vfsp) | 602 | bhv_vfs_t *vfsp) |
| 613 | { | 603 | { |
| 614 | vfsp->vfs_sync_work.w_syncer = vfs_sync_worker; | 604 | vfsp->vfs_sync_work.w_syncer = vfs_sync_worker; |
| 615 | vfsp->vfs_sync_work.w_vfs = vfsp; | 605 | vfsp->vfs_sync_work.w_vfs = vfsp; |
| @@ -621,7 +611,7 @@ xfs_fs_start_syncd( | |||
| 621 | 611 | ||
| 622 | STATIC void | 612 | STATIC void |
| 623 | xfs_fs_stop_syncd( | 613 | xfs_fs_stop_syncd( |
| 624 | vfs_t *vfsp) | 614 | bhv_vfs_t *vfsp) |
| 625 | { | 615 | { |
| 626 | kthread_stop(vfsp->vfs_sync_task); | 616 | kthread_stop(vfsp->vfs_sync_task); |
| 627 | } | 617 | } |
| @@ -630,35 +620,26 @@ STATIC void | |||
| 630 | xfs_fs_put_super( | 620 | xfs_fs_put_super( |
| 631 | struct super_block *sb) | 621 | struct super_block *sb) |
| 632 | { | 622 | { |
| 633 | vfs_t *vfsp = vfs_from_sb(sb); | 623 | bhv_vfs_t *vfsp = vfs_from_sb(sb); |
| 634 | int error; | 624 | int error; |
| 635 | 625 | ||
| 636 | xfs_fs_stop_syncd(vfsp); | 626 | xfs_fs_stop_syncd(vfsp); |
| 637 | VFS_SYNC(vfsp, SYNC_ATTR|SYNC_DELWRI, NULL, error); | 627 | bhv_vfs_sync(vfsp, SYNC_ATTR | SYNC_DELWRI, NULL); |
| 638 | if (!error) | 628 | error = bhv_vfs_unmount(vfsp, 0, NULL); |
| 639 | VFS_UNMOUNT(vfsp, 0, NULL, error); | ||
| 640 | if (error) { | 629 | if (error) { |
| 641 | printk("XFS unmount got error %d\n", error); | 630 | printk("XFS: unmount got error=%d\n", error); |
| 642 | printk("%s: vfsp/0x%p left dangling!\n", __FUNCTION__, vfsp); | 631 | printk("%s: vfs=0x%p left dangling!\n", __FUNCTION__, vfsp); |
| 643 | return; | 632 | } else { |
| 633 | vfs_deallocate(vfsp); | ||
| 644 | } | 634 | } |
| 645 | |||
| 646 | vfs_deallocate(vfsp); | ||
| 647 | } | 635 | } |
| 648 | 636 | ||
| 649 | STATIC void | 637 | STATIC void |
| 650 | xfs_fs_write_super( | 638 | xfs_fs_write_super( |
| 651 | struct super_block *sb) | 639 | struct super_block *sb) |
| 652 | { | 640 | { |
| 653 | vfs_t *vfsp = vfs_from_sb(sb); | 641 | if (!(sb->s_flags & MS_RDONLY)) |
| 654 | int error; | 642 | bhv_vfs_sync(vfs_from_sb(sb), SYNC_FSDATA, NULL); |
| 655 | |||
| 656 | if (sb->s_flags & MS_RDONLY) { | ||
| 657 | sb->s_dirt = 0; /* paranoia */ | ||
| 658 | return; | ||
| 659 | } | ||
| 660 | /* Push the log and superblock a little */ | ||
| 661 | VFS_SYNC(vfsp, SYNC_FSDATA, NULL, error); | ||
| 662 | sb->s_dirt = 0; | 643 | sb->s_dirt = 0; |
| 663 | } | 644 | } |
| 664 | 645 | ||
| @@ -667,16 +648,16 @@ xfs_fs_sync_super( | |||
| 667 | struct super_block *sb, | 648 | struct super_block *sb, |
| 668 | int wait) | 649 | int wait) |
| 669 | { | 650 | { |
| 670 | vfs_t *vfsp = vfs_from_sb(sb); | 651 | bhv_vfs_t *vfsp = vfs_from_sb(sb); |
| 671 | int error; | 652 | int error; |
| 672 | int flags = SYNC_FSDATA; | 653 | int flags; |
| 673 | 654 | ||
| 674 | if (unlikely(sb->s_frozen == SB_FREEZE_WRITE)) | 655 | if (unlikely(sb->s_frozen == SB_FREEZE_WRITE)) |
| 675 | flags = SYNC_QUIESCE; | 656 | flags = SYNC_QUIESCE; |
| 676 | else | 657 | else |
| 677 | flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0); | 658 | flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0); |
| 678 | 659 | ||
| 679 | VFS_SYNC(vfsp, flags, NULL, error); | 660 | error = bhv_vfs_sync(vfsp, flags, NULL); |
| 680 | sb->s_dirt = 0; | 661 | sb->s_dirt = 0; |
| 681 | 662 | ||
| 682 | if (unlikely(laptop_mode)) { | 663 | if (unlikely(laptop_mode)) { |
| @@ -706,11 +687,7 @@ xfs_fs_statfs( | |||
| 706 | struct super_block *sb, | 687 | struct super_block *sb, |
| 707 | struct kstatfs *statp) | 688 | struct kstatfs *statp) |
| 708 | { | 689 | { |
| 709 | vfs_t *vfsp = vfs_from_sb(sb); | 690 | return -bhv_vfs_statvfs(vfs_from_sb(sb), statp, NULL); |
| 710 | int error; | ||
| 711 | |||
| 712 | VFS_STATVFS(vfsp, statp, NULL, error); | ||
| 713 | return -error; | ||
| 714 | } | 691 | } |
| 715 | 692 | ||
| 716 | STATIC int | 693 | STATIC int |
| @@ -719,13 +696,13 @@ xfs_fs_remount( | |||
| 719 | int *flags, | 696 | int *flags, |
| 720 | char *options) | 697 | char *options) |
| 721 | { | 698 | { |
| 722 | vfs_t *vfsp = vfs_from_sb(sb); | 699 | bhv_vfs_t *vfsp = vfs_from_sb(sb); |
| 723 | struct xfs_mount_args *args = xfs_args_allocate(sb, 0); | 700 | struct xfs_mount_args *args = xfs_args_allocate(sb, 0); |
| 724 | int error; | 701 | int error; |
| 725 | 702 | ||
| 726 | VFS_PARSEARGS(vfsp, options, args, 1, error); | 703 | error = bhv_vfs_parseargs(vfsp, options, args, 1); |
| 727 | if (!error) | 704 | if (!error) |
| 728 | VFS_MNTUPDATE(vfsp, flags, args, error); | 705 | error = bhv_vfs_mntupdate(vfsp, flags, args); |
| 729 | kmem_free(args, sizeof(*args)); | 706 | kmem_free(args, sizeof(*args)); |
| 730 | return -error; | 707 | return -error; |
| 731 | } | 708 | } |
| @@ -734,7 +711,7 @@ STATIC void | |||
| 734 | xfs_fs_lockfs( | 711 | xfs_fs_lockfs( |
| 735 | struct super_block *sb) | 712 | struct super_block *sb) |
| 736 | { | 713 | { |
| 737 | VFS_FREEZE(vfs_from_sb(sb)); | 714 | bhv_vfs_freeze(vfs_from_sb(sb)); |
| 738 | } | 715 | } |
| 739 | 716 | ||
| 740 | STATIC int | 717 | STATIC int |
| @@ -742,11 +719,7 @@ xfs_fs_show_options( | |||
| 742 | struct seq_file *m, | 719 | struct seq_file *m, |
| 743 | struct vfsmount *mnt) | 720 | struct vfsmount *mnt) |
| 744 | { | 721 | { |
| 745 | struct vfs *vfsp = vfs_from_sb(mnt->mnt_sb); | 722 | return -bhv_vfs_showargs(vfs_from_sb(mnt->mnt_sb), m); |
| 746 | int error; | ||
| 747 | |||
| 748 | VFS_SHOWARGS(vfsp, m, error); | ||
| 749 | return error; | ||
| 750 | } | 723 | } |
| 751 | 724 | ||
| 752 | STATIC int | 725 | STATIC int |
| @@ -754,11 +727,7 @@ xfs_fs_quotasync( | |||
| 754 | struct super_block *sb, | 727 | struct super_block *sb, |
| 755 | int type) | 728 | int type) |
| 756 | { | 729 | { |
| 757 | struct vfs *vfsp = vfs_from_sb(sb); | 730 | return -bhv_vfs_quotactl(vfs_from_sb(sb), Q_XQUOTASYNC, 0, NULL); |
| 758 | int error; | ||
| 759 | |||
| 760 | VFS_QUOTACTL(vfsp, Q_XQUOTASYNC, 0, (caddr_t)NULL, error); | ||
| 761 | return -error; | ||
| 762 | } | 731 | } |
| 763 | 732 | ||
| 764 | STATIC int | 733 | STATIC int |
| @@ -766,11 +735,7 @@ xfs_fs_getxstate( | |||
| 766 | struct super_block *sb, | 735 | struct super_block *sb, |
| 767 | struct fs_quota_stat *fqs) | 736 | struct fs_quota_stat *fqs) |
| 768 | { | 737 | { |
| 769 | struct vfs *vfsp = vfs_from_sb(sb); | 738 | return -bhv_vfs_quotactl(vfs_from_sb(sb), Q_XGETQSTAT, 0, (caddr_t)fqs); |
| 770 | int error; | ||
| 771 | |||
| 772 | VFS_QUOTACTL(vfsp, Q_XGETQSTAT, 0, (caddr_t)fqs, error); | ||
| 773 | return -error; | ||
| 774 | } | 739 | } |
| 775 | 740 | ||
| 776 | STATIC int | 741 | STATIC int |
| @@ -779,11 +744,7 @@ xfs_fs_setxstate( | |||
| 779 | unsigned int flags, | 744 | unsigned int flags, |
| 780 | int op) | 745 | int op) |
| 781 | { | 746 | { |
| 782 | struct vfs *vfsp = vfs_from_sb(sb); | 747 | return -bhv_vfs_quotactl(vfs_from_sb(sb), op, 0, (caddr_t)&flags); |
| 783 | int error; | ||
| 784 | |||
| 785 | VFS_QUOTACTL(vfsp, op, 0, (caddr_t)&flags, error); | ||
| 786 | return -error; | ||
| 787 | } | 748 | } |
| 788 | 749 | ||
| 789 | STATIC int | 750 | STATIC int |
| @@ -793,13 +754,10 @@ xfs_fs_getxquota( | |||
| 793 | qid_t id, | 754 | qid_t id, |
| 794 | struct fs_disk_quota *fdq) | 755 | struct fs_disk_quota *fdq) |
| 795 | { | 756 | { |
| 796 | struct vfs *vfsp = vfs_from_sb(sb); | 757 | return -bhv_vfs_quotactl(vfs_from_sb(sb), |
| 797 | int error, getmode; | 758 | (type == USRQUOTA) ? Q_XGETQUOTA : |
| 798 | 759 | ((type == GRPQUOTA) ? Q_XGETGQUOTA : | |
| 799 | getmode = (type == USRQUOTA) ? Q_XGETQUOTA : | 760 | Q_XGETPQUOTA), id, (caddr_t)fdq); |
| 800 | ((type == GRPQUOTA) ? Q_XGETGQUOTA : Q_XGETPQUOTA); | ||
| 801 | VFS_QUOTACTL(vfsp, getmode, id, (caddr_t)fdq, error); | ||
| 802 | return -error; | ||
| 803 | } | 761 | } |
| 804 | 762 | ||
| 805 | STATIC int | 763 | STATIC int |
| @@ -809,13 +767,10 @@ xfs_fs_setxquota( | |||
| 809 | qid_t id, | 767 | qid_t id, |
| 810 | struct fs_disk_quota *fdq) | 768 | struct fs_disk_quota *fdq) |
| 811 | { | 769 | { |
| 812 | struct vfs *vfsp = vfs_from_sb(sb); | 770 | return -bhv_vfs_quotactl(vfs_from_sb(sb), |
| 813 | int error, setmode; | 771 | (type == USRQUOTA) ? Q_XSETQLIM : |
| 814 | 772 | ((type == GRPQUOTA) ? Q_XSETGQLIM : | |
| 815 | setmode = (type == USRQUOTA) ? Q_XSETQLIM : | 773 | Q_XSETPQLIM), id, (caddr_t)fdq); |
| 816 | ((type == GRPQUOTA) ? Q_XSETGQLIM : Q_XSETPQLIM); | ||
| 817 | VFS_QUOTACTL(vfsp, setmode, id, (caddr_t)fdq, error); | ||
| 818 | return -error; | ||
| 819 | } | 774 | } |
| 820 | 775 | ||
| 821 | STATIC int | 776 | STATIC int |
| @@ -824,34 +779,32 @@ xfs_fs_fill_super( | |||
| 824 | void *data, | 779 | void *data, |
| 825 | int silent) | 780 | int silent) |
| 826 | { | 781 | { |
| 827 | vnode_t *rootvp; | 782 | struct bhv_vnode *rootvp; |
| 828 | struct vfs *vfsp = vfs_allocate(sb); | 783 | struct bhv_vfs *vfsp = vfs_allocate(sb); |
| 829 | struct xfs_mount_args *args = xfs_args_allocate(sb, silent); | 784 | struct xfs_mount_args *args = xfs_args_allocate(sb, silent); |
| 830 | struct kstatfs statvfs; | 785 | struct kstatfs statvfs; |
| 831 | int error, error2; | 786 | int error; |
| 832 | 787 | ||
| 833 | bhv_insert_all_vfsops(vfsp); | 788 | bhv_insert_all_vfsops(vfsp); |
| 834 | 789 | ||
| 835 | VFS_PARSEARGS(vfsp, (char *)data, args, 0, error); | 790 | error = bhv_vfs_parseargs(vfsp, (char *)data, args, 0); |
| 836 | if (error) { | 791 | if (error) { |
| 837 | bhv_remove_all_vfsops(vfsp, 1); | 792 | bhv_remove_all_vfsops(vfsp, 1); |
| 838 | goto fail_vfsop; | 793 | goto fail_vfsop; |
| 839 | } | 794 | } |
| 840 | 795 | ||
| 841 | sb_min_blocksize(sb, BBSIZE); | 796 | sb_min_blocksize(sb, BBSIZE); |
| 842 | #ifdef CONFIG_XFS_EXPORT | ||
| 843 | sb->s_export_op = &xfs_export_operations; | 797 | sb->s_export_op = &xfs_export_operations; |
| 844 | #endif | ||
| 845 | sb->s_qcop = &xfs_quotactl_operations; | 798 | sb->s_qcop = &xfs_quotactl_operations; |
| 846 | sb->s_op = &xfs_super_operations; | 799 | sb->s_op = &xfs_super_operations; |
| 847 | 800 | ||
| 848 | VFS_MOUNT(vfsp, args, NULL, error); | 801 | error = bhv_vfs_mount(vfsp, args, NULL); |
| 849 | if (error) { | 802 | if (error) { |
| 850 | bhv_remove_all_vfsops(vfsp, 1); | 803 | bhv_remove_all_vfsops(vfsp, 1); |
| 851 | goto fail_vfsop; | 804 | goto fail_vfsop; |
| 852 | } | 805 | } |
| 853 | 806 | ||
| 854 | VFS_STATVFS(vfsp, &statvfs, NULL, error); | 807 | error = bhv_vfs_statvfs(vfsp, &statvfs, NULL); |
| 855 | if (error) | 808 | if (error) |
| 856 | goto fail_unmount; | 809 | goto fail_unmount; |
| 857 | 810 | ||
| @@ -863,7 +816,7 @@ xfs_fs_fill_super( | |||
| 863 | sb->s_time_gran = 1; | 816 | sb->s_time_gran = 1; |
| 864 | set_posix_acl_flag(sb); | 817 | set_posix_acl_flag(sb); |
| 865 | 818 | ||
| 866 | VFS_ROOT(vfsp, &rootvp, error); | 819 | error = bhv_vfs_root(vfsp, &rootvp); |
| 867 | if (error) | 820 | if (error) |
| 868 | goto fail_unmount; | 821 | goto fail_unmount; |
| 869 | 822 | ||
| @@ -892,7 +845,7 @@ fail_vnrele: | |||
| 892 | } | 845 | } |
| 893 | 846 | ||
| 894 | fail_unmount: | 847 | fail_unmount: |
| 895 | VFS_UNMOUNT(vfsp, 0, NULL, error2); | 848 | bhv_vfs_unmount(vfsp, 0, NULL); |
| 896 | 849 | ||
| 897 | fail_vfsop: | 850 | fail_vfsop: |
| 898 | vfs_deallocate(vfsp); | 851 | vfs_deallocate(vfsp); |
diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h index 376b96cb513a..33dd1ca13245 100644 --- a/fs/xfs/linux-2.6/xfs_super.h +++ b/fs/xfs/linux-2.6/xfs_super.h | |||
| @@ -105,7 +105,7 @@ struct block_device; | |||
| 105 | 105 | ||
| 106 | extern __uint64_t xfs_max_file_offset(unsigned int); | 106 | extern __uint64_t xfs_max_file_offset(unsigned int); |
| 107 | 107 | ||
| 108 | extern void xfs_initialize_vnode(bhv_desc_t *, vnode_t *, bhv_desc_t *, int); | 108 | extern void xfs_initialize_vnode(bhv_desc_t *, bhv_vnode_t *, bhv_desc_t *, int); |
| 109 | 109 | ||
| 110 | extern void xfs_flush_inode(struct xfs_inode *); | 110 | extern void xfs_flush_inode(struct xfs_inode *); |
| 111 | extern void xfs_flush_device(struct xfs_inode *); | 111 | extern void xfs_flush_device(struct xfs_inode *); |
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c index 7079cc837210..4af97682bec8 100644 --- a/fs/xfs/linux-2.6/xfs_sysctl.c +++ b/fs/xfs/linux-2.6/xfs_sysctl.c | |||
| @@ -120,6 +120,11 @@ STATIC ctl_table xfs_table[] = { | |||
| 120 | &sysctl_intvec, NULL, | 120 | &sysctl_intvec, NULL, |
| 121 | &xfs_params.rotorstep.min, &xfs_params.rotorstep.max}, | 121 | &xfs_params.rotorstep.min, &xfs_params.rotorstep.max}, |
| 122 | 122 | ||
| 123 | {XFS_INHERIT_NODFRG, "inherit_nodefrag", &xfs_params.inherit_nodfrg.val, | ||
| 124 | sizeof(int), 0644, NULL, &proc_dointvec_minmax, | ||
| 125 | &sysctl_intvec, NULL, | ||
| 126 | &xfs_params.inherit_nodfrg.min, &xfs_params.inherit_nodfrg.max}, | ||
| 127 | |||
| 123 | /* please keep this the last entry */ | 128 | /* please keep this the last entry */ |
| 124 | #ifdef CONFIG_PROC_FS | 129 | #ifdef CONFIG_PROC_FS |
| 125 | {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val, | 130 | {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val, |
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.h b/fs/xfs/linux-2.6/xfs_sysctl.h index bc8c11f13722..a631fb8cc5ac 100644 --- a/fs/xfs/linux-2.6/xfs_sysctl.h +++ b/fs/xfs/linux-2.6/xfs_sysctl.h | |||
| @@ -46,6 +46,7 @@ typedef struct xfs_param { | |||
| 46 | xfs_sysctl_val_t xfs_buf_age; /* Metadata buffer age before flush. */ | 46 | xfs_sysctl_val_t xfs_buf_age; /* Metadata buffer age before flush. */ |
| 47 | xfs_sysctl_val_t inherit_nosym; /* Inherit the "nosymlinks" flag. */ | 47 | xfs_sysctl_val_t inherit_nosym; /* Inherit the "nosymlinks" flag. */ |
| 48 | xfs_sysctl_val_t rotorstep; /* inode32 AG rotoring control knob */ | 48 | xfs_sysctl_val_t rotorstep; /* inode32 AG rotoring control knob */ |
| 49 | xfs_sysctl_val_t inherit_nodfrg;/* Inherit the "nodefrag" inode flag. */ | ||
| 49 | } xfs_param_t; | 50 | } xfs_param_t; |
| 50 | 51 | ||
| 51 | /* | 52 | /* |
| @@ -84,6 +85,7 @@ enum { | |||
| 84 | /* XFS_IO_BYPASS = 18 */ | 85 | /* XFS_IO_BYPASS = 18 */ |
| 85 | XFS_INHERIT_NOSYM = 19, | 86 | XFS_INHERIT_NOSYM = 19, |
| 86 | XFS_ROTORSTEP = 20, | 87 | XFS_ROTORSTEP = 20, |
| 88 | XFS_INHERIT_NODFRG = 21, | ||
| 87 | }; | 89 | }; |
| 88 | 90 | ||
| 89 | extern xfs_param_t xfs_params; | 91 | extern xfs_param_t xfs_params; |
diff --git a/fs/xfs/linux-2.6/xfs_vfs.c b/fs/xfs/linux-2.6/xfs_vfs.c index 6f7c9f7a8624..6145e8bd0be2 100644 --- a/fs/xfs/linux-2.6/xfs_vfs.c +++ b/fs/xfs/linux-2.6/xfs_vfs.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_imap.h" | 27 | #include "xfs_imap.h" |
| 29 | #include "xfs_alloc.h" | 28 | #include "xfs_alloc.h" |
| @@ -104,7 +103,7 @@ vfs_mntupdate( | |||
| 104 | int | 103 | int |
| 105 | vfs_root( | 104 | vfs_root( |
| 106 | struct bhv_desc *bdp, | 105 | struct bhv_desc *bdp, |
| 107 | struct vnode **vpp) | 106 | struct bhv_vnode **vpp) |
| 108 | { | 107 | { |
| 109 | struct bhv_desc *next = bdp; | 108 | struct bhv_desc *next = bdp; |
| 110 | 109 | ||
| @@ -117,15 +116,15 @@ vfs_root( | |||
| 117 | int | 116 | int |
| 118 | vfs_statvfs( | 117 | vfs_statvfs( |
| 119 | struct bhv_desc *bdp, | 118 | struct bhv_desc *bdp, |
| 120 | xfs_statfs_t *sp, | 119 | bhv_statvfs_t *statp, |
| 121 | struct vnode *vp) | 120 | struct bhv_vnode *vp) |
| 122 | { | 121 | { |
| 123 | struct bhv_desc *next = bdp; | 122 | struct bhv_desc *next = bdp; |
| 124 | 123 | ||
| 125 | ASSERT(next); | 124 | ASSERT(next); |
| 126 | while (! (bhvtovfsops(next))->vfs_statvfs) | 125 | while (! (bhvtovfsops(next))->vfs_statvfs) |
| 127 | next = BHV_NEXT(next); | 126 | next = BHV_NEXT(next); |
| 128 | return ((*bhvtovfsops(next)->vfs_statvfs)(next, sp, vp)); | 127 | return ((*bhvtovfsops(next)->vfs_statvfs)(next, statp, vp)); |
| 129 | } | 128 | } |
| 130 | 129 | ||
| 131 | int | 130 | int |
| @@ -145,7 +144,7 @@ vfs_sync( | |||
| 145 | int | 144 | int |
| 146 | vfs_vget( | 145 | vfs_vget( |
| 147 | struct bhv_desc *bdp, | 146 | struct bhv_desc *bdp, |
| 148 | struct vnode **vpp, | 147 | struct bhv_vnode **vpp, |
| 149 | struct fid *fidp) | 148 | struct fid *fidp) |
| 150 | { | 149 | { |
| 151 | struct bhv_desc *next = bdp; | 150 | struct bhv_desc *next = bdp; |
| @@ -187,7 +186,7 @@ vfs_quotactl( | |||
| 187 | void | 186 | void |
| 188 | vfs_init_vnode( | 187 | vfs_init_vnode( |
| 189 | struct bhv_desc *bdp, | 188 | struct bhv_desc *bdp, |
| 190 | struct vnode *vp, | 189 | struct bhv_vnode *vp, |
| 191 | struct bhv_desc *bp, | 190 | struct bhv_desc *bp, |
| 192 | int unlock) | 191 | int unlock) |
| 193 | { | 192 | { |
| @@ -226,13 +225,13 @@ vfs_freeze( | |||
| 226 | ((*bhvtovfsops(next)->vfs_freeze)(next)); | 225 | ((*bhvtovfsops(next)->vfs_freeze)(next)); |
| 227 | } | 226 | } |
| 228 | 227 | ||
| 229 | vfs_t * | 228 | bhv_vfs_t * |
| 230 | vfs_allocate( | 229 | vfs_allocate( |
| 231 | struct super_block *sb) | 230 | struct super_block *sb) |
| 232 | { | 231 | { |
| 233 | struct vfs *vfsp; | 232 | struct bhv_vfs *vfsp; |
| 234 | 233 | ||
| 235 | vfsp = kmem_zalloc(sizeof(vfs_t), KM_SLEEP); | 234 | vfsp = kmem_zalloc(sizeof(bhv_vfs_t), KM_SLEEP); |
| 236 | bhv_head_init(VFS_BHVHEAD(vfsp), "vfs"); | 235 | bhv_head_init(VFS_BHVHEAD(vfsp), "vfs"); |
| 237 | INIT_LIST_HEAD(&vfsp->vfs_sync_list); | 236 | INIT_LIST_HEAD(&vfsp->vfs_sync_list); |
| 238 | spin_lock_init(&vfsp->vfs_sync_lock); | 237 | spin_lock_init(&vfsp->vfs_sync_lock); |
| @@ -247,25 +246,25 @@ vfs_allocate( | |||
| 247 | return vfsp; | 246 | return vfsp; |
| 248 | } | 247 | } |
| 249 | 248 | ||
| 250 | vfs_t * | 249 | bhv_vfs_t * |
| 251 | vfs_from_sb( | 250 | vfs_from_sb( |
| 252 | struct super_block *sb) | 251 | struct super_block *sb) |
| 253 | { | 252 | { |
| 254 | return (vfs_t *)sb->s_fs_info; | 253 | return (bhv_vfs_t *)sb->s_fs_info; |
| 255 | } | 254 | } |
| 256 | 255 | ||
| 257 | void | 256 | void |
| 258 | vfs_deallocate( | 257 | vfs_deallocate( |
| 259 | struct vfs *vfsp) | 258 | struct bhv_vfs *vfsp) |
| 260 | { | 259 | { |
| 261 | bhv_head_destroy(VFS_BHVHEAD(vfsp)); | 260 | bhv_head_destroy(VFS_BHVHEAD(vfsp)); |
| 262 | kmem_free(vfsp, sizeof(vfs_t)); | 261 | kmem_free(vfsp, sizeof(bhv_vfs_t)); |
| 263 | } | 262 | } |
| 264 | 263 | ||
| 265 | void | 264 | void |
| 266 | vfs_insertops( | 265 | vfs_insertops( |
| 267 | struct vfs *vfsp, | 266 | struct bhv_vfs *vfsp, |
| 268 | struct bhv_vfsops *vfsops) | 267 | struct bhv_module_vfsops *vfsops) |
| 269 | { | 268 | { |
| 270 | struct bhv_desc *bdp; | 269 | struct bhv_desc *bdp; |
| 271 | 270 | ||
| @@ -276,9 +275,9 @@ vfs_insertops( | |||
| 276 | 275 | ||
| 277 | void | 276 | void |
| 278 | vfs_insertbhv( | 277 | vfs_insertbhv( |
| 279 | struct vfs *vfsp, | 278 | struct bhv_vfs *vfsp, |
| 280 | struct bhv_desc *bdp, | 279 | struct bhv_desc *bdp, |
| 281 | struct vfsops *vfsops, | 280 | struct bhv_vfsops *vfsops, |
| 282 | void *mount) | 281 | void *mount) |
| 283 | { | 282 | { |
| 284 | bhv_desc_init(bdp, mount, vfsp, vfsops); | 283 | bhv_desc_init(bdp, mount, vfsp, vfsops); |
| @@ -287,7 +286,7 @@ vfs_insertbhv( | |||
| 287 | 286 | ||
| 288 | void | 287 | void |
| 289 | bhv_remove_vfsops( | 288 | bhv_remove_vfsops( |
| 290 | struct vfs *vfsp, | 289 | struct bhv_vfs *vfsp, |
| 291 | int pos) | 290 | int pos) |
| 292 | { | 291 | { |
| 293 | struct bhv_desc *bhv; | 292 | struct bhv_desc *bhv; |
| @@ -301,7 +300,7 @@ bhv_remove_vfsops( | |||
| 301 | 300 | ||
| 302 | void | 301 | void |
| 303 | bhv_remove_all_vfsops( | 302 | bhv_remove_all_vfsops( |
| 304 | struct vfs *vfsp, | 303 | struct bhv_vfs *vfsp, |
| 305 | int freebase) | 304 | int freebase) |
| 306 | { | 305 | { |
| 307 | struct xfs_mount *mp; | 306 | struct xfs_mount *mp; |
| @@ -317,7 +316,7 @@ bhv_remove_all_vfsops( | |||
| 317 | 316 | ||
| 318 | void | 317 | void |
| 319 | bhv_insert_all_vfsops( | 318 | bhv_insert_all_vfsops( |
| 320 | struct vfs *vfsp) | 319 | struct bhv_vfs *vfsp) |
| 321 | { | 320 | { |
| 322 | struct xfs_mount *mp; | 321 | struct xfs_mount *mp; |
| 323 | 322 | ||
diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h index 841200c03092..91fc2c4b3353 100644 --- a/fs/xfs/linux-2.6/xfs_vfs.h +++ b/fs/xfs/linux-2.6/xfs_vfs.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -21,42 +21,40 @@ | |||
| 21 | #include <linux/vfs.h> | 21 | #include <linux/vfs.h> |
| 22 | #include "xfs_fs.h" | 22 | #include "xfs_fs.h" |
| 23 | 23 | ||
| 24 | struct bhv_vfs; | ||
| 25 | struct bhv_vnode; | ||
| 26 | |||
| 24 | struct fid; | 27 | struct fid; |
| 25 | struct vfs; | ||
| 26 | struct cred; | 28 | struct cred; |
| 27 | struct vnode; | ||
| 28 | struct kstatfs; | ||
| 29 | struct seq_file; | 29 | struct seq_file; |
| 30 | struct super_block; | 30 | struct super_block; |
| 31 | struct xfs_mount_args; | 31 | struct xfs_mount_args; |
| 32 | 32 | ||
| 33 | typedef struct kstatfs xfs_statfs_t; | 33 | typedef struct kstatfs bhv_statvfs_t; |
| 34 | 34 | ||
| 35 | typedef struct vfs_sync_work { | 35 | typedef struct bhv_vfs_sync_work { |
| 36 | struct list_head w_list; | 36 | struct list_head w_list; |
| 37 | struct vfs *w_vfs; | 37 | struct bhv_vfs *w_vfs; |
| 38 | void *w_data; /* syncer routine argument */ | 38 | void *w_data; /* syncer routine argument */ |
| 39 | void (*w_syncer)(struct vfs *, void *); | 39 | void (*w_syncer)(struct bhv_vfs *, void *); |
| 40 | } vfs_sync_work_t; | 40 | } bhv_vfs_sync_work_t; |
| 41 | 41 | ||
| 42 | typedef struct vfs { | 42 | typedef struct bhv_vfs { |
| 43 | u_int vfs_flag; /* flags */ | 43 | u_int vfs_flag; /* flags */ |
| 44 | xfs_fsid_t vfs_fsid; /* file system ID */ | 44 | xfs_fsid_t vfs_fsid; /* file system ID */ |
| 45 | xfs_fsid_t *vfs_altfsid; /* An ID fixed for life of FS */ | 45 | xfs_fsid_t *vfs_altfsid; /* An ID fixed for life of FS */ |
| 46 | bhv_head_t vfs_bh; /* head of vfs behavior chain */ | 46 | bhv_head_t vfs_bh; /* head of vfs behavior chain */ |
| 47 | struct super_block *vfs_super; /* generic superblock pointer */ | 47 | struct super_block *vfs_super; /* generic superblock pointer */ |
| 48 | struct task_struct *vfs_sync_task; /* generalised sync thread */ | 48 | struct task_struct *vfs_sync_task; /* generalised sync thread */ |
| 49 | vfs_sync_work_t vfs_sync_work; /* work item for VFS_SYNC */ | 49 | bhv_vfs_sync_work_t vfs_sync_work; /* work item for VFS_SYNC */ |
| 50 | struct list_head vfs_sync_list; /* sync thread work item list */ | 50 | struct list_head vfs_sync_list; /* sync thread work item list */ |
| 51 | spinlock_t vfs_sync_lock; /* work item list lock */ | 51 | spinlock_t vfs_sync_lock; /* work item list lock */ |
| 52 | int vfs_sync_seq; /* sync thread generation no. */ | 52 | int vfs_sync_seq; /* sync thread generation no. */ |
| 53 | wait_queue_head_t vfs_wait_single_sync_task; | 53 | wait_queue_head_t vfs_wait_single_sync_task; |
| 54 | } vfs_t; | 54 | } bhv_vfs_t; |
| 55 | |||
| 56 | #define vfs_fbhv vfs_bh.bh_first /* 1st on vfs behavior chain */ | ||
| 57 | 55 | ||
| 58 | #define bhvtovfs(bdp) ( (struct vfs *)BHV_VOBJ(bdp) ) | 56 | #define bhvtovfs(bdp) ( (struct bhv_vfs *)BHV_VOBJ(bdp) ) |
| 59 | #define bhvtovfsops(bdp) ( (struct vfsops *)BHV_OPS(bdp) ) | 57 | #define bhvtovfsops(bdp) ( (struct bhv_vfsops *)BHV_OPS(bdp) ) |
| 60 | #define VFS_BHVHEAD(vfs) ( &(vfs)->vfs_bh ) | 58 | #define VFS_BHVHEAD(vfs) ( &(vfs)->vfs_bh ) |
| 61 | #define VFS_REMOVEBHV(vfs, bdp) ( bhv_remove(VFS_BHVHEAD(vfs), bdp) ) | 59 | #define VFS_REMOVEBHV(vfs, bdp) ( bhv_remove(VFS_BHVHEAD(vfs), bdp) ) |
| 62 | 60 | ||
| @@ -71,7 +69,7 @@ typedef enum { | |||
| 71 | VFS_BHV_QM, /* quota manager */ | 69 | VFS_BHV_QM, /* quota manager */ |
| 72 | VFS_BHV_IO, /* IO path */ | 70 | VFS_BHV_IO, /* IO path */ |
| 73 | VFS_BHV_END /* housekeeping end-of-range */ | 71 | VFS_BHV_END /* housekeeping end-of-range */ |
| 74 | } vfs_bhv_t; | 72 | } bhv_vfs_type_t; |
| 75 | 73 | ||
| 76 | #define VFS_POSITION_XFS (BHV_POSITION_BASE) | 74 | #define VFS_POSITION_XFS (BHV_POSITION_BASE) |
| 77 | #define VFS_POSITION_DM (VFS_POSITION_BASE+10) | 75 | #define VFS_POSITION_DM (VFS_POSITION_BASE+10) |
| @@ -81,8 +79,9 @@ typedef enum { | |||
| 81 | #define VFS_RDONLY 0x0001 /* read-only vfs */ | 79 | #define VFS_RDONLY 0x0001 /* read-only vfs */ |
| 82 | #define VFS_GRPID 0x0002 /* group-ID assigned from directory */ | 80 | #define VFS_GRPID 0x0002 /* group-ID assigned from directory */ |
| 83 | #define VFS_DMI 0x0004 /* filesystem has the DMI enabled */ | 81 | #define VFS_DMI 0x0004 /* filesystem has the DMI enabled */ |
| 84 | #define VFS_32BITINODES 0x0008 /* do not use inums above 32 bits */ | 82 | #define VFS_UMOUNT 0x0008 /* unmount in progress */ |
| 85 | #define VFS_END 0x0008 /* max flag */ | 83 | #define VFS_32BITINODES 0x0010 /* do not use inums above 32 bits */ |
| 84 | #define VFS_END 0x0010 /* max flag */ | ||
| 86 | 85 | ||
| 87 | #define SYNC_ATTR 0x0001 /* sync attributes */ | 86 | #define SYNC_ATTR 0x0001 /* sync attributes */ |
| 88 | #define SYNC_CLOSE 0x0002 /* close file system down */ | 87 | #define SYNC_CLOSE 0x0002 /* close file system down */ |
| @@ -92,7 +91,14 @@ typedef enum { | |||
| 92 | #define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */ | 91 | #define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */ |
| 93 | #define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */ | 92 | #define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */ |
| 94 | #define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */ | 93 | #define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */ |
| 95 | #define SYNC_QUIESCE 0x0100 /* quiesce filesystem for a snapshot */ | 94 | #define SYNC_QUIESCE 0x0100 /* quiesce fileystem for a snapshot */ |
| 95 | |||
| 96 | #define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */ | ||
| 97 | #define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */ | ||
| 98 | #define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */ | ||
| 99 | #define SHUTDOWN_CORRUPT_INCORE 0x0008 /* corrupt in-memory data structures */ | ||
| 100 | #define SHUTDOWN_REMOTE_REQ 0x0010 /* shutdown came from remote cell */ | ||
| 101 | #define SHUTDOWN_DEVICE_REQ 0x0020 /* failed all paths to the device */ | ||
| 96 | 102 | ||
| 97 | typedef int (*vfs_mount_t)(bhv_desc_t *, | 103 | typedef int (*vfs_mount_t)(bhv_desc_t *, |
| 98 | struct xfs_mount_args *, struct cred *); | 104 | struct xfs_mount_args *, struct cred *); |
| @@ -102,18 +108,19 @@ typedef int (*vfs_showargs_t)(bhv_desc_t *, struct seq_file *); | |||
| 102 | typedef int (*vfs_unmount_t)(bhv_desc_t *, int, struct cred *); | 108 | typedef int (*vfs_unmount_t)(bhv_desc_t *, int, struct cred *); |
| 103 | typedef int (*vfs_mntupdate_t)(bhv_desc_t *, int *, | 109 | typedef int (*vfs_mntupdate_t)(bhv_desc_t *, int *, |
| 104 | struct xfs_mount_args *); | 110 | struct xfs_mount_args *); |
| 105 | typedef int (*vfs_root_t)(bhv_desc_t *, struct vnode **); | 111 | typedef int (*vfs_root_t)(bhv_desc_t *, struct bhv_vnode **); |
| 106 | typedef int (*vfs_statvfs_t)(bhv_desc_t *, xfs_statfs_t *, struct vnode *); | 112 | typedef int (*vfs_statvfs_t)(bhv_desc_t *, bhv_statvfs_t *, |
| 113 | struct bhv_vnode *); | ||
| 107 | typedef int (*vfs_sync_t)(bhv_desc_t *, int, struct cred *); | 114 | typedef int (*vfs_sync_t)(bhv_desc_t *, int, struct cred *); |
| 108 | typedef int (*vfs_vget_t)(bhv_desc_t *, struct vnode **, struct fid *); | 115 | typedef int (*vfs_vget_t)(bhv_desc_t *, struct bhv_vnode **, struct fid *); |
| 109 | typedef int (*vfs_dmapiops_t)(bhv_desc_t *, caddr_t); | 116 | typedef int (*vfs_dmapiops_t)(bhv_desc_t *, caddr_t); |
| 110 | typedef int (*vfs_quotactl_t)(bhv_desc_t *, int, int, caddr_t); | 117 | typedef int (*vfs_quotactl_t)(bhv_desc_t *, int, int, caddr_t); |
| 111 | typedef void (*vfs_init_vnode_t)(bhv_desc_t *, | 118 | typedef void (*vfs_init_vnode_t)(bhv_desc_t *, |
| 112 | struct vnode *, bhv_desc_t *, int); | 119 | struct bhv_vnode *, bhv_desc_t *, int); |
| 113 | typedef void (*vfs_force_shutdown_t)(bhv_desc_t *, int, char *, int); | 120 | typedef void (*vfs_force_shutdown_t)(bhv_desc_t *, int, char *, int); |
| 114 | typedef void (*vfs_freeze_t)(bhv_desc_t *); | 121 | typedef void (*vfs_freeze_t)(bhv_desc_t *); |
| 115 | 122 | ||
| 116 | typedef struct vfsops { | 123 | typedef struct bhv_vfsops { |
| 117 | bhv_position_t vf_position; /* behavior chain position */ | 124 | bhv_position_t vf_position; /* behavior chain position */ |
| 118 | vfs_mount_t vfs_mount; /* mount file system */ | 125 | vfs_mount_t vfs_mount; /* mount file system */ |
| 119 | vfs_parseargs_t vfs_parseargs; /* parse mount options */ | 126 | vfs_parseargs_t vfs_parseargs; /* parse mount options */ |
| @@ -129,82 +136,82 @@ typedef struct vfsops { | |||
| 129 | vfs_init_vnode_t vfs_init_vnode; /* initialize a new vnode */ | 136 | vfs_init_vnode_t vfs_init_vnode; /* initialize a new vnode */ |
| 130 | vfs_force_shutdown_t vfs_force_shutdown; /* crash and burn */ | 137 | vfs_force_shutdown_t vfs_force_shutdown; /* crash and burn */ |
| 131 | vfs_freeze_t vfs_freeze; /* freeze fs for snapshot */ | 138 | vfs_freeze_t vfs_freeze; /* freeze fs for snapshot */ |
| 132 | } vfsops_t; | 139 | } bhv_vfsops_t; |
| 133 | 140 | ||
| 134 | /* | 141 | /* |
| 135 | * VFS's. Operates on vfs structure pointers (starts at bhv head). | 142 | * Virtual filesystem operations, operating from head bhv. |
| 136 | */ | 143 | */ |
| 137 | #define VHEAD(v) ((v)->vfs_fbhv) | 144 | #define VFSHEAD(v) ((v)->vfs_bh.bh_first) |
| 138 | #define VFS_MOUNT(v, ma,cr, rv) ((rv) = vfs_mount(VHEAD(v), ma,cr)) | 145 | #define bhv_vfs_mount(v, ma,cr) vfs_mount(VFSHEAD(v), ma,cr) |
| 139 | #define VFS_PARSEARGS(v, o,ma,f, rv) ((rv) = vfs_parseargs(VHEAD(v), o,ma,f)) | 146 | #define bhv_vfs_parseargs(v, o,ma,f) vfs_parseargs(VFSHEAD(v), o,ma,f) |
| 140 | #define VFS_SHOWARGS(v, m, rv) ((rv) = vfs_showargs(VHEAD(v), m)) | 147 | #define bhv_vfs_showargs(v, m) vfs_showargs(VFSHEAD(v), m) |
| 141 | #define VFS_UNMOUNT(v, f, cr, rv) ((rv) = vfs_unmount(VHEAD(v), f,cr)) | 148 | #define bhv_vfs_unmount(v, f,cr) vfs_unmount(VFSHEAD(v), f,cr) |
| 142 | #define VFS_MNTUPDATE(v, fl, args, rv) ((rv) = vfs_mntupdate(VHEAD(v), fl, args)) | 149 | #define bhv_vfs_mntupdate(v, fl,args) vfs_mntupdate(VFSHEAD(v), fl,args) |
| 143 | #define VFS_ROOT(v, vpp, rv) ((rv) = vfs_root(VHEAD(v), vpp)) | 150 | #define bhv_vfs_root(v, vpp) vfs_root(VFSHEAD(v), vpp) |
| 144 | #define VFS_STATVFS(v, sp,vp, rv) ((rv) = vfs_statvfs(VHEAD(v), sp,vp)) | 151 | #define bhv_vfs_statvfs(v, sp,vp) vfs_statvfs(VFSHEAD(v), sp,vp) |
| 145 | #define VFS_SYNC(v, flag,cr, rv) ((rv) = vfs_sync(VHEAD(v), flag,cr)) | 152 | #define bhv_vfs_sync(v, flag,cr) vfs_sync(VFSHEAD(v), flag,cr) |
| 146 | #define VFS_VGET(v, vpp,fidp, rv) ((rv) = vfs_vget(VHEAD(v), vpp,fidp)) | 153 | #define bhv_vfs_vget(v, vpp,fidp) vfs_vget(VFSHEAD(v), vpp,fidp) |
| 147 | #define VFS_DMAPIOPS(v, p, rv) ((rv) = vfs_dmapiops(VHEAD(v), p)) | 154 | #define bhv_vfs_dmapiops(v, p) vfs_dmapiops(VFSHEAD(v), p) |
| 148 | #define VFS_QUOTACTL(v, c,id,p, rv) ((rv) = vfs_quotactl(VHEAD(v), c,id,p)) | 155 | #define bhv_vfs_quotactl(v, c,id,p) vfs_quotactl(VFSHEAD(v), c,id,p) |
| 149 | #define VFS_INIT_VNODE(v, vp,b,ul) ( vfs_init_vnode(VHEAD(v), vp,b,ul) ) | 156 | #define bhv_vfs_init_vnode(v, vp,b,ul) vfs_init_vnode(VFSHEAD(v), vp,b,ul) |
| 150 | #define VFS_FORCE_SHUTDOWN(v, fl,f,l) ( vfs_force_shutdown(VHEAD(v), fl,f,l) ) | 157 | #define bhv_vfs_force_shutdown(v,u,f,l) vfs_force_shutdown(VFSHEAD(v), u,f,l) |
| 151 | #define VFS_FREEZE(v) ( vfs_freeze(VHEAD(v)) ) | 158 | #define bhv_vfs_freeze(v) vfs_freeze(VFSHEAD(v)) |
| 152 | 159 | ||
| 153 | /* | 160 | /* |
| 154 | * PVFS's. Operates on behavior descriptor pointers. | 161 | * Virtual filesystem operations, operating from next bhv. |
| 155 | */ | 162 | */ |
| 156 | #define PVFS_MOUNT(b, ma,cr, rv) ((rv) = vfs_mount(b, ma,cr)) | 163 | #define bhv_next_vfs_mount(b, ma,cr) vfs_mount(b, ma,cr) |
| 157 | #define PVFS_PARSEARGS(b, o,ma,f, rv) ((rv) = vfs_parseargs(b, o,ma,f)) | 164 | #define bhv_next_vfs_parseargs(b, o,ma,f) vfs_parseargs(b, o,ma,f) |
| 158 | #define PVFS_SHOWARGS(b, m, rv) ((rv) = vfs_showargs(b, m)) | 165 | #define bhv_next_vfs_showargs(b, m) vfs_showargs(b, m) |
| 159 | #define PVFS_UNMOUNT(b, f,cr, rv) ((rv) = vfs_unmount(b, f,cr)) | 166 | #define bhv_next_vfs_unmount(b, f,cr) vfs_unmount(b, f,cr) |
| 160 | #define PVFS_MNTUPDATE(b, fl, args, rv) ((rv) = vfs_mntupdate(b, fl, args)) | 167 | #define bhv_next_vfs_mntupdate(b, fl,args) vfs_mntupdate(b, fl, args) |
| 161 | #define PVFS_ROOT(b, vpp, rv) ((rv) = vfs_root(b, vpp)) | 168 | #define bhv_next_vfs_root(b, vpp) vfs_root(b, vpp) |
| 162 | #define PVFS_STATVFS(b, sp,vp, rv) ((rv) = vfs_statvfs(b, sp,vp)) | 169 | #define bhv_next_vfs_statvfs(b, sp,vp) vfs_statvfs(b, sp,vp) |
| 163 | #define PVFS_SYNC(b, flag,cr, rv) ((rv) = vfs_sync(b, flag,cr)) | 170 | #define bhv_next_vfs_sync(b, flag,cr) vfs_sync(b, flag,cr) |
| 164 | #define PVFS_VGET(b, vpp,fidp, rv) ((rv) = vfs_vget(b, vpp,fidp)) | 171 | #define bhv_next_vfs_vget(b, vpp,fidp) vfs_vget(b, vpp,fidp) |
| 165 | #define PVFS_DMAPIOPS(b, p, rv) ((rv) = vfs_dmapiops(b, p)) | 172 | #define bhv_next_vfs_dmapiops(b, p) vfs_dmapiops(b, p) |
| 166 | #define PVFS_QUOTACTL(b, c,id,p, rv) ((rv) = vfs_quotactl(b, c,id,p)) | 173 | #define bhv_next_vfs_quotactl(b, c,id,p) vfs_quotactl(b, c,id,p) |
| 167 | #define PVFS_INIT_VNODE(b, vp,b2,ul) ( vfs_init_vnode(b, vp,b2,ul) ) | 174 | #define bhv_next_vfs_init_vnode(b, vp,b2,ul) vfs_init_vnode(b, vp,b2,ul) |
| 168 | #define PVFS_FORCE_SHUTDOWN(b, fl,f,l) ( vfs_force_shutdown(b, fl,f,l) ) | 175 | #define bhv_next_force_shutdown(b, fl,f,l) vfs_force_shutdown(b, fl,f,l) |
| 169 | #define PVFS_FREEZE(b) ( vfs_freeze(b) ) | 176 | #define bhv_next_vfs_freeze(b) vfs_freeze(b) |
| 170 | 177 | ||
| 171 | extern int vfs_mount(bhv_desc_t *, struct xfs_mount_args *, struct cred *); | 178 | extern int vfs_mount(bhv_desc_t *, struct xfs_mount_args *, struct cred *); |
| 172 | extern int vfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int); | 179 | extern int vfs_parseargs(bhv_desc_t *, char *, struct xfs_mount_args *, int); |
| 173 | extern int vfs_showargs(bhv_desc_t *, struct seq_file *); | 180 | extern int vfs_showargs(bhv_desc_t *, struct seq_file *); |
| 174 | extern int vfs_unmount(bhv_desc_t *, int, struct cred *); | 181 | extern int vfs_unmount(bhv_desc_t *, int, struct cred *); |
| 175 | extern int vfs_mntupdate(bhv_desc_t *, int *, struct xfs_mount_args *); | 182 | extern int vfs_mntupdate(bhv_desc_t *, int *, struct xfs_mount_args *); |
| 176 | extern int vfs_root(bhv_desc_t *, struct vnode **); | 183 | extern int vfs_root(bhv_desc_t *, struct bhv_vnode **); |
| 177 | extern int vfs_statvfs(bhv_desc_t *, xfs_statfs_t *, struct vnode *); | 184 | extern int vfs_statvfs(bhv_desc_t *, bhv_statvfs_t *, struct bhv_vnode *); |
| 178 | extern int vfs_sync(bhv_desc_t *, int, struct cred *); | 185 | extern int vfs_sync(bhv_desc_t *, int, struct cred *); |
| 179 | extern int vfs_vget(bhv_desc_t *, struct vnode **, struct fid *); | 186 | extern int vfs_vget(bhv_desc_t *, struct bhv_vnode **, struct fid *); |
| 180 | extern int vfs_dmapiops(bhv_desc_t *, caddr_t); | 187 | extern int vfs_dmapiops(bhv_desc_t *, caddr_t); |
| 181 | extern int vfs_quotactl(bhv_desc_t *, int, int, caddr_t); | 188 | extern int vfs_quotactl(bhv_desc_t *, int, int, caddr_t); |
| 182 | extern void vfs_init_vnode(bhv_desc_t *, struct vnode *, bhv_desc_t *, int); | 189 | extern void vfs_init_vnode(bhv_desc_t *, struct bhv_vnode *, bhv_desc_t *, int); |
| 183 | extern void vfs_force_shutdown(bhv_desc_t *, int, char *, int); | 190 | extern void vfs_force_shutdown(bhv_desc_t *, int, char *, int); |
| 184 | extern void vfs_freeze(bhv_desc_t *); | 191 | extern void vfs_freeze(bhv_desc_t *); |
| 185 | 192 | ||
| 186 | typedef struct bhv_vfsops { | 193 | #define vfs_test_for_freeze(vfs) ((vfs)->vfs_super->s_frozen) |
| 187 | struct vfsops bhv_common; | 194 | #define vfs_wait_for_freeze(vfs,l) vfs_check_frozen((vfs)->vfs_super, (l)) |
| 195 | |||
| 196 | typedef struct bhv_module_vfsops { | ||
| 197 | struct bhv_vfsops bhv_common; | ||
| 188 | void * bhv_custom; | 198 | void * bhv_custom; |
| 189 | } bhv_vfsops_t; | 199 | } bhv_module_vfsops_t; |
| 190 | 200 | ||
| 191 | #define vfs_bhv_lookup(v, id) ( bhv_lookup_range(&(v)->vfs_bh, (id), (id)) ) | 201 | #define vfs_bhv_lookup(v, id) (bhv_lookup_range(&(v)->vfs_bh, (id), (id))) |
| 192 | #define vfs_bhv_custom(b) ( ((bhv_vfsops_t *)BHV_OPS(b))->bhv_custom ) | 202 | #define vfs_bhv_custom(b) (((bhv_module_vfsops_t*)BHV_OPS(b))->bhv_custom) |
| 193 | #define vfs_bhv_set_custom(b,o) ( (b)->bhv_custom = (void *)(o)) | 203 | #define vfs_bhv_set_custom(b,o) ((b)->bhv_custom = (void *)(o)) |
| 194 | #define vfs_bhv_clr_custom(b) ( (b)->bhv_custom = NULL ) | 204 | #define vfs_bhv_clr_custom(b) ((b)->bhv_custom = NULL) |
| 195 | 205 | ||
| 196 | extern vfs_t *vfs_allocate(struct super_block *); | 206 | extern bhv_vfs_t *vfs_allocate(struct super_block *); |
| 197 | extern vfs_t *vfs_from_sb(struct super_block *); | 207 | extern bhv_vfs_t *vfs_from_sb(struct super_block *); |
| 198 | extern void vfs_deallocate(vfs_t *); | 208 | extern void vfs_deallocate(bhv_vfs_t *); |
| 199 | extern void vfs_insertops(vfs_t *, bhv_vfsops_t *); | 209 | extern void vfs_insertbhv(bhv_vfs_t *, bhv_desc_t *, bhv_vfsops_t *, void *); |
| 200 | extern void vfs_insertbhv(vfs_t *, bhv_desc_t *, vfsops_t *, void *); | ||
| 201 | 210 | ||
| 202 | extern void bhv_insert_all_vfsops(struct vfs *); | 211 | extern void vfs_insertops(bhv_vfs_t *, bhv_module_vfsops_t *); |
| 203 | extern void bhv_remove_all_vfsops(struct vfs *, int); | ||
| 204 | extern void bhv_remove_vfsops(struct vfs *, int); | ||
| 205 | 212 | ||
| 206 | #define fs_frozen(vfsp) ((vfsp)->vfs_super->s_frozen) | 213 | extern void bhv_insert_all_vfsops(struct bhv_vfs *); |
| 207 | #define fs_check_frozen(vfsp, level) \ | 214 | extern void bhv_remove_all_vfsops(struct bhv_vfs *, int); |
| 208 | vfs_check_frozen(vfsp->vfs_super, level); | 215 | extern void bhv_remove_vfsops(struct bhv_vfs *, int); |
| 209 | 216 | ||
| 210 | #endif /* __XFS_VFS_H__ */ | 217 | #endif /* __XFS_VFS_H__ */ |
diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index d27c25b27ccd..6628d96b6fd6 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c | |||
| @@ -39,7 +39,7 @@ vn_init(void) | |||
| 39 | 39 | ||
| 40 | void | 40 | void |
| 41 | vn_iowait( | 41 | vn_iowait( |
| 42 | struct vnode *vp) | 42 | bhv_vnode_t *vp) |
| 43 | { | 43 | { |
| 44 | wait_queue_head_t *wq = vptosync(vp); | 44 | wait_queue_head_t *wq = vptosync(vp); |
| 45 | 45 | ||
| @@ -48,17 +48,33 @@ vn_iowait( | |||
| 48 | 48 | ||
| 49 | void | 49 | void |
| 50 | vn_iowake( | 50 | vn_iowake( |
| 51 | struct vnode *vp) | 51 | bhv_vnode_t *vp) |
| 52 | { | 52 | { |
| 53 | if (atomic_dec_and_test(&vp->v_iocount)) | 53 | if (atomic_dec_and_test(&vp->v_iocount)) |
| 54 | wake_up(vptosync(vp)); | 54 | wake_up(vptosync(vp)); |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | struct vnode * | 57 | /* |
| 58 | * Volume managers supporting multiple paths can send back ENODEV when the | ||
| 59 | * final path disappears. In this case continuing to fill the page cache | ||
| 60 | * with dirty data which cannot be written out is evil, so prevent that. | ||
| 61 | */ | ||
| 62 | void | ||
| 63 | vn_ioerror( | ||
| 64 | bhv_vnode_t *vp, | ||
| 65 | int error, | ||
| 66 | char *f, | ||
| 67 | int l) | ||
| 68 | { | ||
| 69 | if (unlikely(error == -ENODEV)) | ||
| 70 | bhv_vfs_force_shutdown(vp->v_vfsp, SHUTDOWN_DEVICE_REQ, f, l); | ||
| 71 | } | ||
| 72 | |||
| 73 | bhv_vnode_t * | ||
| 58 | vn_initialize( | 74 | vn_initialize( |
| 59 | struct inode *inode) | 75 | struct inode *inode) |
| 60 | { | 76 | { |
| 61 | struct vnode *vp = vn_from_inode(inode); | 77 | bhv_vnode_t *vp = vn_from_inode(inode); |
| 62 | 78 | ||
| 63 | XFS_STATS_INC(vn_active); | 79 | XFS_STATS_INC(vn_active); |
| 64 | XFS_STATS_INC(vn_alloc); | 80 | XFS_STATS_INC(vn_alloc); |
| @@ -94,8 +110,8 @@ vn_initialize( | |||
| 94 | */ | 110 | */ |
| 95 | void | 111 | void |
| 96 | vn_revalidate_core( | 112 | vn_revalidate_core( |
| 97 | struct vnode *vp, | 113 | bhv_vnode_t *vp, |
| 98 | vattr_t *vap) | 114 | bhv_vattr_t *vap) |
| 99 | { | 115 | { |
| 100 | struct inode *inode = vn_to_inode(vp); | 116 | struct inode *inode = vn_to_inode(vp); |
| 101 | 117 | ||
| @@ -130,14 +146,14 @@ vn_revalidate_core( | |||
| 130 | */ | 146 | */ |
| 131 | int | 147 | int |
| 132 | __vn_revalidate( | 148 | __vn_revalidate( |
| 133 | struct vnode *vp, | 149 | bhv_vnode_t *vp, |
| 134 | struct vattr *vattr) | 150 | bhv_vattr_t *vattr) |
| 135 | { | 151 | { |
| 136 | int error; | 152 | int error; |
| 137 | 153 | ||
| 138 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); | 154 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); |
| 139 | vattr->va_mask = XFS_AT_STAT | XFS_AT_XFLAGS; | 155 | vattr->va_mask = XFS_AT_STAT | XFS_AT_XFLAGS; |
| 140 | VOP_GETATTR(vp, vattr, 0, NULL, error); | 156 | error = bhv_vop_getattr(vp, vattr, 0, NULL); |
| 141 | if (likely(!error)) { | 157 | if (likely(!error)) { |
| 142 | vn_revalidate_core(vp, vattr); | 158 | vn_revalidate_core(vp, vattr); |
| 143 | VUNMODIFY(vp); | 159 | VUNMODIFY(vp); |
| @@ -147,9 +163,9 @@ __vn_revalidate( | |||
| 147 | 163 | ||
| 148 | int | 164 | int |
| 149 | vn_revalidate( | 165 | vn_revalidate( |
| 150 | struct vnode *vp) | 166 | bhv_vnode_t *vp) |
| 151 | { | 167 | { |
| 152 | vattr_t vattr; | 168 | bhv_vattr_t vattr; |
| 153 | 169 | ||
| 154 | return __vn_revalidate(vp, &vattr); | 170 | return __vn_revalidate(vp, &vattr); |
| 155 | } | 171 | } |
| @@ -157,9 +173,9 @@ vn_revalidate( | |||
| 157 | /* | 173 | /* |
| 158 | * Add a reference to a referenced vnode. | 174 | * Add a reference to a referenced vnode. |
| 159 | */ | 175 | */ |
| 160 | struct vnode * | 176 | bhv_vnode_t * |
| 161 | vn_hold( | 177 | vn_hold( |
| 162 | struct vnode *vp) | 178 | bhv_vnode_t *vp) |
| 163 | { | 179 | { |
| 164 | struct inode *inode; | 180 | struct inode *inode; |
| 165 | 181 | ||
| @@ -192,31 +208,31 @@ vn_hold( | |||
| 192 | * Vnode tracing code. | 208 | * Vnode tracing code. |
| 193 | */ | 209 | */ |
| 194 | void | 210 | void |
| 195 | vn_trace_entry(vnode_t *vp, const char *func, inst_t *ra) | 211 | vn_trace_entry(bhv_vnode_t *vp, const char *func, inst_t *ra) |
| 196 | { | 212 | { |
| 197 | KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra); | 213 | KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra); |
| 198 | } | 214 | } |
| 199 | 215 | ||
| 200 | void | 216 | void |
| 201 | vn_trace_exit(vnode_t *vp, const char *func, inst_t *ra) | 217 | vn_trace_exit(bhv_vnode_t *vp, const char *func, inst_t *ra) |
| 202 | { | 218 | { |
| 203 | KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra); | 219 | KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra); |
| 204 | } | 220 | } |
| 205 | 221 | ||
| 206 | void | 222 | void |
| 207 | vn_trace_hold(vnode_t *vp, char *file, int line, inst_t *ra) | 223 | vn_trace_hold(bhv_vnode_t *vp, char *file, int line, inst_t *ra) |
| 208 | { | 224 | { |
| 209 | KTRACE_ENTER(vp, VNODE_KTRACE_HOLD, file, line, ra); | 225 | KTRACE_ENTER(vp, VNODE_KTRACE_HOLD, file, line, ra); |
| 210 | } | 226 | } |
| 211 | 227 | ||
| 212 | void | 228 | void |
| 213 | vn_trace_ref(vnode_t *vp, char *file, int line, inst_t *ra) | 229 | vn_trace_ref(bhv_vnode_t *vp, char *file, int line, inst_t *ra) |
| 214 | { | 230 | { |
| 215 | KTRACE_ENTER(vp, VNODE_KTRACE_REF, file, line, ra); | 231 | KTRACE_ENTER(vp, VNODE_KTRACE_REF, file, line, ra); |
| 216 | } | 232 | } |
| 217 | 233 | ||
| 218 | void | 234 | void |
| 219 | vn_trace_rele(vnode_t *vp, char *file, int line, inst_t *ra) | 235 | vn_trace_rele(bhv_vnode_t *vp, char *file, int line, inst_t *ra) |
| 220 | { | 236 | { |
| 221 | KTRACE_ENTER(vp, VNODE_KTRACE_RELE, file, line, ra); | 237 | KTRACE_ENTER(vp, VNODE_KTRACE_RELE, file, line, ra); |
| 222 | } | 238 | } |
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 2a8e16c22353..35c6a01963a7 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h | |||
| @@ -14,57 +14,35 @@ | |||
| 14 | * You should have received a copy of the GNU General Public License | 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this program; if not, write the Free Software Foundation, | 15 | * along with this program; if not, write the Free Software Foundation, |
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 17 | * | ||
| 18 | * Portions Copyright (c) 1989, 1993 | ||
| 19 | * The Regents of the University of California. All rights reserved. | ||
| 20 | * | ||
| 21 | * Redistribution and use in source and binary forms, with or without | ||
| 22 | * modification, are permitted provided that the following conditions | ||
| 23 | * are met: | ||
| 24 | * 1. Redistributions of source code must retain the above copyright | ||
| 25 | * notice, this list of conditions and the following disclaimer. | ||
| 26 | * 2. Redistributions in binary form must reproduce the above copyright | ||
| 27 | * notice, this list of conditions and the following disclaimer in the | ||
| 28 | * documentation and/or other materials provided with the distribution. | ||
| 29 | * 3. Neither the name of the University nor the names of its contributors | ||
| 30 | * may be used to endorse or promote products derived from this software | ||
| 31 | * without specific prior written permission. | ||
| 32 | * | ||
| 33 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
| 34 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| 35 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| 36 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
| 37 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 38 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| 39 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| 40 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
| 41 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
| 42 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
| 43 | * SUCH DAMAGE. | ||
| 44 | */ | 17 | */ |
| 45 | #ifndef __XFS_VNODE_H__ | 18 | #ifndef __XFS_VNODE_H__ |
| 46 | #define __XFS_VNODE_H__ | 19 | #define __XFS_VNODE_H__ |
| 47 | 20 | ||
| 48 | struct uio; | 21 | struct uio; |
| 49 | struct file; | 22 | struct file; |
| 50 | struct vattr; | 23 | struct bhv_vfs; |
| 24 | struct bhv_vattr; | ||
| 51 | struct xfs_iomap; | 25 | struct xfs_iomap; |
| 52 | struct attrlist_cursor_kern; | 26 | struct attrlist_cursor_kern; |
| 53 | 27 | ||
| 28 | typedef struct dentry bhv_vname_t; | ||
| 29 | typedef __u64 bhv_vnumber_t; | ||
| 54 | 30 | ||
| 55 | typedef xfs_ino_t vnumber_t; | 31 | typedef enum bhv_vflags { |
| 56 | typedef struct dentry vname_t; | 32 | VMODIFIED = 0x08, /* XFS inode state possibly differs */ |
| 57 | typedef bhv_head_t vn_bhv_head_t; | 33 | /* to the Linux inode state. */ |
| 34 | VTRUNCATED = 0x40, /* truncated down so flush-on-close */ | ||
| 35 | } bhv_vflags_t; | ||
| 58 | 36 | ||
| 59 | /* | 37 | /* |
| 60 | * MP locking protocols: | 38 | * MP locking protocols: |
| 61 | * v_flag, v_vfsp VN_LOCK/VN_UNLOCK | 39 | * v_flag, v_vfsp VN_LOCK/VN_UNLOCK |
| 62 | */ | 40 | */ |
| 63 | typedef struct vnode { | 41 | typedef struct bhv_vnode { |
| 64 | __u32 v_flag; /* vnode flags (see below) */ | 42 | bhv_vflags_t v_flag; /* vnode flags (see above) */ |
| 65 | struct vfs *v_vfsp; /* ptr to containing VFS */ | 43 | bhv_vfs_t *v_vfsp; /* ptr to containing VFS */ |
| 66 | vnumber_t v_number; /* in-core vnode number */ | 44 | bhv_vnumber_t v_number; /* in-core vnode number */ |
| 67 | vn_bhv_head_t v_bh; /* behavior head */ | 45 | bhv_head_t v_bh; /* behavior head */ |
| 68 | spinlock_t v_lock; /* VN_LOCK/VN_UNLOCK */ | 46 | spinlock_t v_lock; /* VN_LOCK/VN_UNLOCK */ |
| 69 | atomic_t v_iocount; /* outstanding I/O count */ | 47 | atomic_t v_iocount; /* outstanding I/O count */ |
| 70 | #ifdef XFS_VNODE_TRACE | 48 | #ifdef XFS_VNODE_TRACE |
| @@ -72,7 +50,7 @@ typedef struct vnode { | |||
| 72 | #endif | 50 | #endif |
| 73 | struct inode v_inode; /* Linux inode */ | 51 | struct inode v_inode; /* Linux inode */ |
| 74 | /* inode MUST be last */ | 52 | /* inode MUST be last */ |
| 75 | } vnode_t; | 53 | } bhv_vnode_t; |
| 76 | 54 | ||
| 77 | #define VN_ISLNK(vp) S_ISLNK((vp)->v_inode.i_mode) | 55 | #define VN_ISLNK(vp) S_ISLNK((vp)->v_inode.i_mode) |
| 78 | #define VN_ISREG(vp) S_ISREG((vp)->v_inode.i_mode) | 56 | #define VN_ISREG(vp) S_ISREG((vp)->v_inode.i_mode) |
| @@ -80,9 +58,6 @@ typedef struct vnode { | |||
| 80 | #define VN_ISCHR(vp) S_ISCHR((vp)->v_inode.i_mode) | 58 | #define VN_ISCHR(vp) S_ISCHR((vp)->v_inode.i_mode) |
| 81 | #define VN_ISBLK(vp) S_ISBLK((vp)->v_inode.i_mode) | 59 | #define VN_ISBLK(vp) S_ISBLK((vp)->v_inode.i_mode) |
| 82 | 60 | ||
| 83 | #define v_fbhv v_bh.bh_first /* first behavior */ | ||
| 84 | #define v_fops v_bh.bh_first->bd_ops /* first behavior ops */ | ||
| 85 | |||
| 86 | #define VNODE_POSITION_BASE BHV_POSITION_BASE /* chain bottom */ | 61 | #define VNODE_POSITION_BASE BHV_POSITION_BASE /* chain bottom */ |
| 87 | #define VNODE_POSITION_TOP BHV_POSITION_TOP /* chain top */ | 62 | #define VNODE_POSITION_TOP BHV_POSITION_TOP /* chain top */ |
| 88 | #define VNODE_POSITION_INVALID BHV_POSITION_INVALID /* invalid pos. num */ | 63 | #define VNODE_POSITION_INVALID BHV_POSITION_INVALID /* invalid pos. num */ |
| @@ -104,8 +79,8 @@ typedef enum { | |||
| 104 | /* | 79 | /* |
| 105 | * Macros for dealing with the behavior descriptor inside of the vnode. | 80 | * Macros for dealing with the behavior descriptor inside of the vnode. |
| 106 | */ | 81 | */ |
| 107 | #define BHV_TO_VNODE(bdp) ((vnode_t *)BHV_VOBJ(bdp)) | 82 | #define BHV_TO_VNODE(bdp) ((bhv_vnode_t *)BHV_VOBJ(bdp)) |
| 108 | #define BHV_TO_VNODE_NULL(bdp) ((vnode_t *)BHV_VOBJNULL(bdp)) | 83 | #define BHV_TO_VNODE_NULL(bdp) ((bhv_vnode_t *)BHV_VOBJNULL(bdp)) |
| 109 | 84 | ||
| 110 | #define VN_BHV_HEAD(vp) ((bhv_head_t *)(&((vp)->v_bh))) | 85 | #define VN_BHV_HEAD(vp) ((bhv_head_t *)(&((vp)->v_bh))) |
| 111 | #define vn_bhv_head_init(bhp,name) bhv_head_init(bhp,name) | 86 | #define vn_bhv_head_init(bhp,name) bhv_head_init(bhp,name) |
| @@ -116,35 +91,29 @@ typedef enum { | |||
| 116 | /* | 91 | /* |
| 117 | * Vnode to Linux inode mapping. | 92 | * Vnode to Linux inode mapping. |
| 118 | */ | 93 | */ |
| 119 | static inline struct vnode *vn_from_inode(struct inode *inode) | 94 | static inline struct bhv_vnode *vn_from_inode(struct inode *inode) |
| 120 | { | 95 | { |
| 121 | return (vnode_t *)list_entry(inode, vnode_t, v_inode); | 96 | return (bhv_vnode_t *)list_entry(inode, bhv_vnode_t, v_inode); |
| 122 | } | 97 | } |
| 123 | static inline struct inode *vn_to_inode(struct vnode *vnode) | 98 | static inline struct inode *vn_to_inode(struct bhv_vnode *vnode) |
| 124 | { | 99 | { |
| 125 | return &vnode->v_inode; | 100 | return &vnode->v_inode; |
| 126 | } | 101 | } |
| 127 | 102 | ||
| 128 | /* | 103 | /* |
| 129 | * Vnode flags. | 104 | * Values for the vop_rwlock/rwunlock flags parameter. |
| 130 | */ | ||
| 131 | #define VMODIFIED 0x8 /* XFS inode state possibly differs */ | ||
| 132 | /* to the Linux inode state. */ | ||
| 133 | |||
| 134 | /* | ||
| 135 | * Values for the VOP_RWLOCK and VOP_RWUNLOCK flags parameter. | ||
| 136 | */ | 105 | */ |
| 137 | typedef enum vrwlock { | 106 | typedef enum bhv_vrwlock { |
| 138 | VRWLOCK_NONE, | 107 | VRWLOCK_NONE, |
| 139 | VRWLOCK_READ, | 108 | VRWLOCK_READ, |
| 140 | VRWLOCK_WRITE, | 109 | VRWLOCK_WRITE, |
| 141 | VRWLOCK_WRITE_DIRECT, | 110 | VRWLOCK_WRITE_DIRECT, |
| 142 | VRWLOCK_TRY_READ, | 111 | VRWLOCK_TRY_READ, |
| 143 | VRWLOCK_TRY_WRITE | 112 | VRWLOCK_TRY_WRITE |
| 144 | } vrwlock_t; | 113 | } bhv_vrwlock_t; |
| 145 | 114 | ||
| 146 | /* | 115 | /* |
| 147 | * Return values for VOP_INACTIVE. A return value of | 116 | * Return values for bhv_vop_inactive. A return value of |
| 148 | * VN_INACTIVE_NOCACHE implies that the file system behavior | 117 | * VN_INACTIVE_NOCACHE implies that the file system behavior |
| 149 | * has disassociated its state and bhv_desc_t from the vnode. | 118 | * has disassociated its state and bhv_desc_t from the vnode. |
| 150 | */ | 119 | */ |
| @@ -152,18 +121,20 @@ typedef enum vrwlock { | |||
| 152 | #define VN_INACTIVE_NOCACHE 1 | 121 | #define VN_INACTIVE_NOCACHE 1 |
| 153 | 122 | ||
| 154 | /* | 123 | /* |
| 155 | * Values for the cmd code given to VOP_VNODE_CHANGE. | 124 | * Values for the cmd code given to vop_vnode_change. |
| 156 | */ | 125 | */ |
| 157 | typedef enum vchange { | 126 | typedef enum bhv_vchange { |
| 158 | VCHANGE_FLAGS_FRLOCKS = 0, | 127 | VCHANGE_FLAGS_FRLOCKS = 0, |
| 159 | VCHANGE_FLAGS_ENF_LOCKING = 1, | 128 | VCHANGE_FLAGS_ENF_LOCKING = 1, |
| 160 | VCHANGE_FLAGS_TRUNCATED = 2, | 129 | VCHANGE_FLAGS_TRUNCATED = 2, |
| 161 | VCHANGE_FLAGS_PAGE_DIRTY = 3, | 130 | VCHANGE_FLAGS_PAGE_DIRTY = 3, |
| 162 | VCHANGE_FLAGS_IOEXCL_COUNT = 4 | 131 | VCHANGE_FLAGS_IOEXCL_COUNT = 4 |
| 163 | } vchange_t; | 132 | } bhv_vchange_t; |
| 164 | 133 | ||
| 134 | typedef enum { L_FALSE, L_TRUE } lastclose_t; | ||
| 165 | 135 | ||
| 166 | typedef int (*vop_open_t)(bhv_desc_t *, struct cred *); | 136 | typedef int (*vop_open_t)(bhv_desc_t *, struct cred *); |
| 137 | typedef int (*vop_close_t)(bhv_desc_t *, int, lastclose_t, struct cred *); | ||
| 167 | typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct kiocb *, | 138 | typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct kiocb *, |
| 168 | const struct iovec *, unsigned int, | 139 | const struct iovec *, unsigned int, |
| 169 | loff_t *, int, struct cred *); | 140 | loff_t *, int, struct cred *); |
| @@ -181,27 +152,27 @@ typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct pipe_inode_info *, | |||
| 181 | struct cred *); | 152 | struct cred *); |
| 182 | typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, | 153 | typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, |
| 183 | int, unsigned int, void __user *); | 154 | int, unsigned int, void __user *); |
| 184 | typedef int (*vop_getattr_t)(bhv_desc_t *, struct vattr *, int, | 155 | typedef int (*vop_getattr_t)(bhv_desc_t *, struct bhv_vattr *, int, |
| 185 | struct cred *); | 156 | struct cred *); |
| 186 | typedef int (*vop_setattr_t)(bhv_desc_t *, struct vattr *, int, | 157 | typedef int (*vop_setattr_t)(bhv_desc_t *, struct bhv_vattr *, int, |
| 187 | struct cred *); | 158 | struct cred *); |
| 188 | typedef int (*vop_access_t)(bhv_desc_t *, int, struct cred *); | 159 | typedef int (*vop_access_t)(bhv_desc_t *, int, struct cred *); |
| 189 | typedef int (*vop_lookup_t)(bhv_desc_t *, vname_t *, vnode_t **, | 160 | typedef int (*vop_lookup_t)(bhv_desc_t *, bhv_vname_t *, bhv_vnode_t **, |
| 190 | int, vnode_t *, struct cred *); | 161 | int, bhv_vnode_t *, struct cred *); |
| 191 | typedef int (*vop_create_t)(bhv_desc_t *, vname_t *, struct vattr *, | 162 | typedef int (*vop_create_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr *, |
| 192 | vnode_t **, struct cred *); | 163 | bhv_vnode_t **, struct cred *); |
| 193 | typedef int (*vop_remove_t)(bhv_desc_t *, vname_t *, struct cred *); | 164 | typedef int (*vop_remove_t)(bhv_desc_t *, bhv_vname_t *, struct cred *); |
| 194 | typedef int (*vop_link_t)(bhv_desc_t *, vnode_t *, vname_t *, | 165 | typedef int (*vop_link_t)(bhv_desc_t *, bhv_vnode_t *, bhv_vname_t *, |
| 195 | struct cred *); | ||
| 196 | typedef int (*vop_rename_t)(bhv_desc_t *, vname_t *, vnode_t *, vname_t *, | ||
| 197 | struct cred *); | 166 | struct cred *); |
| 198 | typedef int (*vop_mkdir_t)(bhv_desc_t *, vname_t *, struct vattr *, | 167 | typedef int (*vop_rename_t)(bhv_desc_t *, bhv_vname_t *, bhv_vnode_t *, |
| 199 | vnode_t **, struct cred *); | 168 | bhv_vname_t *, struct cred *); |
| 200 | typedef int (*vop_rmdir_t)(bhv_desc_t *, vname_t *, struct cred *); | 169 | typedef int (*vop_mkdir_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr *, |
| 170 | bhv_vnode_t **, struct cred *); | ||
| 171 | typedef int (*vop_rmdir_t)(bhv_desc_t *, bhv_vname_t *, struct cred *); | ||
| 201 | typedef int (*vop_readdir_t)(bhv_desc_t *, struct uio *, struct cred *, | 172 | typedef int (*vop_readdir_t)(bhv_desc_t *, struct uio *, struct cred *, |
| 202 | int *); | 173 | int *); |
| 203 | typedef int (*vop_symlink_t)(bhv_desc_t *, vname_t *, struct vattr *, | 174 | typedef int (*vop_symlink_t)(bhv_desc_t *, bhv_vname_t *, struct bhv_vattr*, |
| 204 | char *, vnode_t **, struct cred *); | 175 | char *, bhv_vnode_t **, struct cred *); |
| 205 | typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, int, | 176 | typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, int, |
| 206 | struct cred *); | 177 | struct cred *); |
| 207 | typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *, | 178 | typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *, |
| @@ -209,8 +180,8 @@ typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *, | |||
| 209 | typedef int (*vop_inactive_t)(bhv_desc_t *, struct cred *); | 180 | typedef int (*vop_inactive_t)(bhv_desc_t *, struct cred *); |
| 210 | typedef int (*vop_fid2_t)(bhv_desc_t *, struct fid *); | 181 | typedef int (*vop_fid2_t)(bhv_desc_t *, struct fid *); |
| 211 | typedef int (*vop_release_t)(bhv_desc_t *); | 182 | typedef int (*vop_release_t)(bhv_desc_t *); |
| 212 | typedef int (*vop_rwlock_t)(bhv_desc_t *, vrwlock_t); | 183 | typedef int (*vop_rwlock_t)(bhv_desc_t *, bhv_vrwlock_t); |
| 213 | typedef void (*vop_rwunlock_t)(bhv_desc_t *, vrwlock_t); | 184 | typedef void (*vop_rwunlock_t)(bhv_desc_t *, bhv_vrwlock_t); |
| 214 | typedef int (*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, | 185 | typedef int (*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, |
| 215 | struct xfs_iomap *, int *); | 186 | struct xfs_iomap *, int *); |
| 216 | typedef int (*vop_reclaim_t)(bhv_desc_t *); | 187 | typedef int (*vop_reclaim_t)(bhv_desc_t *); |
| @@ -222,8 +193,8 @@ typedef int (*vop_attr_remove_t)(bhv_desc_t *, const char *, | |||
| 222 | int, struct cred *); | 193 | int, struct cred *); |
| 223 | typedef int (*vop_attr_list_t)(bhv_desc_t *, char *, int, int, | 194 | typedef int (*vop_attr_list_t)(bhv_desc_t *, char *, int, int, |
| 224 | struct attrlist_cursor_kern *, struct cred *); | 195 | struct attrlist_cursor_kern *, struct cred *); |
| 225 | typedef void (*vop_link_removed_t)(bhv_desc_t *, vnode_t *, int); | 196 | typedef void (*vop_link_removed_t)(bhv_desc_t *, bhv_vnode_t *, int); |
| 226 | typedef void (*vop_vnode_change_t)(bhv_desc_t *, vchange_t, __psint_t); | 197 | typedef void (*vop_vnode_change_t)(bhv_desc_t *, bhv_vchange_t, __psint_t); |
| 227 | typedef void (*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); | 198 | typedef void (*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); |
| 228 | typedef void (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); | 199 | typedef void (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); |
| 229 | typedef int (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, | 200 | typedef int (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, |
| @@ -231,9 +202,10 @@ typedef int (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, | |||
| 231 | typedef int (*vop_iflush_t)(bhv_desc_t *, int); | 202 | typedef int (*vop_iflush_t)(bhv_desc_t *, int); |
| 232 | 203 | ||
| 233 | 204 | ||
| 234 | typedef struct vnodeops { | 205 | typedef struct bhv_vnodeops { |
| 235 | bhv_position_t vn_position; /* position within behavior chain */ | 206 | bhv_position_t vn_position; /* position within behavior chain */ |
| 236 | vop_open_t vop_open; | 207 | vop_open_t vop_open; |
| 208 | vop_close_t vop_close; | ||
| 237 | vop_read_t vop_read; | 209 | vop_read_t vop_read; |
| 238 | vop_write_t vop_write; | 210 | vop_write_t vop_write; |
| 239 | vop_sendfile_t vop_sendfile; | 211 | vop_sendfile_t vop_sendfile; |
| @@ -271,103 +243,80 @@ typedef struct vnodeops { | |||
| 271 | vop_pflushvp_t vop_flush_pages; | 243 | vop_pflushvp_t vop_flush_pages; |
| 272 | vop_release_t vop_release; | 244 | vop_release_t vop_release; |
| 273 | vop_iflush_t vop_iflush; | 245 | vop_iflush_t vop_iflush; |
| 274 | } vnodeops_t; | 246 | } bhv_vnodeops_t; |
| 275 | 247 | ||
| 276 | /* | 248 | /* |
| 277 | * VOP's. | 249 | * Virtual node operations, operating from head bhv. |
| 278 | */ | ||
| 279 | #define _VOP_(op, vp) (*((vnodeops_t *)(vp)->v_fops)->op) | ||
| 280 | |||
| 281 | #define VOP_READ(vp,file,iov,segs,offset,ioflags,cr,rv) \ | ||
| 282 | rv = _VOP_(vop_read, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr) | ||
| 283 | #define VOP_WRITE(vp,file,iov,segs,offset,ioflags,cr,rv) \ | ||
| 284 | rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr) | ||
| 285 | #define VOP_SENDFILE(vp,f,off,ioflags,cnt,act,targ,cr,rv) \ | ||
| 286 | rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,ioflags,cnt,act,targ,cr) | ||
| 287 | #define VOP_SPLICE_READ(vp,f,o,pipe,cnt,fl,iofl,cr,rv) \ | ||
| 288 | rv = _VOP_(vop_splice_read, vp)((vp)->v_fbhv,f,o,pipe,cnt,fl,iofl,cr) | ||
| 289 | #define VOP_SPLICE_WRITE(vp,f,o,pipe,cnt,fl,iofl,cr,rv) \ | ||
| 290 | rv = _VOP_(vop_splice_write, vp)((vp)->v_fbhv,f,o,pipe,cnt,fl,iofl,cr) | ||
| 291 | #define VOP_BMAP(vp,of,sz,rw,b,n,rv) \ | ||
| 292 | rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n) | ||
| 293 | #define VOP_OPEN(vp, cr, rv) \ | ||
| 294 | rv = _VOP_(vop_open, vp)((vp)->v_fbhv, cr) | ||
| 295 | #define VOP_GETATTR(vp, vap, f, cr, rv) \ | ||
| 296 | rv = _VOP_(vop_getattr, vp)((vp)->v_fbhv, vap, f, cr) | ||
| 297 | #define VOP_SETATTR(vp, vap, f, cr, rv) \ | ||
| 298 | rv = _VOP_(vop_setattr, vp)((vp)->v_fbhv, vap, f, cr) | ||
| 299 | #define VOP_ACCESS(vp, mode, cr, rv) \ | ||
| 300 | rv = _VOP_(vop_access, vp)((vp)->v_fbhv, mode, cr) | ||
| 301 | #define VOP_LOOKUP(vp,d,vpp,f,rdir,cr,rv) \ | ||
| 302 | rv = _VOP_(vop_lookup, vp)((vp)->v_fbhv,d,vpp,f,rdir,cr) | ||
| 303 | #define VOP_CREATE(dvp,d,vap,vpp,cr,rv) \ | ||
| 304 | rv = _VOP_(vop_create, dvp)((dvp)->v_fbhv,d,vap,vpp,cr) | ||
| 305 | #define VOP_REMOVE(dvp,d,cr,rv) \ | ||
| 306 | rv = _VOP_(vop_remove, dvp)((dvp)->v_fbhv,d,cr) | ||
| 307 | #define VOP_LINK(tdvp,fvp,d,cr,rv) \ | ||
| 308 | rv = _VOP_(vop_link, tdvp)((tdvp)->v_fbhv,fvp,d,cr) | ||
| 309 | #define VOP_RENAME(fvp,fnm,tdvp,tnm,cr,rv) \ | ||
| 310 | rv = _VOP_(vop_rename, fvp)((fvp)->v_fbhv,fnm,tdvp,tnm,cr) | ||
| 311 | #define VOP_MKDIR(dp,d,vap,vpp,cr,rv) \ | ||
| 312 | rv = _VOP_(vop_mkdir, dp)((dp)->v_fbhv,d,vap,vpp,cr) | ||
| 313 | #define VOP_RMDIR(dp,d,cr,rv) \ | ||
| 314 | rv = _VOP_(vop_rmdir, dp)((dp)->v_fbhv,d,cr) | ||
| 315 | #define VOP_READDIR(vp,uiop,cr,eofp,rv) \ | ||
| 316 | rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp) | ||
| 317 | #define VOP_SYMLINK(dvp,d,vap,tnm,vpp,cr,rv) \ | ||
| 318 | rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,d,vap,tnm,vpp,cr) | ||
| 319 | #define VOP_READLINK(vp,uiop,fl,cr,rv) \ | ||
| 320 | rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,fl,cr) | ||
| 321 | #define VOP_FSYNC(vp,f,cr,b,e,rv) \ | ||
| 322 | rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e) | ||
| 323 | #define VOP_INACTIVE(vp, cr, rv) \ | ||
| 324 | rv = _VOP_(vop_inactive, vp)((vp)->v_fbhv, cr) | ||
| 325 | #define VOP_RELEASE(vp, rv) \ | ||
| 326 | rv = _VOP_(vop_release, vp)((vp)->v_fbhv) | ||
| 327 | #define VOP_FID2(vp, fidp, rv) \ | ||
| 328 | rv = _VOP_(vop_fid2, vp)((vp)->v_fbhv, fidp) | ||
| 329 | #define VOP_RWLOCK(vp,i) \ | ||
| 330 | (void)_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i) | ||
| 331 | #define VOP_RWLOCK_TRY(vp,i) \ | ||
| 332 | _VOP_(vop_rwlock, vp)((vp)->v_fbhv, i) | ||
| 333 | #define VOP_RWUNLOCK(vp,i) \ | ||
| 334 | (void)_VOP_(vop_rwunlock, vp)((vp)->v_fbhv, i) | ||
| 335 | #define VOP_FRLOCK(vp,c,fl,flags,offset,fr,rv) \ | ||
| 336 | rv = _VOP_(vop_frlock, vp)((vp)->v_fbhv,c,fl,flags,offset,fr) | ||
| 337 | #define VOP_RECLAIM(vp, rv) \ | ||
| 338 | rv = _VOP_(vop_reclaim, vp)((vp)->v_fbhv) | ||
| 339 | #define VOP_ATTR_GET(vp, name, val, vallenp, fl, cred, rv) \ | ||
| 340 | rv = _VOP_(vop_attr_get, vp)((vp)->v_fbhv,name,val,vallenp,fl,cred) | ||
| 341 | #define VOP_ATTR_SET(vp, name, val, vallen, fl, cred, rv) \ | ||
| 342 | rv = _VOP_(vop_attr_set, vp)((vp)->v_fbhv,name,val,vallen,fl,cred) | ||
| 343 | #define VOP_ATTR_REMOVE(vp, name, flags, cred, rv) \ | ||
| 344 | rv = _VOP_(vop_attr_remove, vp)((vp)->v_fbhv,name,flags,cred) | ||
| 345 | #define VOP_ATTR_LIST(vp, buf, buflen, fl, cursor, cred, rv) \ | ||
| 346 | rv = _VOP_(vop_attr_list, vp)((vp)->v_fbhv,buf,buflen,fl,cursor,cred) | ||
| 347 | #define VOP_LINK_REMOVED(vp, dvp, linkzero) \ | ||
| 348 | (void)_VOP_(vop_link_removed, vp)((vp)->v_fbhv, dvp, linkzero) | ||
| 349 | #define VOP_VNODE_CHANGE(vp, cmd, val) \ | ||
| 350 | (void)_VOP_(vop_vnode_change, vp)((vp)->v_fbhv,cmd,val) | ||
| 351 | /* | ||
| 352 | * These are page cache functions that now go thru VOPs. | ||
| 353 | * 'last' parameter is unused and left in for IRIX compatibility | ||
| 354 | */ | 250 | */ |
| 355 | #define VOP_TOSS_PAGES(vp, first, last, fiopt) \ | 251 | #define VNHEAD(vp) ((vp)->v_bh.bh_first) |
| 356 | _VOP_(vop_tosspages, vp)((vp)->v_fbhv,first, last, fiopt) | 252 | #define VOP(op, vp) (*((bhv_vnodeops_t *)VNHEAD(vp)->bd_ops)->op) |
| 357 | /* | 253 | #define bhv_vop_open(vp, cr) VOP(vop_open, vp)(VNHEAD(vp),cr) |
| 358 | * 'last' parameter is unused and left in for IRIX compatibility | 254 | #define bhv_vop_close(vp, f,last,cr) VOP(vop_close, vp)(VNHEAD(vp),f,last,cr) |
| 359 | */ | 255 | #define bhv_vop_read(vp,file,iov,segs,offset,ioflags,cr) \ |
| 360 | #define VOP_FLUSHINVAL_PAGES(vp, first, last, fiopt) \ | 256 | VOP(vop_read, vp)(VNHEAD(vp),file,iov,segs,offset,ioflags,cr) |
| 361 | _VOP_(vop_flushinval_pages, vp)((vp)->v_fbhv,first,last,fiopt) | 257 | #define bhv_vop_write(vp,file,iov,segs,offset,ioflags,cr) \ |
| 362 | /* | 258 | VOP(vop_write, vp)(VNHEAD(vp),file,iov,segs,offset,ioflags,cr) |
| 363 | * 'last' parameter is unused and left in for IRIX compatibility | 259 | #define bhv_vop_sendfile(vp,f,off,ioflags,cnt,act,targ,cr) \ |
| 364 | */ | 260 | VOP(vop_sendfile, vp)(VNHEAD(vp),f,off,ioflags,cnt,act,targ,cr) |
| 365 | #define VOP_FLUSH_PAGES(vp, first, last, flags, fiopt, rv) \ | 261 | #define bhv_vop_splice_read(vp,f,o,pipe,cnt,fl,iofl,cr) \ |
| 366 | rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt) | 262 | VOP(vop_splice_read, vp)(VNHEAD(vp),f,o,pipe,cnt,fl,iofl,cr) |
| 367 | #define VOP_IOCTL(vp, inode, filp, fl, cmd, arg, rv) \ | 263 | #define bhv_vop_splice_write(vp,f,o,pipe,cnt,fl,iofl,cr) \ |
| 368 | rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,fl,cmd,arg) | 264 | VOP(vop_splice_write, vp)(VNHEAD(vp),f,o,pipe,cnt,fl,iofl,cr) |
| 369 | #define VOP_IFLUSH(vp, flags, rv) \ | 265 | #define bhv_vop_bmap(vp,of,sz,rw,b,n) \ |
| 370 | rv = _VOP_(vop_iflush, vp)((vp)->v_fbhv, flags) | 266 | VOP(vop_bmap, vp)(VNHEAD(vp),of,sz,rw,b,n) |
| 267 | #define bhv_vop_getattr(vp, vap,f,cr) \ | ||
| 268 | VOP(vop_getattr, vp)(VNHEAD(vp), vap,f,cr) | ||
| 269 | #define bhv_vop_setattr(vp, vap,f,cr) \ | ||
| 270 | VOP(vop_setattr, vp)(VNHEAD(vp), vap,f,cr) | ||
| 271 | #define bhv_vop_access(vp, mode,cr) VOP(vop_access, vp)(VNHEAD(vp), mode,cr) | ||
| 272 | #define bhv_vop_lookup(vp,d,vpp,f,rdir,cr) \ | ||
| 273 | VOP(vop_lookup, vp)(VNHEAD(vp),d,vpp,f,rdir,cr) | ||
| 274 | #define bhv_vop_create(dvp,d,vap,vpp,cr) \ | ||
| 275 | VOP(vop_create, dvp)(VNHEAD(dvp),d,vap,vpp,cr) | ||
| 276 | #define bhv_vop_remove(dvp,d,cr) VOP(vop_remove, dvp)(VNHEAD(dvp),d,cr) | ||
| 277 | #define bhv_vop_link(dvp,fvp,d,cr) VOP(vop_link, dvp)(VNHEAD(dvp),fvp,d,cr) | ||
| 278 | #define bhv_vop_rename(fvp,fnm,tdvp,tnm,cr) \ | ||
| 279 | VOP(vop_rename, fvp)(VNHEAD(fvp),fnm,tdvp,tnm,cr) | ||
| 280 | #define bhv_vop_mkdir(dp,d,vap,vpp,cr) \ | ||
| 281 | VOP(vop_mkdir, dp)(VNHEAD(dp),d,vap,vpp,cr) | ||
| 282 | #define bhv_vop_rmdir(dp,d,cr) VOP(vop_rmdir, dp)(VNHEAD(dp),d,cr) | ||
| 283 | #define bhv_vop_readdir(vp,uiop,cr,eofp) \ | ||
| 284 | VOP(vop_readdir, vp)(VNHEAD(vp),uiop,cr,eofp) | ||
| 285 | #define bhv_vop_symlink(dvp,d,vap,tnm,vpp,cr) \ | ||
| 286 | VOP(vop_symlink, dvp)(VNHEAD(dvp),d,vap,tnm,vpp,cr) | ||
| 287 | #define bhv_vop_readlink(vp,uiop,fl,cr) \ | ||
| 288 | VOP(vop_readlink, vp)(VNHEAD(vp),uiop,fl,cr) | ||
| 289 | #define bhv_vop_fsync(vp,f,cr,b,e) VOP(vop_fsync, vp)(VNHEAD(vp),f,cr,b,e) | ||
| 290 | #define bhv_vop_inactive(vp,cr) VOP(vop_inactive, vp)(VNHEAD(vp),cr) | ||
| 291 | #define bhv_vop_release(vp) VOP(vop_release, vp)(VNHEAD(vp)) | ||
| 292 | #define bhv_vop_fid2(vp,fidp) VOP(vop_fid2, vp)(VNHEAD(vp),fidp) | ||
| 293 | #define bhv_vop_rwlock(vp,i) VOP(vop_rwlock, vp)(VNHEAD(vp),i) | ||
| 294 | #define bhv_vop_rwlock_try(vp,i) VOP(vop_rwlock, vp)(VNHEAD(vp),i) | ||
| 295 | #define bhv_vop_rwunlock(vp,i) VOP(vop_rwunlock, vp)(VNHEAD(vp),i) | ||
| 296 | #define bhv_vop_frlock(vp,c,fl,flags,offset,fr) \ | ||
| 297 | VOP(vop_frlock, vp)(VNHEAD(vp),c,fl,flags,offset,fr) | ||
| 298 | #define bhv_vop_reclaim(vp) VOP(vop_reclaim, vp)(VNHEAD(vp)) | ||
| 299 | #define bhv_vop_attr_get(vp, name, val, vallenp, fl, cred) \ | ||
| 300 | VOP(vop_attr_get, vp)(VNHEAD(vp),name,val,vallenp,fl,cred) | ||
| 301 | #define bhv_vop_attr_set(vp, name, val, vallen, fl, cred) \ | ||
| 302 | VOP(vop_attr_set, vp)(VNHEAD(vp),name,val,vallen,fl,cred) | ||
| 303 | #define bhv_vop_attr_remove(vp, name, flags, cred) \ | ||
| 304 | VOP(vop_attr_remove, vp)(VNHEAD(vp),name,flags,cred) | ||
| 305 | #define bhv_vop_attr_list(vp, buf, buflen, fl, cursor, cred) \ | ||
| 306 | VOP(vop_attr_list, vp)(VNHEAD(vp),buf,buflen,fl,cursor,cred) | ||
| 307 | #define bhv_vop_link_removed(vp, dvp, linkzero) \ | ||
| 308 | VOP(vop_link_removed, vp)(VNHEAD(vp), dvp, linkzero) | ||
| 309 | #define bhv_vop_vnode_change(vp, cmd, val) \ | ||
| 310 | VOP(vop_vnode_change, vp)(VNHEAD(vp), cmd, val) | ||
| 311 | #define bhv_vop_toss_pages(vp, first, last, fiopt) \ | ||
| 312 | VOP(vop_tosspages, vp)(VNHEAD(vp), first, last, fiopt) | ||
| 313 | #define bhv_vop_flushinval_pages(vp, first, last, fiopt) \ | ||
| 314 | VOP(vop_flushinval_pages, vp)(VNHEAD(vp),first,last,fiopt) | ||
| 315 | #define bhv_vop_flush_pages(vp, first, last, flags, fiopt) \ | ||
| 316 | VOP(vop_flush_pages, vp)(VNHEAD(vp),first,last,flags,fiopt) | ||
| 317 | #define bhv_vop_ioctl(vp, inode, filp, fl, cmd, arg) \ | ||
| 318 | VOP(vop_ioctl, vp)(VNHEAD(vp),inode,filp,fl,cmd,arg) | ||
| 319 | #define bhv_vop_iflush(vp, flags) VOP(vop_iflush, vp)(VNHEAD(vp), flags) | ||
| 371 | 320 | ||
| 372 | /* | 321 | /* |
| 373 | * Flags for read/write calls - same values as IRIX | 322 | * Flags for read/write calls - same values as IRIX |
| @@ -377,7 +326,7 @@ typedef struct vnodeops { | |||
| 377 | #define IO_INVIS 0x00020 /* don't update inode timestamps */ | 326 | #define IO_INVIS 0x00020 /* don't update inode timestamps */ |
| 378 | 327 | ||
| 379 | /* | 328 | /* |
| 380 | * Flags for VOP_IFLUSH call | 329 | * Flags for vop_iflush call |
| 381 | */ | 330 | */ |
| 382 | #define FLUSH_SYNC 1 /* wait for flush to complete */ | 331 | #define FLUSH_SYNC 1 /* wait for flush to complete */ |
| 383 | #define FLUSH_INODE 2 /* flush the inode itself */ | 332 | #define FLUSH_INODE 2 /* flush the inode itself */ |
| @@ -385,8 +334,7 @@ typedef struct vnodeops { | |||
| 385 | * this inode out to disk */ | 334 | * this inode out to disk */ |
| 386 | 335 | ||
| 387 | /* | 336 | /* |
| 388 | * Flush/Invalidate options for VOP_TOSS_PAGES, VOP_FLUSHINVAL_PAGES and | 337 | * Flush/Invalidate options for vop_toss/flush/flushinval_pages. |
| 389 | * VOP_FLUSH_PAGES. | ||
| 390 | */ | 338 | */ |
| 391 | #define FI_NONE 0 /* none */ | 339 | #define FI_NONE 0 /* none */ |
| 392 | #define FI_REMAPF 1 /* Do a remapf prior to the operation */ | 340 | #define FI_REMAPF 1 /* Do a remapf prior to the operation */ |
| @@ -398,7 +346,7 @@ typedef struct vnodeops { | |||
| 398 | * Vnode attributes. va_mask indicates those attributes the caller | 346 | * Vnode attributes. va_mask indicates those attributes the caller |
| 399 | * wants to set or extract. | 347 | * wants to set or extract. |
| 400 | */ | 348 | */ |
| 401 | typedef struct vattr { | 349 | typedef struct bhv_vattr { |
| 402 | int va_mask; /* bit-mask of attributes present */ | 350 | int va_mask; /* bit-mask of attributes present */ |
| 403 | mode_t va_mode; /* file access mode and type */ | 351 | mode_t va_mode; /* file access mode and type */ |
| 404 | xfs_nlink_t va_nlink; /* number of references to file */ | 352 | xfs_nlink_t va_nlink; /* number of references to file */ |
| @@ -418,7 +366,7 @@ typedef struct vattr { | |||
| 418 | u_long va_nextents; /* number of extents in file */ | 366 | u_long va_nextents; /* number of extents in file */ |
| 419 | u_long va_anextents; /* number of attr extents in file */ | 367 | u_long va_anextents; /* number of attr extents in file */ |
| 420 | prid_t va_projid; /* project id */ | 368 | prid_t va_projid; /* project id */ |
| 421 | } vattr_t; | 369 | } bhv_vattr_t; |
| 422 | 370 | ||
| 423 | /* | 371 | /* |
| 424 | * setattr or getattr attributes | 372 | * setattr or getattr attributes |
| @@ -492,29 +440,17 @@ typedef struct vattr { | |||
| 492 | (VN_ISREG(vp) && ((mode) & (VSGID|(VEXEC>>3))) == VSGID) | 440 | (VN_ISREG(vp) && ((mode) & (VSGID|(VEXEC>>3))) == VSGID) |
| 493 | 441 | ||
| 494 | extern void vn_init(void); | 442 | extern void vn_init(void); |
| 495 | extern vnode_t *vn_initialize(struct inode *); | 443 | extern bhv_vnode_t *vn_initialize(struct inode *); |
| 496 | 444 | extern int vn_revalidate(struct bhv_vnode *); | |
| 497 | /* | 445 | extern int __vn_revalidate(struct bhv_vnode *, bhv_vattr_t *); |
| 498 | * vnode_map structures _must_ match vn_epoch and vnode structure sizes. | 446 | extern void vn_revalidate_core(struct bhv_vnode *, bhv_vattr_t *); |
| 499 | */ | ||
| 500 | typedef struct vnode_map { | ||
| 501 | vfs_t *v_vfsp; | ||
| 502 | vnumber_t v_number; /* in-core vnode number */ | ||
| 503 | xfs_ino_t v_ino; /* inode # */ | ||
| 504 | } vmap_t; | ||
| 505 | |||
| 506 | #define VMAP(vp, vmap) {(vmap).v_vfsp = (vp)->v_vfsp, \ | ||
| 507 | (vmap).v_number = (vp)->v_number, \ | ||
| 508 | (vmap).v_ino = (vp)->v_inode.i_ino; } | ||
| 509 | 447 | ||
| 510 | extern int vn_revalidate(struct vnode *); | 448 | extern void vn_iowait(struct bhv_vnode *vp); |
| 511 | extern int __vn_revalidate(struct vnode *, vattr_t *); | 449 | extern void vn_iowake(struct bhv_vnode *vp); |
| 512 | extern void vn_revalidate_core(struct vnode *, vattr_t *); | ||
| 513 | 450 | ||
| 514 | extern void vn_iowait(struct vnode *vp); | 451 | extern void vn_ioerror(struct bhv_vnode *vp, int error, char *f, int l); |
| 515 | extern void vn_iowake(struct vnode *vp); | ||
| 516 | 452 | ||
| 517 | static inline int vn_count(struct vnode *vp) | 453 | static inline int vn_count(struct bhv_vnode *vp) |
| 518 | { | 454 | { |
| 519 | return atomic_read(&vn_to_inode(vp)->i_count); | 455 | return atomic_read(&vn_to_inode(vp)->i_count); |
| 520 | } | 456 | } |
| @@ -522,7 +458,7 @@ static inline int vn_count(struct vnode *vp) | |||
| 522 | /* | 458 | /* |
| 523 | * Vnode reference counting functions (and macros for compatibility). | 459 | * Vnode reference counting functions (and macros for compatibility). |
| 524 | */ | 460 | */ |
| 525 | extern vnode_t *vn_hold(struct vnode *); | 461 | extern bhv_vnode_t *vn_hold(struct bhv_vnode *); |
| 526 | 462 | ||
| 527 | #if defined(XFS_VNODE_TRACE) | 463 | #if defined(XFS_VNODE_TRACE) |
| 528 | #define VN_HOLD(vp) \ | 464 | #define VN_HOLD(vp) \ |
| @@ -536,7 +472,7 @@ extern vnode_t *vn_hold(struct vnode *); | |||
| 536 | #define VN_RELE(vp) (iput(vn_to_inode(vp))) | 472 | #define VN_RELE(vp) (iput(vn_to_inode(vp))) |
| 537 | #endif | 473 | #endif |
| 538 | 474 | ||
| 539 | static inline struct vnode *vn_grab(struct vnode *vp) | 475 | static inline struct bhv_vnode *vn_grab(struct bhv_vnode *vp) |
| 540 | { | 476 | { |
| 541 | struct inode *inode = igrab(vn_to_inode(vp)); | 477 | struct inode *inode = igrab(vn_to_inode(vp)); |
| 542 | return inode ? vn_from_inode(inode) : NULL; | 478 | return inode ? vn_from_inode(inode) : NULL; |
| @@ -554,32 +490,39 @@ static inline struct vnode *vn_grab(struct vnode *vp) | |||
| 554 | */ | 490 | */ |
| 555 | #define VN_LOCK(vp) mutex_spinlock(&(vp)->v_lock) | 491 | #define VN_LOCK(vp) mutex_spinlock(&(vp)->v_lock) |
| 556 | #define VN_UNLOCK(vp, s) mutex_spinunlock(&(vp)->v_lock, s) | 492 | #define VN_UNLOCK(vp, s) mutex_spinunlock(&(vp)->v_lock, s) |
| 557 | #define VN_FLAGSET(vp,b) vn_flagset(vp,b) | ||
| 558 | #define VN_FLAGCLR(vp,b) vn_flagclr(vp,b) | ||
| 559 | 493 | ||
| 560 | static __inline__ void vn_flagset(struct vnode *vp, uint flag) | 494 | static __inline__ void vn_flagset(struct bhv_vnode *vp, uint flag) |
| 561 | { | 495 | { |
| 562 | spin_lock(&vp->v_lock); | 496 | spin_lock(&vp->v_lock); |
| 563 | vp->v_flag |= flag; | 497 | vp->v_flag |= flag; |
| 564 | spin_unlock(&vp->v_lock); | 498 | spin_unlock(&vp->v_lock); |
| 565 | } | 499 | } |
| 566 | 500 | ||
| 567 | static __inline__ void vn_flagclr(struct vnode *vp, uint flag) | 501 | static __inline__ uint vn_flagclr(struct bhv_vnode *vp, uint flag) |
| 568 | { | 502 | { |
| 503 | uint cleared; | ||
| 504 | |||
| 569 | spin_lock(&vp->v_lock); | 505 | spin_lock(&vp->v_lock); |
| 506 | cleared = (vp->v_flag & flag); | ||
| 570 | vp->v_flag &= ~flag; | 507 | vp->v_flag &= ~flag; |
| 571 | spin_unlock(&vp->v_lock); | 508 | spin_unlock(&vp->v_lock); |
| 509 | return cleared; | ||
| 572 | } | 510 | } |
| 573 | 511 | ||
| 512 | #define VMODIFY(vp) vn_flagset(vp, VMODIFIED) | ||
| 513 | #define VUNMODIFY(vp) vn_flagclr(vp, VMODIFIED) | ||
| 514 | #define VTRUNCATE(vp) vn_flagset(vp, VTRUNCATED) | ||
| 515 | #define VUNTRUNCATE(vp) vn_flagclr(vp, VTRUNCATED) | ||
| 516 | |||
| 574 | /* | 517 | /* |
| 575 | * Dealing with bad inodes | 518 | * Dealing with bad inodes |
| 576 | */ | 519 | */ |
| 577 | static inline void vn_mark_bad(struct vnode *vp) | 520 | static inline void vn_mark_bad(struct bhv_vnode *vp) |
| 578 | { | 521 | { |
| 579 | make_bad_inode(vn_to_inode(vp)); | 522 | make_bad_inode(vn_to_inode(vp)); |
| 580 | } | 523 | } |
| 581 | 524 | ||
| 582 | static inline int VN_BAD(struct vnode *vp) | 525 | static inline int VN_BAD(struct bhv_vnode *vp) |
| 583 | { | 526 | { |
| 584 | return is_bad_inode(vn_to_inode(vp)); | 527 | return is_bad_inode(vn_to_inode(vp)); |
| 585 | } | 528 | } |
| @@ -587,18 +530,18 @@ static inline int VN_BAD(struct vnode *vp) | |||
| 587 | /* | 530 | /* |
| 588 | * Extracting atime values in various formats | 531 | * Extracting atime values in various formats |
| 589 | */ | 532 | */ |
| 590 | static inline void vn_atime_to_bstime(struct vnode *vp, xfs_bstime_t *bs_atime) | 533 | static inline void vn_atime_to_bstime(bhv_vnode_t *vp, xfs_bstime_t *bs_atime) |
| 591 | { | 534 | { |
| 592 | bs_atime->tv_sec = vp->v_inode.i_atime.tv_sec; | 535 | bs_atime->tv_sec = vp->v_inode.i_atime.tv_sec; |
| 593 | bs_atime->tv_nsec = vp->v_inode.i_atime.tv_nsec; | 536 | bs_atime->tv_nsec = vp->v_inode.i_atime.tv_nsec; |
| 594 | } | 537 | } |
| 595 | 538 | ||
| 596 | static inline void vn_atime_to_timespec(struct vnode *vp, struct timespec *ts) | 539 | static inline void vn_atime_to_timespec(bhv_vnode_t *vp, struct timespec *ts) |
| 597 | { | 540 | { |
| 598 | *ts = vp->v_inode.i_atime; | 541 | *ts = vp->v_inode.i_atime; |
| 599 | } | 542 | } |
| 600 | 543 | ||
| 601 | static inline void vn_atime_to_time_t(struct vnode *vp, time_t *tt) | 544 | static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) |
| 602 | { | 545 | { |
| 603 | *tt = vp->v_inode.i_atime.tv_sec; | 546 | *tt = vp->v_inode.i_atime.tv_sec; |
| 604 | } | 547 | } |
| @@ -610,11 +553,10 @@ static inline void vn_atime_to_time_t(struct vnode *vp, time_t *tt) | |||
| 610 | #define VN_CACHED(vp) (vn_to_inode(vp)->i_mapping->nrpages) | 553 | #define VN_CACHED(vp) (vn_to_inode(vp)->i_mapping->nrpages) |
| 611 | #define VN_DIRTY(vp) mapping_tagged(vn_to_inode(vp)->i_mapping, \ | 554 | #define VN_DIRTY(vp) mapping_tagged(vn_to_inode(vp)->i_mapping, \ |
| 612 | PAGECACHE_TAG_DIRTY) | 555 | PAGECACHE_TAG_DIRTY) |
| 613 | #define VMODIFY(vp) VN_FLAGSET(vp, VMODIFIED) | 556 | #define VN_TRUNC(vp) ((vp)->v_flag & VTRUNCATED) |
| 614 | #define VUNMODIFY(vp) VN_FLAGCLR(vp, VMODIFIED) | ||
| 615 | 557 | ||
| 616 | /* | 558 | /* |
| 617 | * Flags to VOP_SETATTR/VOP_GETATTR. | 559 | * Flags to vop_setattr/getattr. |
| 618 | */ | 560 | */ |
| 619 | #define ATTR_UTIME 0x01 /* non-default utime(2) request */ | 561 | #define ATTR_UTIME 0x01 /* non-default utime(2) request */ |
| 620 | #define ATTR_DMI 0x08 /* invocation from a DMI function */ | 562 | #define ATTR_DMI 0x08 /* invocation from a DMI function */ |
| @@ -624,7 +566,7 @@ static inline void vn_atime_to_time_t(struct vnode *vp, time_t *tt) | |||
| 624 | #define ATTR_NOSIZETOK 0x400 /* Don't get the SIZE token */ | 566 | #define ATTR_NOSIZETOK 0x400 /* Don't get the SIZE token */ |
| 625 | 567 | ||
| 626 | /* | 568 | /* |
| 627 | * Flags to VOP_FSYNC and VOP_RECLAIM. | 569 | * Flags to vop_fsync/reclaim. |
| 628 | */ | 570 | */ |
| 629 | #define FSYNC_NOWAIT 0 /* asynchronous flush */ | 571 | #define FSYNC_NOWAIT 0 /* asynchronous flush */ |
| 630 | #define FSYNC_WAIT 0x1 /* synchronous fsync or forced reclaim */ | 572 | #define FSYNC_WAIT 0x1 /* synchronous fsync or forced reclaim */ |
| @@ -643,11 +585,11 @@ static inline void vn_atime_to_time_t(struct vnode *vp, time_t *tt) | |||
| 643 | #define VNODE_KTRACE_REF 4 | 585 | #define VNODE_KTRACE_REF 4 |
| 644 | #define VNODE_KTRACE_RELE 5 | 586 | #define VNODE_KTRACE_RELE 5 |
| 645 | 587 | ||
| 646 | extern void vn_trace_entry(struct vnode *, const char *, inst_t *); | 588 | extern void vn_trace_entry(struct bhv_vnode *, const char *, inst_t *); |
| 647 | extern void vn_trace_exit(struct vnode *, const char *, inst_t *); | 589 | extern void vn_trace_exit(struct bhv_vnode *, const char *, inst_t *); |
| 648 | extern void vn_trace_hold(struct vnode *, char *, int, inst_t *); | 590 | extern void vn_trace_hold(struct bhv_vnode *, char *, int, inst_t *); |
| 649 | extern void vn_trace_ref(struct vnode *, char *, int, inst_t *); | 591 | extern void vn_trace_ref(struct bhv_vnode *, char *, int, inst_t *); |
| 650 | extern void vn_trace_rele(struct vnode *, char *, int, inst_t *); | 592 | extern void vn_trace_rele(struct bhv_vnode *, char *, int, inst_t *); |
| 651 | 593 | ||
| 652 | #define VN_TRACE(vp) \ | 594 | #define VN_TRACE(vp) \ |
| 653 | vn_trace_ref(vp, __FILE__, __LINE__, (inst_t *)__return_address) | 595 | vn_trace_ref(vp, __FILE__, __LINE__, (inst_t *)__return_address) |
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index 772ac48329ea..3aa771531856 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_alloc.h" | 27 | #include "xfs_alloc.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| @@ -444,7 +442,7 @@ xfs_qm_dqalloc( | |||
| 444 | XFS_BMAPI_METADATA | XFS_BMAPI_WRITE, | 442 | XFS_BMAPI_METADATA | XFS_BMAPI_WRITE, |
| 445 | &firstblock, | 443 | &firstblock, |
| 446 | XFS_QM_DQALLOC_SPACE_RES(mp), | 444 | XFS_QM_DQALLOC_SPACE_RES(mp), |
| 447 | &map, &nmaps, &flist))) { | 445 | &map, &nmaps, &flist, NULL))) { |
| 448 | goto error0; | 446 | goto error0; |
| 449 | } | 447 | } |
| 450 | ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB); | 448 | ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB); |
| @@ -559,7 +557,7 @@ xfs_qm_dqtobp( | |||
| 559 | error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset, | 557 | error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset, |
| 560 | XFS_DQUOT_CLUSTER_SIZE_FSB, | 558 | XFS_DQUOT_CLUSTER_SIZE_FSB, |
| 561 | XFS_BMAPI_METADATA, | 559 | XFS_BMAPI_METADATA, |
| 562 | NULL, 0, &map, &nmaps, NULL); | 560 | NULL, 0, &map, &nmaps, NULL, NULL); |
| 563 | 561 | ||
| 564 | xfs_iunlock(quotip, XFS_ILOCK_SHARED); | 562 | xfs_iunlock(quotip, XFS_ILOCK_SHARED); |
| 565 | if (error) | 563 | if (error) |
| @@ -1261,7 +1259,7 @@ xfs_qm_dqflush( | |||
| 1261 | 1259 | ||
| 1262 | if (xfs_qm_dqcheck(&dqp->q_core, be32_to_cpu(ddqp->d_id), | 1260 | if (xfs_qm_dqcheck(&dqp->q_core, be32_to_cpu(ddqp->d_id), |
| 1263 | 0, XFS_QMOPT_DOWARN, "dqflush (incore copy)")) { | 1261 | 0, XFS_QMOPT_DOWARN, "dqflush (incore copy)")) { |
| 1264 | xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE); | 1262 | xfs_force_shutdown(dqp->q_mount, SHUTDOWN_CORRUPT_INCORE); |
| 1265 | return XFS_ERROR(EIO); | 1263 | return XFS_ERROR(EIO); |
| 1266 | } | 1264 | } |
| 1267 | 1265 | ||
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h index c0c629663a5c..78d3ab95c5fd 100644 --- a/fs/xfs/quota/xfs_dquot.h +++ b/fs/xfs/quota/xfs_dquot.h | |||
| @@ -119,7 +119,7 @@ XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp) | |||
| 119 | */ | 119 | */ |
| 120 | #define xfs_dqflock(dqp) { psema(&((dqp)->q_flock), PINOD | PRECALC);\ | 120 | #define xfs_dqflock(dqp) { psema(&((dqp)->q_flock), PINOD | PRECALC);\ |
| 121 | (dqp)->dq_flags |= XFS_DQ_FLOCKED; } | 121 | (dqp)->dq_flags |= XFS_DQ_FLOCKED; } |
| 122 | #define xfs_dqfunlock(dqp) { ASSERT(valusema(&((dqp)->q_flock)) <= 0); \ | 122 | #define xfs_dqfunlock(dqp) { ASSERT(issemalocked(&((dqp)->q_flock))); \ |
| 123 | vsema(&((dqp)->q_flock)); \ | 123 | vsema(&((dqp)->q_flock)); \ |
| 124 | (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); } | 124 | (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); } |
| 125 | 125 | ||
| @@ -128,7 +128,7 @@ XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp) | |||
| 128 | #define XFS_DQ_PINUNLOCK(dqp, s) mutex_spinunlock( \ | 128 | #define XFS_DQ_PINUNLOCK(dqp, s) mutex_spinunlock( \ |
| 129 | &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s) | 129 | &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s) |
| 130 | 130 | ||
| 131 | #define XFS_DQ_IS_FLUSH_LOCKED(dqp) (valusema(&((dqp)->q_flock)) <= 0) | 131 | #define XFS_DQ_IS_FLUSH_LOCKED(dqp) (issemalocked(&((dqp)->q_flock))) |
| 132 | #define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp)) | 132 | #define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp)) |
| 133 | #define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) | 133 | #define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) |
| 134 | #define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER) | 134 | #define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER) |
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index 546f48af882a..5b2dcc58b244 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_alloc.h" | 27 | #include "xfs_alloc.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| @@ -248,7 +246,7 @@ xfs_qm_dquot_logitem_pushbuf( | |||
| 248 | * inode flush completed and the inode was taken off the AIL. | 246 | * inode flush completed and the inode was taken off the AIL. |
| 249 | * So, just get out. | 247 | * So, just get out. |
| 250 | */ | 248 | */ |
| 251 | if ((valusema(&(dqp->q_flock)) > 0) || | 249 | if (!issemalocked(&(dqp->q_flock)) || |
| 252 | ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) { | 250 | ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) { |
| 253 | qip->qli_pushbuf_flag = 0; | 251 | qip->qli_pushbuf_flag = 0; |
| 254 | xfs_dqunlock(dqp); | 252 | xfs_dqunlock(dqp); |
| @@ -261,7 +259,7 @@ xfs_qm_dquot_logitem_pushbuf( | |||
| 261 | if (bp != NULL) { | 259 | if (bp != NULL) { |
| 262 | if (XFS_BUF_ISDELAYWRITE(bp)) { | 260 | if (XFS_BUF_ISDELAYWRITE(bp)) { |
| 263 | dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && | 261 | dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && |
| 264 | (valusema(&(dqp->q_flock)) <= 0)); | 262 | issemalocked(&(dqp->q_flock))); |
| 265 | qip->qli_pushbuf_flag = 0; | 263 | qip->qli_pushbuf_flag = 0; |
| 266 | xfs_dqunlock(dqp); | 264 | xfs_dqunlock(dqp); |
| 267 | 265 | ||
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 7fb5eca9bd50..e23e45535c48 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_alloc.h" | 28 | #include "xfs_alloc.h" |
| 30 | #include "xfs_dmapi.h" | 29 | #include "xfs_dmapi.h" |
| @@ -33,7 +32,6 @@ | |||
| 33 | #include "xfs_bmap_btree.h" | 32 | #include "xfs_bmap_btree.h" |
| 34 | #include "xfs_alloc_btree.h" | 33 | #include "xfs_alloc_btree.h" |
| 35 | #include "xfs_ialloc_btree.h" | 34 | #include "xfs_ialloc_btree.h" |
| 36 | #include "xfs_dir_sf.h" | ||
| 37 | #include "xfs_dir2_sf.h" | 35 | #include "xfs_dir2_sf.h" |
| 38 | #include "xfs_attr_sf.h" | 36 | #include "xfs_attr_sf.h" |
| 39 | #include "xfs_dinode.h" | 37 | #include "xfs_dinode.h" |
| @@ -1603,7 +1601,7 @@ xfs_qm_dqiterate( | |||
| 1603 | maxlblkcnt - lblkno, | 1601 | maxlblkcnt - lblkno, |
| 1604 | XFS_BMAPI_METADATA, | 1602 | XFS_BMAPI_METADATA, |
| 1605 | NULL, | 1603 | NULL, |
| 1606 | 0, map, &nmaps, NULL); | 1604 | 0, map, &nmaps, NULL, NULL); |
| 1607 | xfs_iunlock(qip, XFS_ILOCK_SHARED); | 1605 | xfs_iunlock(qip, XFS_ILOCK_SHARED); |
| 1608 | if (error) | 1606 | if (error) |
| 1609 | break; | 1607 | break; |
| @@ -1905,9 +1903,7 @@ xfs_qm_quotacheck( | |||
| 1905 | */ | 1903 | */ |
| 1906 | if ((error = xfs_bulkstat(mp, &lastino, &count, | 1904 | if ((error = xfs_bulkstat(mp, &lastino, &count, |
| 1907 | xfs_qm_dqusage_adjust, NULL, | 1905 | xfs_qm_dqusage_adjust, NULL, |
| 1908 | structsz, NULL, | 1906 | structsz, NULL, BULKSTAT_FG_IGET, &done))) |
| 1909 | BULKSTAT_FG_IGET|BULKSTAT_FG_VFSLOCKED, | ||
| 1910 | &done))) | ||
| 1911 | break; | 1907 | break; |
| 1912 | 1908 | ||
| 1913 | } while (! done); | 1909 | } while (! done); |
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c index 6838b36d95a9..e95e99f7168f 100644 --- a/fs/xfs/quota/xfs_qm_bhv.c +++ b/fs/xfs/quota/xfs_qm_bhv.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -24,7 +24,6 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_alloc.h" | 28 | #include "xfs_alloc.h" |
| 30 | #include "xfs_dmapi.h" | 29 | #include "xfs_dmapi.h" |
| @@ -33,7 +32,6 @@ | |||
| 33 | #include "xfs_bmap_btree.h" | 32 | #include "xfs_bmap_btree.h" |
| 34 | #include "xfs_alloc_btree.h" | 33 | #include "xfs_alloc_btree.h" |
| 35 | #include "xfs_ialloc_btree.h" | 34 | #include "xfs_ialloc_btree.h" |
| 36 | #include "xfs_dir_sf.h" | ||
| 37 | #include "xfs_dir2_sf.h" | 35 | #include "xfs_dir2_sf.h" |
| 38 | #include "xfs_attr_sf.h" | 36 | #include "xfs_attr_sf.h" |
| 39 | #include "xfs_dinode.h" | 37 | #include "xfs_dinode.h" |
| @@ -129,7 +127,7 @@ xfs_qm_parseargs( | |||
| 129 | return XFS_ERROR(EINVAL); | 127 | return XFS_ERROR(EINVAL); |
| 130 | } | 128 | } |
| 131 | 129 | ||
| 132 | PVFS_PARSEARGS(BHV_NEXT(bhv), options, args, update, error); | 130 | error = bhv_next_vfs_parseargs(BHV_NEXT(bhv), options, args, update); |
| 133 | if (!error && !referenced) | 131 | if (!error && !referenced) |
| 134 | bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM); | 132 | bhv_remove_vfsops(bhvtovfs(bhv), VFS_POSITION_QM); |
| 135 | return error; | 133 | return error; |
| @@ -140,9 +138,8 @@ xfs_qm_showargs( | |||
| 140 | struct bhv_desc *bhv, | 138 | struct bhv_desc *bhv, |
| 141 | struct seq_file *m) | 139 | struct seq_file *m) |
| 142 | { | 140 | { |
| 143 | struct vfs *vfsp = bhvtovfs(bhv); | 141 | struct bhv_vfs *vfsp = bhvtovfs(bhv); |
| 144 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); | 142 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); |
| 145 | int error; | ||
| 146 | 143 | ||
| 147 | if (mp->m_qflags & XFS_UQUOTA_ACCT) { | 144 | if (mp->m_qflags & XFS_UQUOTA_ACCT) { |
| 148 | (mp->m_qflags & XFS_UQUOTA_ENFD) ? | 145 | (mp->m_qflags & XFS_UQUOTA_ENFD) ? |
| @@ -165,8 +162,7 @@ xfs_qm_showargs( | |||
| 165 | if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) | 162 | if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) |
| 166 | seq_puts(m, "," MNTOPT_NOQUOTA); | 163 | seq_puts(m, "," MNTOPT_NOQUOTA); |
| 167 | 164 | ||
| 168 | PVFS_SHOWARGS(BHV_NEXT(bhv), m, error); | 165 | return bhv_next_vfs_showargs(BHV_NEXT(bhv), m); |
| 169 | return error; | ||
| 170 | } | 166 | } |
| 171 | 167 | ||
| 172 | STATIC int | 168 | STATIC int |
| @@ -175,14 +171,67 @@ xfs_qm_mount( | |||
| 175 | struct xfs_mount_args *args, | 171 | struct xfs_mount_args *args, |
| 176 | struct cred *cr) | 172 | struct cred *cr) |
| 177 | { | 173 | { |
| 178 | struct vfs *vfsp = bhvtovfs(bhv); | 174 | struct bhv_vfs *vfsp = bhvtovfs(bhv); |
| 179 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); | 175 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); |
| 180 | int error; | ||
| 181 | 176 | ||
| 182 | if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | XFSMNT_PQUOTA)) | 177 | if (args->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | XFSMNT_PQUOTA)) |
| 183 | xfs_qm_mount_quotainit(mp, args->flags); | 178 | xfs_qm_mount_quotainit(mp, args->flags); |
| 184 | PVFS_MOUNT(BHV_NEXT(bhv), args, cr, error); | 179 | return bhv_next_vfs_mount(BHV_NEXT(bhv), args, cr); |
| 185 | return error; | 180 | } |
| 181 | |||
| 182 | /* | ||
| 183 | * Directory tree accounting is implemented using project quotas, where | ||
| 184 | * the project identifier is inherited from parent directories. | ||
| 185 | * A statvfs (df, etc.) of a directory that is using project quota should | ||
| 186 | * return a statvfs of the project, not the entire filesystem. | ||
| 187 | * This makes such trees appear as if they are filesystems in themselves. | ||
| 188 | */ | ||
| 189 | STATIC int | ||
| 190 | xfs_qm_statvfs( | ||
| 191 | struct bhv_desc *bhv, | ||
| 192 | bhv_statvfs_t *statp, | ||
| 193 | struct bhv_vnode *vnode) | ||
| 194 | { | ||
| 195 | xfs_mount_t *mp; | ||
| 196 | xfs_inode_t *ip; | ||
| 197 | xfs_dquot_t *dqp; | ||
| 198 | xfs_disk_dquot_t *dp; | ||
| 199 | __uint64_t limit; | ||
| 200 | int error; | ||
| 201 | |||
| 202 | error = bhv_next_vfs_statvfs(BHV_NEXT(bhv), statp, vnode); | ||
| 203 | if (error || !vnode) | ||
| 204 | return error; | ||
| 205 | |||
| 206 | mp = XFS_BHVTOM(bhv); | ||
| 207 | ip = xfs_vtoi(vnode); | ||
| 208 | |||
| 209 | if (!(ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)) | ||
| 210 | return 0; | ||
| 211 | if (!(mp->m_qflags & XFS_PQUOTA_ACCT)) | ||
| 212 | return 0; | ||
| 213 | if (!(mp->m_qflags & XFS_OQUOTA_ENFD)) | ||
| 214 | return 0; | ||
| 215 | |||
| 216 | if (xfs_qm_dqget(mp, NULL, ip->i_d.di_projid, XFS_DQ_PROJ, 0, &dqp)) | ||
| 217 | return 0; | ||
| 218 | dp = &dqp->q_core; | ||
| 219 | |||
| 220 | limit = dp->d_blk_softlimit ? dp->d_blk_softlimit : dp->d_blk_hardlimit; | ||
| 221 | if (limit && statp->f_blocks > limit) { | ||
| 222 | statp->f_blocks = limit; | ||
| 223 | statp->f_bfree = (statp->f_blocks > dp->d_bcount) ? | ||
| 224 | (statp->f_blocks - dp->d_bcount) : 0; | ||
| 225 | } | ||
| 226 | limit = dp->d_ino_softlimit ? dp->d_ino_softlimit : dp->d_ino_hardlimit; | ||
| 227 | if (limit && statp->f_files > limit) { | ||
| 228 | statp->f_files = limit; | ||
| 229 | statp->f_ffree = (statp->f_files > dp->d_icount) ? | ||
| 230 | (statp->f_ffree - dp->d_icount) : 0; | ||
| 231 | } | ||
| 232 | |||
| 233 | xfs_qm_dqput(dqp); | ||
| 234 | return 0; | ||
| 186 | } | 235 | } |
| 187 | 236 | ||
| 188 | STATIC int | 237 | STATIC int |
| @@ -191,7 +240,7 @@ xfs_qm_syncall( | |||
| 191 | int flags, | 240 | int flags, |
| 192 | cred_t *credp) | 241 | cred_t *credp) |
| 193 | { | 242 | { |
| 194 | struct vfs *vfsp = bhvtovfs(bhv); | 243 | struct bhv_vfs *vfsp = bhvtovfs(bhv); |
| 195 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); | 244 | struct xfs_mount *mp = XFS_VFSTOM(vfsp); |
| 196 | int error; | 245 | int error; |
| 197 | 246 | ||
| @@ -210,8 +259,7 @@ xfs_qm_syncall( | |||
| 210 | } | 259 | } |
| 211 | } | 260 | } |
| 212 | } | 261 | } |
| 213 | PVFS_SYNC(BHV_NEXT(bhv), flags, credp, error); | 262 | return bhv_next_vfs_sync(BHV_NEXT(bhv), flags, credp); |
| 214 | return error; | ||
| 215 | } | 263 | } |
| 216 | 264 | ||
| 217 | STATIC int | 265 | STATIC int |
| @@ -346,11 +394,12 @@ STATIC struct xfs_qmops xfs_qmcore_xfs = { | |||
| 346 | .xfs_dqtrxops = &xfs_trans_dquot_ops, | 394 | .xfs_dqtrxops = &xfs_trans_dquot_ops, |
| 347 | }; | 395 | }; |
| 348 | 396 | ||
| 349 | struct bhv_vfsops xfs_qmops = { { | 397 | struct bhv_module_vfsops xfs_qmops = { { |
| 350 | BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM), | 398 | BHV_IDENTITY_INIT(VFS_BHV_QM, VFS_POSITION_QM), |
| 351 | .vfs_parseargs = xfs_qm_parseargs, | 399 | .vfs_parseargs = xfs_qm_parseargs, |
| 352 | .vfs_showargs = xfs_qm_showargs, | 400 | .vfs_showargs = xfs_qm_showargs, |
| 353 | .vfs_mount = xfs_qm_mount, | 401 | .vfs_mount = xfs_qm_mount, |
| 402 | .vfs_statvfs = xfs_qm_statvfs, | ||
| 354 | .vfs_sync = xfs_qm_syncall, | 403 | .vfs_sync = xfs_qm_syncall, |
| 355 | .vfs_quotactl = xfs_qm_quotactl, }, | 404 | .vfs_quotactl = xfs_qm_quotactl, }, |
| 356 | }; | 405 | }; |
diff --git a/fs/xfs/quota/xfs_qm_stats.c b/fs/xfs/quota/xfs_qm_stats.c index 0570f7733550..6f858fb81a36 100644 --- a/fs/xfs/quota/xfs_qm_stats.c +++ b/fs/xfs/quota/xfs_qm_stats.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_alloc.h" | 27 | #include "xfs_alloc.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index c55db463bbf2..ed620c4d1594 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | #include "xfs_trans.h" | 26 | #include "xfs_trans.h" |
| 27 | #include "xfs_sb.h" | 27 | #include "xfs_sb.h" |
| 28 | #include "xfs_ag.h" | 28 | #include "xfs_ag.h" |
| 29 | #include "xfs_dir.h" | ||
| 30 | #include "xfs_dir2.h" | 29 | #include "xfs_dir2.h" |
| 31 | #include "xfs_alloc.h" | 30 | #include "xfs_alloc.h" |
| 32 | #include "xfs_dmapi.h" | 31 | #include "xfs_dmapi.h" |
| @@ -35,7 +34,6 @@ | |||
| 35 | #include "xfs_bmap_btree.h" | 34 | #include "xfs_bmap_btree.h" |
| 36 | #include "xfs_alloc_btree.h" | 35 | #include "xfs_alloc_btree.h" |
| 37 | #include "xfs_ialloc_btree.h" | 36 | #include "xfs_ialloc_btree.h" |
| 38 | #include "xfs_dir_sf.h" | ||
| 39 | #include "xfs_dir2_sf.h" | 37 | #include "xfs_dir2_sf.h" |
| 40 | #include "xfs_attr_sf.h" | 38 | #include "xfs_attr_sf.h" |
| 41 | #include "xfs_dinode.h" | 39 | #include "xfs_dinode.h" |
| @@ -91,8 +89,8 @@ xfs_qm_quotactl( | |||
| 91 | xfs_caddr_t addr) | 89 | xfs_caddr_t addr) |
| 92 | { | 90 | { |
| 93 | xfs_mount_t *mp; | 91 | xfs_mount_t *mp; |
| 92 | bhv_vfs_t *vfsp; | ||
| 94 | int error; | 93 | int error; |
| 95 | struct vfs *vfsp; | ||
| 96 | 94 | ||
| 97 | vfsp = bhvtovfs(bdp); | 95 | vfsp = bhvtovfs(bdp); |
| 98 | mp = XFS_VFSTOM(vfsp); | 96 | mp = XFS_VFSTOM(vfsp); |
| @@ -1035,7 +1033,7 @@ xfs_qm_dqrele_all_inodes( | |||
| 1035 | { | 1033 | { |
| 1036 | xfs_inode_t *ip, *topino; | 1034 | xfs_inode_t *ip, *topino; |
| 1037 | uint ireclaims; | 1035 | uint ireclaims; |
| 1038 | vnode_t *vp; | 1036 | bhv_vnode_t *vp; |
| 1039 | boolean_t vnode_refd; | 1037 | boolean_t vnode_refd; |
| 1040 | 1038 | ||
| 1041 | ASSERT(mp->m_quotainfo); | 1039 | ASSERT(mp->m_quotainfo); |
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c index 9168918db252..0242e9666e8e 100644 --- a/fs/xfs/quota/xfs_trans_dquot.c +++ b/fs/xfs/quota/xfs_trans_dquot.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_alloc.h" | 27 | #include "xfs_alloc.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| @@ -33,7 +32,6 @@ | |||
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 36 | #include "xfs_dir_sf.h" | ||
| 37 | #include "xfs_dir2_sf.h" | 35 | #include "xfs_dir2_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| 39 | #include "xfs_inode.h" | 37 | #include "xfs_inode.h" |
diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c index b08b3d9345b7..36fbeccdc722 100644 --- a/fs/xfs/support/debug.c +++ b/fs/xfs/support/debug.c | |||
| @@ -47,7 +47,7 @@ cmn_err(register int level, char *fmt, ...) | |||
| 47 | va_start(ap, fmt); | 47 | va_start(ap, fmt); |
| 48 | if (*fmt == '!') fp++; | 48 | if (*fmt == '!') fp++; |
| 49 | len = vsprintf(message, fp, ap); | 49 | len = vsprintf(message, fp, ap); |
| 50 | if (message[len-1] != '\n') | 50 | if (level != CE_DEBUG && message[len-1] != '\n') |
| 51 | strcat(message, "\n"); | 51 | strcat(message, "\n"); |
| 52 | printk("%s%s", err_level[level], message); | 52 | printk("%s%s", err_level[level], message); |
| 53 | va_end(ap); | 53 | va_end(ap); |
| @@ -68,7 +68,7 @@ icmn_err(register int level, char *fmt, va_list ap) | |||
| 68 | level = XFS_MAX_ERR_LEVEL; | 68 | level = XFS_MAX_ERR_LEVEL; |
| 69 | spin_lock_irqsave(&xfs_err_lock,flags); | 69 | spin_lock_irqsave(&xfs_err_lock,flags); |
| 70 | len = vsprintf(message, fmt, ap); | 70 | len = vsprintf(message, fmt, ap); |
| 71 | if (message[len-1] != '\n') | 71 | if (level != CE_DEBUG && message[len-1] != '\n') |
| 72 | strcat(message, "\n"); | 72 | strcat(message, "\n"); |
| 73 | spin_unlock_irqrestore(&xfs_err_lock,flags); | 73 | spin_unlock_irqrestore(&xfs_err_lock,flags); |
| 74 | printk("%s%s", err_level[level], message); | 74 | printk("%s%s", err_level[level], message); |
diff --git a/fs/xfs/support/debug.h b/fs/xfs/support/debug.h index e3bf58112e7e..4f54dca662a8 100644 --- a/fs/xfs/support/debug.h +++ b/fs/xfs/support/debug.h | |||
| @@ -33,9 +33,6 @@ extern void cmn_err(int, char *, ...) | |||
| 33 | __attribute__ ((format (printf, 2, 3))); | 33 | __attribute__ ((format (printf, 2, 3))); |
| 34 | extern void assfail(char *expr, char *f, int l); | 34 | extern void assfail(char *expr, char *f, int l); |
| 35 | 35 | ||
| 36 | #define prdev(fmt,targ,args...) \ | ||
| 37 | printk("Device %s - " fmt "\n", XFS_BUFTARG_NAME(targ), ## args) | ||
| 38 | |||
| 39 | #define ASSERT_ALWAYS(expr) \ | 36 | #define ASSERT_ALWAYS(expr) \ |
| 40 | (unlikely((expr) != 0) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) | 37 | (unlikely((expr) != 0) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) |
| 41 | 38 | ||
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 2539af34eb63..4b0cb474be4c 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c | |||
| @@ -21,12 +21,10 @@ | |||
| 21 | #include "xfs_bit.h" | 21 | #include "xfs_bit.h" |
| 22 | #include "xfs_inum.h" | 22 | #include "xfs_inum.h" |
| 23 | #include "xfs_ag.h" | 23 | #include "xfs_ag.h" |
| 24 | #include "xfs_dir.h" | ||
| 25 | #include "xfs_dir2.h" | 24 | #include "xfs_dir2.h" |
| 26 | #include "xfs_bmap_btree.h" | 25 | #include "xfs_bmap_btree.h" |
| 27 | #include "xfs_alloc_btree.h" | 26 | #include "xfs_alloc_btree.h" |
| 28 | #include "xfs_ialloc_btree.h" | 27 | #include "xfs_ialloc_btree.h" |
| 29 | #include "xfs_dir_sf.h" | ||
| 30 | #include "xfs_dir2_sf.h" | 28 | #include "xfs_dir2_sf.h" |
| 31 | #include "xfs_attr_sf.h" | 29 | #include "xfs_attr_sf.h" |
| 32 | #include "xfs_dinode.h" | 30 | #include "xfs_dinode.h" |
| @@ -39,15 +37,15 @@ | |||
| 39 | #include <linux/capability.h> | 37 | #include <linux/capability.h> |
| 40 | #include <linux/posix_acl_xattr.h> | 38 | #include <linux/posix_acl_xattr.h> |
| 41 | 39 | ||
| 42 | STATIC int xfs_acl_setmode(vnode_t *, xfs_acl_t *, int *); | 40 | STATIC int xfs_acl_setmode(bhv_vnode_t *, xfs_acl_t *, int *); |
| 43 | STATIC void xfs_acl_filter_mode(mode_t, xfs_acl_t *); | 41 | STATIC void xfs_acl_filter_mode(mode_t, xfs_acl_t *); |
| 44 | STATIC void xfs_acl_get_endian(xfs_acl_t *); | 42 | STATIC void xfs_acl_get_endian(xfs_acl_t *); |
| 45 | STATIC int xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *); | 43 | STATIC int xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *); |
| 46 | STATIC int xfs_acl_invalid(xfs_acl_t *); | 44 | STATIC int xfs_acl_invalid(xfs_acl_t *); |
| 47 | STATIC void xfs_acl_sync_mode(mode_t, xfs_acl_t *); | 45 | STATIC void xfs_acl_sync_mode(mode_t, xfs_acl_t *); |
| 48 | STATIC void xfs_acl_get_attr(vnode_t *, xfs_acl_t *, int, int, int *); | 46 | STATIC void xfs_acl_get_attr(bhv_vnode_t *, xfs_acl_t *, int, int, int *); |
| 49 | STATIC void xfs_acl_set_attr(vnode_t *, xfs_acl_t *, int, int *); | 47 | STATIC void xfs_acl_set_attr(bhv_vnode_t *, xfs_acl_t *, int, int *); |
| 50 | STATIC int xfs_acl_allow_set(vnode_t *, int); | 48 | STATIC int xfs_acl_allow_set(bhv_vnode_t *, int); |
| 51 | 49 | ||
| 52 | kmem_zone_t *xfs_acl_zone; | 50 | kmem_zone_t *xfs_acl_zone; |
| 53 | 51 | ||
| @@ -57,7 +55,7 @@ kmem_zone_t *xfs_acl_zone; | |||
| 57 | */ | 55 | */ |
| 58 | int | 56 | int |
| 59 | xfs_acl_vhasacl_access( | 57 | xfs_acl_vhasacl_access( |
| 60 | vnode_t *vp) | 58 | bhv_vnode_t *vp) |
| 61 | { | 59 | { |
| 62 | int error; | 60 | int error; |
| 63 | 61 | ||
| @@ -70,7 +68,7 @@ xfs_acl_vhasacl_access( | |||
| 70 | */ | 68 | */ |
| 71 | int | 69 | int |
| 72 | xfs_acl_vhasacl_default( | 70 | xfs_acl_vhasacl_default( |
| 73 | vnode_t *vp) | 71 | bhv_vnode_t *vp) |
| 74 | { | 72 | { |
| 75 | int error; | 73 | int error; |
| 76 | 74 | ||
| @@ -209,7 +207,7 @@ posix_acl_xfs_to_xattr( | |||
| 209 | 207 | ||
| 210 | int | 208 | int |
| 211 | xfs_acl_vget( | 209 | xfs_acl_vget( |
| 212 | vnode_t *vp, | 210 | bhv_vnode_t *vp, |
| 213 | void *acl, | 211 | void *acl, |
| 214 | size_t size, | 212 | size_t size, |
| 215 | int kind) | 213 | int kind) |
| @@ -241,10 +239,10 @@ xfs_acl_vget( | |||
| 241 | goto out; | 239 | goto out; |
| 242 | } | 240 | } |
| 243 | if (kind == _ACL_TYPE_ACCESS) { | 241 | if (kind == _ACL_TYPE_ACCESS) { |
| 244 | vattr_t va; | 242 | bhv_vattr_t va; |
| 245 | 243 | ||
| 246 | va.va_mask = XFS_AT_MODE; | 244 | va.va_mask = XFS_AT_MODE; |
| 247 | VOP_GETATTR(vp, &va, 0, sys_cred, error); | 245 | error = bhv_vop_getattr(vp, &va, 0, sys_cred); |
| 248 | if (error) | 246 | if (error) |
| 249 | goto out; | 247 | goto out; |
| 250 | xfs_acl_sync_mode(va.va_mode, xfs_acl); | 248 | xfs_acl_sync_mode(va.va_mode, xfs_acl); |
| @@ -260,7 +258,7 @@ out: | |||
| 260 | 258 | ||
| 261 | int | 259 | int |
| 262 | xfs_acl_vremove( | 260 | xfs_acl_vremove( |
| 263 | vnode_t *vp, | 261 | bhv_vnode_t *vp, |
| 264 | int kind) | 262 | int kind) |
| 265 | { | 263 | { |
| 266 | int error; | 264 | int error; |
| @@ -268,9 +266,9 @@ xfs_acl_vremove( | |||
| 268 | VN_HOLD(vp); | 266 | VN_HOLD(vp); |
| 269 | error = xfs_acl_allow_set(vp, kind); | 267 | error = xfs_acl_allow_set(vp, kind); |
| 270 | if (!error) { | 268 | if (!error) { |
| 271 | VOP_ATTR_REMOVE(vp, kind == _ACL_TYPE_DEFAULT? | 269 | error = bhv_vop_attr_remove(vp, kind == _ACL_TYPE_DEFAULT? |
| 272 | SGI_ACL_DEFAULT: SGI_ACL_FILE, | 270 | SGI_ACL_DEFAULT: SGI_ACL_FILE, |
| 273 | ATTR_ROOT, sys_cred, error); | 271 | ATTR_ROOT, sys_cred); |
| 274 | if (error == ENOATTR) | 272 | if (error == ENOATTR) |
| 275 | error = 0; /* 'scool */ | 273 | error = 0; /* 'scool */ |
| 276 | } | 274 | } |
| @@ -280,7 +278,7 @@ xfs_acl_vremove( | |||
| 280 | 278 | ||
| 281 | int | 279 | int |
| 282 | xfs_acl_vset( | 280 | xfs_acl_vset( |
| 283 | vnode_t *vp, | 281 | bhv_vnode_t *vp, |
| 284 | void *acl, | 282 | void *acl, |
| 285 | size_t size, | 283 | size_t size, |
| 286 | int kind) | 284 | int kind) |
| @@ -370,10 +368,10 @@ xfs_acl_iaccess( | |||
| 370 | 368 | ||
| 371 | STATIC int | 369 | STATIC int |
| 372 | xfs_acl_allow_set( | 370 | xfs_acl_allow_set( |
| 373 | vnode_t *vp, | 371 | bhv_vnode_t *vp, |
| 374 | int kind) | 372 | int kind) |
| 375 | { | 373 | { |
| 376 | vattr_t va; | 374 | bhv_vattr_t va; |
| 377 | int error; | 375 | int error; |
| 378 | 376 | ||
| 379 | if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND)) | 377 | if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND)) |
| @@ -383,7 +381,7 @@ xfs_acl_allow_set( | |||
| 383 | if (vp->v_vfsp->vfs_flag & VFS_RDONLY) | 381 | if (vp->v_vfsp->vfs_flag & VFS_RDONLY) |
| 384 | return EROFS; | 382 | return EROFS; |
| 385 | va.va_mask = XFS_AT_UID; | 383 | va.va_mask = XFS_AT_UID; |
| 386 | VOP_GETATTR(vp, &va, 0, NULL, error); | 384 | error = bhv_vop_getattr(vp, &va, 0, NULL); |
| 387 | if (error) | 385 | if (error) |
| 388 | return error; | 386 | return error; |
| 389 | if (va.va_uid != current->fsuid && !capable(CAP_FOWNER)) | 387 | if (va.va_uid != current->fsuid && !capable(CAP_FOWNER)) |
| @@ -606,7 +604,7 @@ xfs_acl_get_endian( | |||
| 606 | */ | 604 | */ |
| 607 | STATIC void | 605 | STATIC void |
| 608 | xfs_acl_get_attr( | 606 | xfs_acl_get_attr( |
| 609 | vnode_t *vp, | 607 | bhv_vnode_t *vp, |
| 610 | xfs_acl_t *aclp, | 608 | xfs_acl_t *aclp, |
| 611 | int kind, | 609 | int kind, |
| 612 | int flags, | 610 | int flags, |
| @@ -616,9 +614,9 @@ xfs_acl_get_attr( | |||
| 616 | 614 | ||
| 617 | ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1); | 615 | ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1); |
| 618 | flags |= ATTR_ROOT; | 616 | flags |= ATTR_ROOT; |
| 619 | VOP_ATTR_GET(vp, | 617 | *error = bhv_vop_attr_get(vp, kind == _ACL_TYPE_ACCESS ? |
| 620 | kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE : SGI_ACL_DEFAULT, | 618 | SGI_ACL_FILE : SGI_ACL_DEFAULT, |
| 621 | (char *)aclp, &len, flags, sys_cred, *error); | 619 | (char *)aclp, &len, flags, sys_cred); |
| 622 | if (*error || (flags & ATTR_KERNOVAL)) | 620 | if (*error || (flags & ATTR_KERNOVAL)) |
| 623 | return; | 621 | return; |
| 624 | xfs_acl_get_endian(aclp); | 622 | xfs_acl_get_endian(aclp); |
| @@ -629,7 +627,7 @@ xfs_acl_get_attr( | |||
| 629 | */ | 627 | */ |
| 630 | STATIC void | 628 | STATIC void |
| 631 | xfs_acl_set_attr( | 629 | xfs_acl_set_attr( |
| 632 | vnode_t *vp, | 630 | bhv_vnode_t *vp, |
| 633 | xfs_acl_t *aclp, | 631 | xfs_acl_t *aclp, |
| 634 | int kind, | 632 | int kind, |
| 635 | int *error) | 633 | int *error) |
| @@ -654,19 +652,19 @@ xfs_acl_set_attr( | |||
| 654 | INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm); | 652 | INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm); |
| 655 | } | 653 | } |
| 656 | INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); | 654 | INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); |
| 657 | VOP_ATTR_SET(vp, | 655 | *error = bhv_vop_attr_set(vp, kind == _ACL_TYPE_ACCESS ? |
| 658 | kind == _ACL_TYPE_ACCESS ? SGI_ACL_FILE: SGI_ACL_DEFAULT, | 656 | SGI_ACL_FILE: SGI_ACL_DEFAULT, |
| 659 | (char *)newacl, len, ATTR_ROOT, sys_cred, *error); | 657 | (char *)newacl, len, ATTR_ROOT, sys_cred); |
| 660 | _ACL_FREE(newacl); | 658 | _ACL_FREE(newacl); |
| 661 | } | 659 | } |
| 662 | 660 | ||
| 663 | int | 661 | int |
| 664 | xfs_acl_vtoacl( | 662 | xfs_acl_vtoacl( |
| 665 | vnode_t *vp, | 663 | bhv_vnode_t *vp, |
| 666 | xfs_acl_t *access_acl, | 664 | xfs_acl_t *access_acl, |
| 667 | xfs_acl_t *default_acl) | 665 | xfs_acl_t *default_acl) |
| 668 | { | 666 | { |
| 669 | vattr_t va; | 667 | bhv_vattr_t va; |
| 670 | int error = 0; | 668 | int error = 0; |
| 671 | 669 | ||
| 672 | if (access_acl) { | 670 | if (access_acl) { |
| @@ -678,7 +676,7 @@ xfs_acl_vtoacl( | |||
| 678 | if (!error) { | 676 | if (!error) { |
| 679 | /* Got the ACL, need the mode... */ | 677 | /* Got the ACL, need the mode... */ |
| 680 | va.va_mask = XFS_AT_MODE; | 678 | va.va_mask = XFS_AT_MODE; |
| 681 | VOP_GETATTR(vp, &va, 0, sys_cred, error); | 679 | error = bhv_vop_getattr(vp, &va, 0, sys_cred); |
| 682 | } | 680 | } |
| 683 | 681 | ||
| 684 | if (error) | 682 | if (error) |
| @@ -701,8 +699,8 @@ xfs_acl_vtoacl( | |||
| 701 | */ | 699 | */ |
| 702 | int | 700 | int |
| 703 | xfs_acl_inherit( | 701 | xfs_acl_inherit( |
| 704 | vnode_t *vp, | 702 | bhv_vnode_t *vp, |
| 705 | vattr_t *vap, | 703 | bhv_vattr_t *vap, |
| 706 | xfs_acl_t *pdaclp) | 704 | xfs_acl_t *pdaclp) |
| 707 | { | 705 | { |
| 708 | xfs_acl_t *cacl; | 706 | xfs_acl_t *cacl; |
| @@ -757,11 +755,11 @@ xfs_acl_inherit( | |||
| 757 | */ | 755 | */ |
| 758 | STATIC int | 756 | STATIC int |
| 759 | xfs_acl_setmode( | 757 | xfs_acl_setmode( |
| 760 | vnode_t *vp, | 758 | bhv_vnode_t *vp, |
| 761 | xfs_acl_t *acl, | 759 | xfs_acl_t *acl, |
| 762 | int *basicperms) | 760 | int *basicperms) |
| 763 | { | 761 | { |
| 764 | vattr_t va; | 762 | bhv_vattr_t va; |
| 765 | xfs_acl_entry_t *ap; | 763 | xfs_acl_entry_t *ap; |
| 766 | xfs_acl_entry_t *gap = NULL; | 764 | xfs_acl_entry_t *gap = NULL; |
| 767 | int i, error, nomask = 1; | 765 | int i, error, nomask = 1; |
| @@ -776,7 +774,7 @@ xfs_acl_setmode( | |||
| 776 | * mode. The m:: bits take precedence over the g:: bits. | 774 | * mode. The m:: bits take precedence over the g:: bits. |
| 777 | */ | 775 | */ |
| 778 | va.va_mask = XFS_AT_MODE; | 776 | va.va_mask = XFS_AT_MODE; |
| 779 | VOP_GETATTR(vp, &va, 0, sys_cred, error); | 777 | error = bhv_vop_getattr(vp, &va, 0, sys_cred); |
| 780 | if (error) | 778 | if (error) |
| 781 | return error; | 779 | return error; |
| 782 | 780 | ||
| @@ -810,8 +808,7 @@ xfs_acl_setmode( | |||
| 810 | if (gap && nomask) | 808 | if (gap && nomask) |
| 811 | va.va_mode |= gap->ae_perm << 3; | 809 | va.va_mode |= gap->ae_perm << 3; |
| 812 | 810 | ||
| 813 | VOP_SETATTR(vp, &va, 0, sys_cred, error); | 811 | return bhv_vop_setattr(vp, &va, 0, sys_cred); |
| 814 | return error; | ||
| 815 | } | 812 | } |
| 816 | 813 | ||
| 817 | /* | 814 | /* |
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 538d0d65b04c..f853cf1a6270 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h | |||
| @@ -50,7 +50,7 @@ typedef struct xfs_acl { | |||
| 50 | #ifdef CONFIG_XFS_POSIX_ACL | 50 | #ifdef CONFIG_XFS_POSIX_ACL |
| 51 | 51 | ||
| 52 | struct vattr; | 52 | struct vattr; |
| 53 | struct vnode; | 53 | struct bhv_vnode; |
| 54 | struct xfs_inode; | 54 | struct xfs_inode; |
| 55 | 55 | ||
| 56 | extern struct kmem_zone *xfs_acl_zone; | 56 | extern struct kmem_zone *xfs_acl_zone; |
| @@ -58,14 +58,14 @@ extern struct kmem_zone *xfs_acl_zone; | |||
| 58 | (zone) = kmem_zone_init(sizeof(xfs_acl_t), (name)) | 58 | (zone) = kmem_zone_init(sizeof(xfs_acl_t), (name)) |
| 59 | #define xfs_acl_zone_destroy(zone) kmem_zone_destroy(zone) | 59 | #define xfs_acl_zone_destroy(zone) kmem_zone_destroy(zone) |
| 60 | 60 | ||
| 61 | extern int xfs_acl_inherit(struct vnode *, struct vattr *, xfs_acl_t *); | 61 | extern int xfs_acl_inherit(struct bhv_vnode *, struct bhv_vattr *, xfs_acl_t *); |
| 62 | extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *); | 62 | extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *); |
| 63 | extern int xfs_acl_vtoacl(struct vnode *, xfs_acl_t *, xfs_acl_t *); | 63 | extern int xfs_acl_vtoacl(struct bhv_vnode *, xfs_acl_t *, xfs_acl_t *); |
| 64 | extern int xfs_acl_vhasacl_access(struct vnode *); | 64 | extern int xfs_acl_vhasacl_access(struct bhv_vnode *); |
| 65 | extern int xfs_acl_vhasacl_default(struct vnode *); | 65 | extern int xfs_acl_vhasacl_default(struct bhv_vnode *); |
| 66 | extern int xfs_acl_vset(struct vnode *, void *, size_t, int); | 66 | extern int xfs_acl_vset(struct bhv_vnode *, void *, size_t, int); |
| 67 | extern int xfs_acl_vget(struct vnode *, void *, size_t, int); | 67 | extern int xfs_acl_vget(struct bhv_vnode *, void *, size_t, int); |
| 68 | extern int xfs_acl_vremove(struct vnode *vp, int); | 68 | extern int xfs_acl_vremove(struct bhv_vnode *, int); |
| 69 | 69 | ||
| 70 | #define _ACL_TYPE_ACCESS 1 | 70 | #define _ACL_TYPE_ACCESS 1 |
| 71 | #define _ACL_TYPE_DEFAULT 2 | 71 | #define _ACL_TYPE_DEFAULT 2 |
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 8558226281c4..eef6763f3a67 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -1862,7 +1860,7 @@ xfs_alloc_fix_freelist( | |||
| 1862 | (pag->pagf_longest - delta) : | 1860 | (pag->pagf_longest - delta) : |
| 1863 | (pag->pagf_flcount > 0 || pag->pagf_longest > 0); | 1861 | (pag->pagf_flcount > 0 || pag->pagf_longest > 0); |
| 1864 | if (args->minlen + args->alignment + args->minalignslop - 1 > longest || | 1862 | if (args->minlen + args->alignment + args->minalignslop - 1 > longest || |
| 1865 | (args->minleft && | 1863 | (!(flags & XFS_ALLOC_FLAG_FREEING) && |
| 1866 | (int)(pag->pagf_freeblks + pag->pagf_flcount - | 1864 | (int)(pag->pagf_freeblks + pag->pagf_flcount - |
| 1867 | need - args->total) < | 1865 | need - args->total) < |
| 1868 | (int)args->minleft)) { | 1866 | (int)args->minleft)) { |
| @@ -1898,7 +1896,7 @@ xfs_alloc_fix_freelist( | |||
| 1898 | longest = (longest > delta) ? (longest - delta) : | 1896 | longest = (longest > delta) ? (longest - delta) : |
| 1899 | (be32_to_cpu(agf->agf_flcount) > 0 || longest > 0); | 1897 | (be32_to_cpu(agf->agf_flcount) > 0 || longest > 0); |
| 1900 | if (args->minlen + args->alignment + args->minalignslop - 1 > longest || | 1898 | if (args->minlen + args->alignment + args->minalignslop - 1 > longest || |
| 1901 | (args->minleft && | 1899 | (!(flags & XFS_ALLOC_FLAG_FREEING) && |
| 1902 | (int)(be32_to_cpu(agf->agf_freeblks) + | 1900 | (int)(be32_to_cpu(agf->agf_freeblks) + |
| 1903 | be32_to_cpu(agf->agf_flcount) - need - args->total) < | 1901 | be32_to_cpu(agf->agf_flcount) - need - args->total) < |
| 1904 | (int)args->minleft)) { | 1902 | (int)args->minleft)) { |
| @@ -1951,8 +1949,14 @@ xfs_alloc_fix_freelist( | |||
| 1951 | * the restrictions correctly. Can happen for free calls | 1949 | * the restrictions correctly. Can happen for free calls |
| 1952 | * on a completely full ag. | 1950 | * on a completely full ag. |
| 1953 | */ | 1951 | */ |
| 1954 | if (targs.agbno == NULLAGBLOCK) | 1952 | if (targs.agbno == NULLAGBLOCK) { |
| 1953 | if (!(flags & XFS_ALLOC_FLAG_FREEING)) { | ||
| 1954 | xfs_trans_brelse(tp, agflbp); | ||
| 1955 | args->agbp = NULL; | ||
| 1956 | return 0; | ||
| 1957 | } | ||
| 1955 | break; | 1958 | break; |
| 1959 | } | ||
| 1956 | /* | 1960 | /* |
| 1957 | * Put each allocated block on the list. | 1961 | * Put each allocated block on the list. |
| 1958 | */ | 1962 | */ |
| @@ -2360,8 +2364,19 @@ xfs_alloc_vextent( | |||
| 2360 | if (args->agno == sagno && | 2364 | if (args->agno == sagno && |
| 2361 | type == XFS_ALLOCTYPE_START_BNO) | 2365 | type == XFS_ALLOCTYPE_START_BNO) |
| 2362 | args->type = XFS_ALLOCTYPE_THIS_AG; | 2366 | args->type = XFS_ALLOCTYPE_THIS_AG; |
| 2363 | if (++(args->agno) == mp->m_sb.sb_agcount) | 2367 | /* |
| 2364 | args->agno = 0; | 2368 | * For the first allocation, we can try any AG to get |
| 2369 | * space. However, if we already have allocated a | ||
| 2370 | * block, we don't want to try AGs whose number is below | ||
| 2371 | * sagno. Otherwise, we may end up with out-of-order | ||
| 2372 | * locking of AGF, which might cause deadlock. | ||
| 2373 | */ | ||
| 2374 | if (++(args->agno) == mp->m_sb.sb_agcount) { | ||
| 2375 | if (args->firstblock != NULLFSBLOCK) | ||
| 2376 | args->agno = sagno; | ||
| 2377 | else | ||
| 2378 | args->agno = 0; | ||
| 2379 | } | ||
| 2365 | /* | 2380 | /* |
| 2366 | * Reached the starting a.g., must either be done | 2381 | * Reached the starting a.g., must either be done |
| 2367 | * or switch to non-trylock mode. | 2382 | * or switch to non-trylock mode. |
| @@ -2443,7 +2458,7 @@ xfs_free_extent( | |||
| 2443 | args.minlen = args.minleft = args.minalignslop = 0; | 2458 | args.minlen = args.minleft = args.minalignslop = 0; |
| 2444 | down_read(&args.mp->m_peraglock); | 2459 | down_read(&args.mp->m_peraglock); |
| 2445 | args.pag = &args.mp->m_perag[args.agno]; | 2460 | args.pag = &args.mp->m_perag[args.agno]; |
| 2446 | if ((error = xfs_alloc_fix_freelist(&args, 0))) | 2461 | if ((error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING))) |
| 2447 | goto error0; | 2462 | goto error0; |
| 2448 | #ifdef DEBUG | 2463 | #ifdef DEBUG |
| 2449 | ASSERT(args.agbp != NULL); | 2464 | ASSERT(args.agbp != NULL); |
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h index 2d1f8928b267..650591f999ae 100644 --- a/fs/xfs/xfs_alloc.h +++ b/fs/xfs/xfs_alloc.h | |||
| @@ -41,6 +41,7 @@ typedef enum xfs_alloctype | |||
| 41 | * Flags for xfs_alloc_fix_freelist. | 41 | * Flags for xfs_alloc_fix_freelist. |
| 42 | */ | 42 | */ |
| 43 | #define XFS_ALLOC_FLAG_TRYLOCK 0x00000001 /* use trylock for buffer locking */ | 43 | #define XFS_ALLOC_FLAG_TRYLOCK 0x00000001 /* use trylock for buffer locking */ |
| 44 | #define XFS_ALLOC_FLAG_FREEING 0x00000002 /* indicate caller is freeing extents*/ | ||
| 44 | 45 | ||
| 45 | /* | 46 | /* |
| 46 | * Argument structure for xfs_alloc routines. | 47 | * Argument structure for xfs_alloc routines. |
| @@ -70,6 +71,7 @@ typedef struct xfs_alloc_arg { | |||
| 70 | char wasfromfl; /* set if allocation is from freelist */ | 71 | char wasfromfl; /* set if allocation is from freelist */ |
| 71 | char isfl; /* set if is freelist blocks - !acctg */ | 72 | char isfl; /* set if is freelist blocks - !acctg */ |
| 72 | char userdata; /* set if this is user data */ | 73 | char userdata; /* set if this is user data */ |
| 74 | xfs_fsblock_t firstblock; /* io first block allocated */ | ||
| 73 | } xfs_alloc_arg_t; | 75 | } xfs_alloc_arg_t; |
| 74 | 76 | ||
| 75 | /* | 77 | /* |
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index a1d92da86ccd..7446556e8021 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index b6e1e02bbb28..1a2101043275 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c | |||
| @@ -27,7 +27,6 @@ | |||
| 27 | #include "xfs_trans.h" | 27 | #include "xfs_trans.h" |
| 28 | #include "xfs_sb.h" | 28 | #include "xfs_sb.h" |
| 29 | #include "xfs_ag.h" | 29 | #include "xfs_ag.h" |
| 30 | #include "xfs_dir.h" | ||
| 31 | #include "xfs_dir2.h" | 30 | #include "xfs_dir2.h" |
| 32 | #include "xfs_dmapi.h" | 31 | #include "xfs_dmapi.h" |
| 33 | #include "xfs_mount.h" | 32 | #include "xfs_mount.h" |
| @@ -35,7 +34,6 @@ | |||
| 35 | #include "xfs_bmap_btree.h" | 34 | #include "xfs_bmap_btree.h" |
| 36 | #include "xfs_alloc_btree.h" | 35 | #include "xfs_alloc_btree.h" |
| 37 | #include "xfs_ialloc_btree.h" | 36 | #include "xfs_ialloc_btree.h" |
| 38 | #include "xfs_dir_sf.h" | ||
| 39 | #include "xfs_dir2_sf.h" | 37 | #include "xfs_dir2_sf.h" |
| 40 | #include "xfs_attr_sf.h" | 38 | #include "xfs_attr_sf.h" |
| 41 | #include "xfs_dinode.h" | 39 | #include "xfs_dinode.h" |
| @@ -1910,7 +1908,7 @@ xfs_attr_rmtval_get(xfs_da_args_t *args) | |||
| 1910 | error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno, | 1908 | error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno, |
| 1911 | args->rmtblkcnt, | 1909 | args->rmtblkcnt, |
| 1912 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, | 1910 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, |
| 1913 | NULL, 0, map, &nmap, NULL); | 1911 | NULL, 0, map, &nmap, NULL, NULL); |
| 1914 | if (error) | 1912 | if (error) |
| 1915 | return(error); | 1913 | return(error); |
| 1916 | ASSERT(nmap >= 1); | 1914 | ASSERT(nmap >= 1); |
| @@ -1988,7 +1986,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) | |||
| 1988 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA | | 1986 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA | |
| 1989 | XFS_BMAPI_WRITE, | 1987 | XFS_BMAPI_WRITE, |
| 1990 | args->firstblock, args->total, &map, &nmap, | 1988 | args->firstblock, args->total, &map, &nmap, |
| 1991 | args->flist); | 1989 | args->flist, NULL); |
| 1992 | if (!error) { | 1990 | if (!error) { |
| 1993 | error = xfs_bmap_finish(&args->trans, args->flist, | 1991 | error = xfs_bmap_finish(&args->trans, args->flist, |
| 1994 | *args->firstblock, &committed); | 1992 | *args->firstblock, &committed); |
| @@ -2039,7 +2037,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) | |||
| 2039 | error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno, | 2037 | error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno, |
| 2040 | args->rmtblkcnt, | 2038 | args->rmtblkcnt, |
| 2041 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, | 2039 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, |
| 2042 | args->firstblock, 0, &map, &nmap, NULL); | 2040 | args->firstblock, 0, &map, &nmap, |
| 2041 | NULL, NULL); | ||
| 2043 | if (error) { | 2042 | if (error) { |
| 2044 | return(error); | 2043 | return(error); |
| 2045 | } | 2044 | } |
| @@ -2104,7 +2103,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) | |||
| 2104 | args->rmtblkcnt, | 2103 | args->rmtblkcnt, |
| 2105 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, | 2104 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, |
| 2106 | args->firstblock, 0, &map, &nmap, | 2105 | args->firstblock, 0, &map, &nmap, |
| 2107 | args->flist); | 2106 | args->flist, NULL); |
| 2108 | if (error) { | 2107 | if (error) { |
| 2109 | return(error); | 2108 | return(error); |
| 2110 | } | 2109 | } |
| @@ -2142,7 +2141,8 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) | |||
| 2142 | XFS_BMAP_INIT(args->flist, args->firstblock); | 2141 | XFS_BMAP_INIT(args->flist, args->firstblock); |
| 2143 | error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, | 2142 | error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, |
| 2144 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, | 2143 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, |
| 2145 | 1, args->firstblock, args->flist, &done); | 2144 | 1, args->firstblock, args->flist, |
| 2145 | NULL, &done); | ||
| 2146 | if (!error) { | 2146 | if (!error) { |
| 2147 | error = xfs_bmap_finish(&args->trans, args->flist, | 2147 | error = xfs_bmap_finish(&args->trans, args->flist, |
| 2148 | *args->firstblock, &committed); | 2148 | *args->firstblock, &committed); |
| @@ -2322,56 +2322,56 @@ xfs_attr_trace_enter(int type, char *where, | |||
| 2322 | 2322 | ||
| 2323 | STATIC int | 2323 | STATIC int |
| 2324 | posix_acl_access_set( | 2324 | posix_acl_access_set( |
| 2325 | vnode_t *vp, char *name, void *data, size_t size, int xflags) | 2325 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) |
| 2326 | { | 2326 | { |
| 2327 | return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS); | 2327 | return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS); |
| 2328 | } | 2328 | } |
| 2329 | 2329 | ||
| 2330 | STATIC int | 2330 | STATIC int |
| 2331 | posix_acl_access_remove( | 2331 | posix_acl_access_remove( |
| 2332 | struct vnode *vp, char *name, int xflags) | 2332 | bhv_vnode_t *vp, char *name, int xflags) |
| 2333 | { | 2333 | { |
| 2334 | return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); | 2334 | return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); |
| 2335 | } | 2335 | } |
| 2336 | 2336 | ||
| 2337 | STATIC int | 2337 | STATIC int |
| 2338 | posix_acl_access_get( | 2338 | posix_acl_access_get( |
| 2339 | vnode_t *vp, char *name, void *data, size_t size, int xflags) | 2339 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) |
| 2340 | { | 2340 | { |
| 2341 | return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS); | 2341 | return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS); |
| 2342 | } | 2342 | } |
| 2343 | 2343 | ||
| 2344 | STATIC int | 2344 | STATIC int |
| 2345 | posix_acl_access_exists( | 2345 | posix_acl_access_exists( |
| 2346 | vnode_t *vp) | 2346 | bhv_vnode_t *vp) |
| 2347 | { | 2347 | { |
| 2348 | return xfs_acl_vhasacl_access(vp); | 2348 | return xfs_acl_vhasacl_access(vp); |
| 2349 | } | 2349 | } |
| 2350 | 2350 | ||
| 2351 | STATIC int | 2351 | STATIC int |
| 2352 | posix_acl_default_set( | 2352 | posix_acl_default_set( |
| 2353 | vnode_t *vp, char *name, void *data, size_t size, int xflags) | 2353 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) |
| 2354 | { | 2354 | { |
| 2355 | return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT); | 2355 | return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT); |
| 2356 | } | 2356 | } |
| 2357 | 2357 | ||
| 2358 | STATIC int | 2358 | STATIC int |
| 2359 | posix_acl_default_get( | 2359 | posix_acl_default_get( |
| 2360 | vnode_t *vp, char *name, void *data, size_t size, int xflags) | 2360 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) |
| 2361 | { | 2361 | { |
| 2362 | return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT); | 2362 | return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT); |
| 2363 | } | 2363 | } |
| 2364 | 2364 | ||
| 2365 | STATIC int | 2365 | STATIC int |
| 2366 | posix_acl_default_remove( | 2366 | posix_acl_default_remove( |
| 2367 | struct vnode *vp, char *name, int xflags) | 2367 | bhv_vnode_t *vp, char *name, int xflags) |
| 2368 | { | 2368 | { |
| 2369 | return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT); | 2369 | return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT); |
| 2370 | } | 2370 | } |
| 2371 | 2371 | ||
| 2372 | STATIC int | 2372 | STATIC int |
| 2373 | posix_acl_default_exists( | 2373 | posix_acl_default_exists( |
| 2374 | vnode_t *vp) | 2374 | bhv_vnode_t *vp) |
| 2375 | { | 2375 | { |
| 2376 | return xfs_acl_vhasacl_default(vp); | 2376 | return xfs_acl_vhasacl_default(vp); |
| 2377 | } | 2377 | } |
| @@ -2404,21 +2404,18 @@ STATIC struct attrnames *attr_system_names[] = | |||
| 2404 | 2404 | ||
| 2405 | STATIC int | 2405 | STATIC int |
| 2406 | attr_generic_set( | 2406 | attr_generic_set( |
| 2407 | struct vnode *vp, char *name, void *data, size_t size, int xflags) | 2407 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) |
| 2408 | { | 2408 | { |
| 2409 | int error; | 2409 | return -bhv_vop_attr_set(vp, name, data, size, xflags, NULL); |
| 2410 | |||
| 2411 | VOP_ATTR_SET(vp, name, data, size, xflags, NULL, error); | ||
| 2412 | return -error; | ||
| 2413 | } | 2410 | } |
| 2414 | 2411 | ||
| 2415 | STATIC int | 2412 | STATIC int |
| 2416 | attr_generic_get( | 2413 | attr_generic_get( |
| 2417 | struct vnode *vp, char *name, void *data, size_t size, int xflags) | 2414 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) |
| 2418 | { | 2415 | { |
| 2419 | int error, asize = size; | 2416 | int error, asize = size; |
| 2420 | 2417 | ||
| 2421 | VOP_ATTR_GET(vp, name, data, &asize, xflags, NULL, error); | 2418 | error = bhv_vop_attr_get(vp, name, data, &asize, xflags, NULL); |
| 2422 | if (!error) | 2419 | if (!error) |
| 2423 | return asize; | 2420 | return asize; |
| 2424 | return -error; | 2421 | return -error; |
| @@ -2426,12 +2423,9 @@ attr_generic_get( | |||
| 2426 | 2423 | ||
| 2427 | STATIC int | 2424 | STATIC int |
| 2428 | attr_generic_remove( | 2425 | attr_generic_remove( |
| 2429 | struct vnode *vp, char *name, int xflags) | 2426 | bhv_vnode_t *vp, char *name, int xflags) |
| 2430 | { | 2427 | { |
| 2431 | int error; | 2428 | return -bhv_vop_attr_remove(vp, name, xflags, NULL); |
| 2432 | |||
| 2433 | VOP_ATTR_REMOVE(vp, name, xflags, NULL, error); | ||
| 2434 | return -error; | ||
| 2435 | } | 2429 | } |
| 2436 | 2430 | ||
| 2437 | STATIC int | 2431 | STATIC int |
| @@ -2459,7 +2453,7 @@ attr_generic_listadd( | |||
| 2459 | 2453 | ||
| 2460 | STATIC int | 2454 | STATIC int |
| 2461 | attr_system_list( | 2455 | attr_system_list( |
| 2462 | struct vnode *vp, | 2456 | bhv_vnode_t *vp, |
| 2463 | void *data, | 2457 | void *data, |
| 2464 | size_t size, | 2458 | size_t size, |
| 2465 | ssize_t *result) | 2459 | ssize_t *result) |
| @@ -2481,12 +2475,12 @@ attr_system_list( | |||
| 2481 | 2475 | ||
| 2482 | int | 2476 | int |
| 2483 | attr_generic_list( | 2477 | attr_generic_list( |
| 2484 | struct vnode *vp, void *data, size_t size, int xflags, ssize_t *result) | 2478 | bhv_vnode_t *vp, void *data, size_t size, int xflags, ssize_t *result) |
| 2485 | { | 2479 | { |
| 2486 | attrlist_cursor_kern_t cursor = { 0 }; | 2480 | attrlist_cursor_kern_t cursor = { 0 }; |
| 2487 | int error; | 2481 | int error; |
| 2488 | 2482 | ||
| 2489 | VOP_ATTR_LIST(vp, data, size, xflags, &cursor, NULL, error); | 2483 | error = bhv_vop_attr_list(vp, data, size, xflags, &cursor, NULL); |
| 2490 | if (error > 0) | 2484 | if (error > 0) |
| 2491 | return -error; | 2485 | return -error; |
| 2492 | *result = -error; | 2486 | *result = -error; |
| @@ -2514,7 +2508,7 @@ attr_lookup_namespace( | |||
| 2514 | */ | 2508 | */ |
| 2515 | STATIC int | 2509 | STATIC int |
| 2516 | attr_user_capable( | 2510 | attr_user_capable( |
| 2517 | struct vnode *vp, | 2511 | bhv_vnode_t *vp, |
| 2518 | cred_t *cred) | 2512 | cred_t *cred) |
| 2519 | { | 2513 | { |
| 2520 | struct inode *inode = vn_to_inode(vp); | 2514 | struct inode *inode = vn_to_inode(vp); |
| @@ -2532,7 +2526,7 @@ attr_user_capable( | |||
| 2532 | 2526 | ||
| 2533 | STATIC int | 2527 | STATIC int |
| 2534 | attr_trusted_capable( | 2528 | attr_trusted_capable( |
| 2535 | struct vnode *vp, | 2529 | bhv_vnode_t *vp, |
| 2536 | cred_t *cred) | 2530 | cred_t *cred) |
| 2537 | { | 2531 | { |
| 2538 | struct inode *inode = vn_to_inode(vp); | 2532 | struct inode *inode = vn_to_inode(vp); |
| @@ -2546,7 +2540,7 @@ attr_trusted_capable( | |||
| 2546 | 2540 | ||
| 2547 | STATIC int | 2541 | STATIC int |
| 2548 | attr_secure_capable( | 2542 | attr_secure_capable( |
| 2549 | struct vnode *vp, | 2543 | bhv_vnode_t *vp, |
| 2550 | cred_t *cred) | 2544 | cred_t *cred) |
| 2551 | { | 2545 | { |
| 2552 | return -ENOSECURITY; | 2546 | return -ENOSECURITY; |
| @@ -2554,7 +2548,7 @@ attr_secure_capable( | |||
| 2554 | 2548 | ||
| 2555 | STATIC int | 2549 | STATIC int |
| 2556 | attr_system_set( | 2550 | attr_system_set( |
| 2557 | struct vnode *vp, char *name, void *data, size_t size, int xflags) | 2551 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) |
| 2558 | { | 2552 | { |
| 2559 | attrnames_t *namesp; | 2553 | attrnames_t *namesp; |
| 2560 | int error; | 2554 | int error; |
| @@ -2573,7 +2567,7 @@ attr_system_set( | |||
| 2573 | 2567 | ||
| 2574 | STATIC int | 2568 | STATIC int |
| 2575 | attr_system_get( | 2569 | attr_system_get( |
| 2576 | struct vnode *vp, char *name, void *data, size_t size, int xflags) | 2570 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) |
| 2577 | { | 2571 | { |
| 2578 | attrnames_t *namesp; | 2572 | attrnames_t *namesp; |
| 2579 | 2573 | ||
| @@ -2585,7 +2579,7 @@ attr_system_get( | |||
| 2585 | 2579 | ||
| 2586 | STATIC int | 2580 | STATIC int |
| 2587 | attr_system_remove( | 2581 | attr_system_remove( |
| 2588 | struct vnode *vp, char *name, int xflags) | 2582 | bhv_vnode_t *vp, char *name, int xflags) |
| 2589 | { | 2583 | { |
| 2590 | attrnames_t *namesp; | 2584 | attrnames_t *namesp; |
| 2591 | 2585 | ||
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h index b2c7b9fcded3..981633f6c077 100644 --- a/fs/xfs/xfs_attr.h +++ b/fs/xfs/xfs_attr.h | |||
| @@ -36,13 +36,13 @@ | |||
| 36 | *========================================================================*/ | 36 | *========================================================================*/ |
| 37 | 37 | ||
| 38 | struct cred; | 38 | struct cred; |
| 39 | struct vnode; | 39 | struct bhv_vnode; |
| 40 | 40 | ||
| 41 | typedef int (*attrset_t)(struct vnode *, char *, void *, size_t, int); | 41 | typedef int (*attrset_t)(struct bhv_vnode *, char *, void *, size_t, int); |
| 42 | typedef int (*attrget_t)(struct vnode *, char *, void *, size_t, int); | 42 | typedef int (*attrget_t)(struct bhv_vnode *, char *, void *, size_t, int); |
| 43 | typedef int (*attrremove_t)(struct vnode *, char *, int); | 43 | typedef int (*attrremove_t)(struct bhv_vnode *, char *, int); |
| 44 | typedef int (*attrexists_t)(struct vnode *); | 44 | typedef int (*attrexists_t)(struct bhv_vnode *); |
| 45 | typedef int (*attrcapable_t)(struct vnode *, struct cred *); | 45 | typedef int (*attrcapable_t)(struct bhv_vnode *, struct cred *); |
| 46 | 46 | ||
| 47 | typedef struct attrnames { | 47 | typedef struct attrnames { |
| 48 | char * attr_name; | 48 | char * attr_name; |
| @@ -63,7 +63,7 @@ extern struct attrnames attr_trusted; | |||
| 63 | extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT]; | 63 | extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT]; |
| 64 | 64 | ||
| 65 | extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int); | 65 | extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int); |
| 66 | extern int attr_generic_list(struct vnode *, void *, size_t, int, ssize_t *); | 66 | extern int attr_generic_list(struct bhv_vnode *, void *, size_t, int, ssize_t *); |
| 67 | 67 | ||
| 68 | #define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */ | 68 | #define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */ |
| 69 | #define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */ | 69 | #define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */ |
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index 9462be86aa14..9455051f0120 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| @@ -34,7 +33,6 @@ | |||
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_alloc.h" | 34 | #include "xfs_alloc.h" |
| 36 | #include "xfs_btree.h" | 35 | #include "xfs_btree.h" |
| 37 | #include "xfs_dir_sf.h" | ||
| 38 | #include "xfs_dir2_sf.h" | 36 | #include "xfs_dir2_sf.h" |
| 39 | #include "xfs_attr_sf.h" | 37 | #include "xfs_attr_sf.h" |
| 40 | #include "xfs_dinode.h" | 38 | #include "xfs_dinode.h" |
| @@ -2990,7 +2988,7 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, | |||
| 2990 | nmap = 1; | 2988 | nmap = 1; |
| 2991 | error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt, | 2989 | error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt, |
| 2992 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, | 2990 | XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, |
| 2993 | NULL, 0, &map, &nmap, NULL); | 2991 | NULL, 0, &map, &nmap, NULL, NULL); |
| 2994 | if (error) { | 2992 | if (error) { |
| 2995 | return(error); | 2993 | return(error); |
| 2996 | } | 2994 | } |
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 26939d364bc4..3a6137539064 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -24,13 +24,11 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_da_btree.h" | 28 | #include "xfs_da_btree.h" |
| 30 | #include "xfs_bmap_btree.h" | 29 | #include "xfs_bmap_btree.h" |
| 31 | #include "xfs_alloc_btree.h" | 30 | #include "xfs_alloc_btree.h" |
| 32 | #include "xfs_ialloc_btree.h" | 31 | #include "xfs_ialloc_btree.h" |
| 33 | #include "xfs_dir_sf.h" | ||
| 34 | #include "xfs_dir2_sf.h" | 32 | #include "xfs_dir2_sf.h" |
| 35 | #include "xfs_attr_sf.h" | 33 | #include "xfs_attr_sf.h" |
| 36 | #include "xfs_dinode.h" | 34 | #include "xfs_dinode.h" |
| @@ -40,13 +38,15 @@ | |||
| 40 | #include "xfs_mount.h" | 38 | #include "xfs_mount.h" |
| 41 | #include "xfs_ialloc.h" | 39 | #include "xfs_ialloc.h" |
| 42 | #include "xfs_itable.h" | 40 | #include "xfs_itable.h" |
| 41 | #include "xfs_dir2_data.h" | ||
| 42 | #include "xfs_dir2_leaf.h" | ||
| 43 | #include "xfs_dir2_block.h" | ||
| 43 | #include "xfs_inode_item.h" | 44 | #include "xfs_inode_item.h" |
| 44 | #include "xfs_extfree_item.h" | 45 | #include "xfs_extfree_item.h" |
| 45 | #include "xfs_alloc.h" | 46 | #include "xfs_alloc.h" |
| 46 | #include "xfs_bmap.h" | 47 | #include "xfs_bmap.h" |
| 47 | #include "xfs_rtalloc.h" | 48 | #include "xfs_rtalloc.h" |
| 48 | #include "xfs_error.h" | 49 | #include "xfs_error.h" |
| 49 | #include "xfs_dir_leaf.h" | ||
| 50 | #include "xfs_attr_leaf.h" | 50 | #include "xfs_attr_leaf.h" |
| 51 | #include "xfs_rw.h" | 51 | #include "xfs_rw.h" |
| 52 | #include "xfs_quota.h" | 52 | #include "xfs_quota.h" |
| @@ -101,6 +101,7 @@ xfs_bmap_add_extent( | |||
| 101 | xfs_fsblock_t *first, /* pointer to firstblock variable */ | 101 | xfs_fsblock_t *first, /* pointer to firstblock variable */ |
| 102 | xfs_bmap_free_t *flist, /* list of extents to be freed */ | 102 | xfs_bmap_free_t *flist, /* list of extents to be freed */ |
| 103 | int *logflagsp, /* inode logging flags */ | 103 | int *logflagsp, /* inode logging flags */ |
| 104 | xfs_extdelta_t *delta, /* Change made to incore extents */ | ||
| 104 | int whichfork, /* data or attr fork */ | 105 | int whichfork, /* data or attr fork */ |
| 105 | int rsvd); /* OK to allocate reserved blocks */ | 106 | int rsvd); /* OK to allocate reserved blocks */ |
| 106 | 107 | ||
| @@ -118,6 +119,7 @@ xfs_bmap_add_extent_delay_real( | |||
| 118 | xfs_fsblock_t *first, /* pointer to firstblock variable */ | 119 | xfs_fsblock_t *first, /* pointer to firstblock variable */ |
| 119 | xfs_bmap_free_t *flist, /* list of extents to be freed */ | 120 | xfs_bmap_free_t *flist, /* list of extents to be freed */ |
| 120 | int *logflagsp, /* inode logging flags */ | 121 | int *logflagsp, /* inode logging flags */ |
| 122 | xfs_extdelta_t *delta, /* Change made to incore extents */ | ||
| 121 | int rsvd); /* OK to allocate reserved blocks */ | 123 | int rsvd); /* OK to allocate reserved blocks */ |
| 122 | 124 | ||
| 123 | /* | 125 | /* |
| @@ -131,6 +133,7 @@ xfs_bmap_add_extent_hole_delay( | |||
| 131 | xfs_btree_cur_t *cur, /* if null, not a btree */ | 133 | xfs_btree_cur_t *cur, /* if null, not a btree */ |
| 132 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | 134 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ |
| 133 | int *logflagsp,/* inode logging flags */ | 135 | int *logflagsp,/* inode logging flags */ |
| 136 | xfs_extdelta_t *delta, /* Change made to incore extents */ | ||
| 134 | int rsvd); /* OK to allocate reserved blocks */ | 137 | int rsvd); /* OK to allocate reserved blocks */ |
| 135 | 138 | ||
| 136 | /* | 139 | /* |
| @@ -144,6 +147,7 @@ xfs_bmap_add_extent_hole_real( | |||
| 144 | xfs_btree_cur_t *cur, /* if null, not a btree */ | 147 | xfs_btree_cur_t *cur, /* if null, not a btree */ |
| 145 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | 148 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ |
| 146 | int *logflagsp, /* inode logging flags */ | 149 | int *logflagsp, /* inode logging flags */ |
| 150 | xfs_extdelta_t *delta, /* Change made to incore extents */ | ||
| 147 | int whichfork); /* data or attr fork */ | 151 | int whichfork); /* data or attr fork */ |
| 148 | 152 | ||
| 149 | /* | 153 | /* |
| @@ -156,7 +160,8 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 156 | xfs_extnum_t idx, /* extent number to update/insert */ | 160 | xfs_extnum_t idx, /* extent number to update/insert */ |
| 157 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ | 161 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ |
| 158 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | 162 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ |
| 159 | int *logflagsp); /* inode logging flags */ | 163 | int *logflagsp, /* inode logging flags */ |
| 164 | xfs_extdelta_t *delta); /* Change made to incore extents */ | ||
| 160 | 165 | ||
| 161 | /* | 166 | /* |
| 162 | * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. | 167 | * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. |
| @@ -203,6 +208,7 @@ xfs_bmap_del_extent( | |||
| 203 | xfs_btree_cur_t *cur, /* if null, not a btree */ | 208 | xfs_btree_cur_t *cur, /* if null, not a btree */ |
| 204 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | 209 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ |
| 205 | int *logflagsp,/* inode logging flags */ | 210 | int *logflagsp,/* inode logging flags */ |
| 211 | xfs_extdelta_t *delta, /* Change made to incore extents */ | ||
| 206 | int whichfork, /* data or attr fork */ | 212 | int whichfork, /* data or attr fork */ |
| 207 | int rsvd); /* OK to allocate reserved blocks */ | 213 | int rsvd); /* OK to allocate reserved blocks */ |
| 208 | 214 | ||
| @@ -510,7 +516,7 @@ xfs_bmap_add_attrfork_local( | |||
| 510 | dargs.total = mp->m_dirblkfsbs; | 516 | dargs.total = mp->m_dirblkfsbs; |
| 511 | dargs.whichfork = XFS_DATA_FORK; | 517 | dargs.whichfork = XFS_DATA_FORK; |
| 512 | dargs.trans = tp; | 518 | dargs.trans = tp; |
| 513 | error = XFS_DIR_SHORTFORM_TO_SINGLE(mp, &dargs); | 519 | error = xfs_dir2_sf_to_block(&dargs); |
| 514 | } else | 520 | } else |
| 515 | error = xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags, | 521 | error = xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags, |
| 516 | XFS_DATA_FORK); | 522 | XFS_DATA_FORK); |
| @@ -530,6 +536,7 @@ xfs_bmap_add_extent( | |||
| 530 | xfs_fsblock_t *first, /* pointer to firstblock variable */ | 536 | xfs_fsblock_t *first, /* pointer to firstblock variable */ |
| 531 | xfs_bmap_free_t *flist, /* list of extents to be freed */ | 537 | xfs_bmap_free_t *flist, /* list of extents to be freed */ |
| 532 | int *logflagsp, /* inode logging flags */ | 538 | int *logflagsp, /* inode logging flags */ |
| 539 | xfs_extdelta_t *delta, /* Change made to incore extents */ | ||
| 533 | int whichfork, /* data or attr fork */ | 540 | int whichfork, /* data or attr fork */ |
| 534 | int rsvd) /* OK to use reserved data blocks */ | 541 | int rsvd) /* OK to use reserved data blocks */ |
| 535 | { | 542 | { |
| @@ -567,6 +574,15 @@ xfs_bmap_add_extent( | |||
| 567 | logflags = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); | 574 | logflags = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); |
| 568 | } else | 575 | } else |
| 569 | logflags = 0; | 576 | logflags = 0; |
| 577 | /* DELTA: single new extent */ | ||
| 578 | if (delta) { | ||
| 579 | if (delta->xed_startoff > new->br_startoff) | ||
| 580 | delta->xed_startoff = new->br_startoff; | ||
| 581 | if (delta->xed_blockcount < | ||
| 582 | new->br_startoff + new->br_blockcount) | ||
| 583 | delta->xed_blockcount = new->br_startoff + | ||
| 584 | new->br_blockcount; | ||
| 585 | } | ||
| 570 | } | 586 | } |
| 571 | /* | 587 | /* |
| 572 | * Any kind of new delayed allocation goes here. | 588 | * Any kind of new delayed allocation goes here. |
| @@ -576,7 +592,7 @@ xfs_bmap_add_extent( | |||
| 576 | ASSERT((cur->bc_private.b.flags & | 592 | ASSERT((cur->bc_private.b.flags & |
| 577 | XFS_BTCUR_BPRV_WASDEL) == 0); | 593 | XFS_BTCUR_BPRV_WASDEL) == 0); |
| 578 | if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, cur, new, | 594 | if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, cur, new, |
| 579 | &logflags, rsvd))) | 595 | &logflags, delta, rsvd))) |
| 580 | goto done; | 596 | goto done; |
| 581 | } | 597 | } |
| 582 | /* | 598 | /* |
| @@ -587,7 +603,7 @@ xfs_bmap_add_extent( | |||
| 587 | ASSERT((cur->bc_private.b.flags & | 603 | ASSERT((cur->bc_private.b.flags & |
| 588 | XFS_BTCUR_BPRV_WASDEL) == 0); | 604 | XFS_BTCUR_BPRV_WASDEL) == 0); |
| 589 | if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new, | 605 | if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new, |
| 590 | &logflags, whichfork))) | 606 | &logflags, delta, whichfork))) |
| 591 | goto done; | 607 | goto done; |
| 592 | } else { | 608 | } else { |
| 593 | xfs_bmbt_irec_t prev; /* old extent at offset idx */ | 609 | xfs_bmbt_irec_t prev; /* old extent at offset idx */ |
| @@ -612,17 +628,17 @@ xfs_bmap_add_extent( | |||
| 612 | XFS_BTCUR_BPRV_WASDEL); | 628 | XFS_BTCUR_BPRV_WASDEL); |
| 613 | if ((error = xfs_bmap_add_extent_delay_real(ip, | 629 | if ((error = xfs_bmap_add_extent_delay_real(ip, |
| 614 | idx, &cur, new, &da_new, first, flist, | 630 | idx, &cur, new, &da_new, first, flist, |
| 615 | &logflags, rsvd))) | 631 | &logflags, delta, rsvd))) |
| 616 | goto done; | 632 | goto done; |
| 617 | } else if (new->br_state == XFS_EXT_NORM) { | 633 | } else if (new->br_state == XFS_EXT_NORM) { |
| 618 | ASSERT(new->br_state == XFS_EXT_NORM); | 634 | ASSERT(new->br_state == XFS_EXT_NORM); |
| 619 | if ((error = xfs_bmap_add_extent_unwritten_real( | 635 | if ((error = xfs_bmap_add_extent_unwritten_real( |
| 620 | ip, idx, &cur, new, &logflags))) | 636 | ip, idx, &cur, new, &logflags, delta))) |
| 621 | goto done; | 637 | goto done; |
| 622 | } else { | 638 | } else { |
| 623 | ASSERT(new->br_state == XFS_EXT_UNWRITTEN); | 639 | ASSERT(new->br_state == XFS_EXT_UNWRITTEN); |
| 624 | if ((error = xfs_bmap_add_extent_unwritten_real( | 640 | if ((error = xfs_bmap_add_extent_unwritten_real( |
| 625 | ip, idx, &cur, new, &logflags))) | 641 | ip, idx, &cur, new, &logflags, delta))) |
| 626 | goto done; | 642 | goto done; |
| 627 | } | 643 | } |
| 628 | ASSERT(*curp == cur || *curp == NULL); | 644 | ASSERT(*curp == cur || *curp == NULL); |
| @@ -635,7 +651,7 @@ xfs_bmap_add_extent( | |||
| 635 | ASSERT((cur->bc_private.b.flags & | 651 | ASSERT((cur->bc_private.b.flags & |
| 636 | XFS_BTCUR_BPRV_WASDEL) == 0); | 652 | XFS_BTCUR_BPRV_WASDEL) == 0); |
| 637 | if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, | 653 | if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, |
| 638 | new, &logflags, whichfork))) | 654 | new, &logflags, delta, whichfork))) |
| 639 | goto done; | 655 | goto done; |
| 640 | } | 656 | } |
| 641 | } | 657 | } |
| @@ -700,6 +716,7 @@ xfs_bmap_add_extent_delay_real( | |||
| 700 | xfs_fsblock_t *first, /* pointer to firstblock variable */ | 716 | xfs_fsblock_t *first, /* pointer to firstblock variable */ |
| 701 | xfs_bmap_free_t *flist, /* list of extents to be freed */ | 717 | xfs_bmap_free_t *flist, /* list of extents to be freed */ |
| 702 | int *logflagsp, /* inode logging flags */ | 718 | int *logflagsp, /* inode logging flags */ |
| 719 | xfs_extdelta_t *delta, /* Change made to incore extents */ | ||
| 703 | int rsvd) /* OK to use reserved data block allocation */ | 720 | int rsvd) /* OK to use reserved data block allocation */ |
| 704 | { | 721 | { |
| 705 | xfs_btree_cur_t *cur; /* btree cursor */ | 722 | xfs_btree_cur_t *cur; /* btree cursor */ |
| @@ -716,8 +733,8 @@ xfs_bmap_add_extent_delay_real( | |||
| 716 | /* left is 0, right is 1, prev is 2 */ | 733 | /* left is 0, right is 1, prev is 2 */ |
| 717 | int rval=0; /* return value (logging flags) */ | 734 | int rval=0; /* return value (logging flags) */ |
| 718 | int state = 0;/* state bits, accessed thru macros */ | 735 | int state = 0;/* state bits, accessed thru macros */ |
| 719 | xfs_filblks_t temp; /* value for dnew calculations */ | 736 | xfs_filblks_t temp=0; /* value for dnew calculations */ |
| 720 | xfs_filblks_t temp2; /* value for dnew calculations */ | 737 | xfs_filblks_t temp2=0;/* value for dnew calculations */ |
| 721 | int tmp_rval; /* partial logging flags */ | 738 | int tmp_rval; /* partial logging flags */ |
| 722 | enum { /* bit number definitions for state */ | 739 | enum { /* bit number definitions for state */ |
| 723 | LEFT_CONTIG, RIGHT_CONTIG, | 740 | LEFT_CONTIG, RIGHT_CONTIG, |
| @@ -839,6 +856,11 @@ xfs_bmap_add_extent_delay_real( | |||
| 839 | goto done; | 856 | goto done; |
| 840 | } | 857 | } |
| 841 | *dnew = 0; | 858 | *dnew = 0; |
| 859 | /* DELTA: Three in-core extents are replaced by one. */ | ||
| 860 | temp = LEFT.br_startoff; | ||
| 861 | temp2 = LEFT.br_blockcount + | ||
| 862 | PREV.br_blockcount + | ||
| 863 | RIGHT.br_blockcount; | ||
| 842 | break; | 864 | break; |
| 843 | 865 | ||
| 844 | case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG): | 866 | case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG): |
| @@ -872,6 +894,10 @@ xfs_bmap_add_extent_delay_real( | |||
| 872 | goto done; | 894 | goto done; |
| 873 | } | 895 | } |
| 874 | *dnew = 0; | 896 | *dnew = 0; |
| 897 | /* DELTA: Two in-core extents are replaced by one. */ | ||
| 898 | temp = LEFT.br_startoff; | ||
| 899 | temp2 = LEFT.br_blockcount + | ||
| 900 | PREV.br_blockcount; | ||
| 875 | break; | 901 | break; |
| 876 | 902 | ||
| 877 | case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG): | 903 | case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG): |
| @@ -906,6 +932,10 @@ xfs_bmap_add_extent_delay_real( | |||
| 906 | goto done; | 932 | goto done; |
| 907 | } | 933 | } |
| 908 | *dnew = 0; | 934 | *dnew = 0; |
| 935 | /* DELTA: Two in-core extents are replaced by one. */ | ||
| 936 | temp = PREV.br_startoff; | ||
| 937 | temp2 = PREV.br_blockcount + | ||
| 938 | RIGHT.br_blockcount; | ||
| 909 | break; | 939 | break; |
| 910 | 940 | ||
| 911 | case MASK2(LEFT_FILLING, RIGHT_FILLING): | 941 | case MASK2(LEFT_FILLING, RIGHT_FILLING): |
| @@ -936,6 +966,9 @@ xfs_bmap_add_extent_delay_real( | |||
| 936 | ASSERT(i == 1); | 966 | ASSERT(i == 1); |
| 937 | } | 967 | } |
| 938 | *dnew = 0; | 968 | *dnew = 0; |
| 969 | /* DELTA: The in-core extent described by new changed type. */ | ||
| 970 | temp = new->br_startoff; | ||
| 971 | temp2 = new->br_blockcount; | ||
| 939 | break; | 972 | break; |
| 940 | 973 | ||
| 941 | case MASK2(LEFT_FILLING, LEFT_CONTIG): | 974 | case MASK2(LEFT_FILLING, LEFT_CONTIG): |
| @@ -978,6 +1011,10 @@ xfs_bmap_add_extent_delay_real( | |||
| 978 | xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx, | 1011 | xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx, |
| 979 | XFS_DATA_FORK); | 1012 | XFS_DATA_FORK); |
| 980 | *dnew = temp; | 1013 | *dnew = temp; |
| 1014 | /* DELTA: The boundary between two in-core extents moved. */ | ||
| 1015 | temp = LEFT.br_startoff; | ||
| 1016 | temp2 = LEFT.br_blockcount + | ||
| 1017 | PREV.br_blockcount; | ||
| 981 | break; | 1018 | break; |
| 982 | 1019 | ||
| 983 | case MASK(LEFT_FILLING): | 1020 | case MASK(LEFT_FILLING): |
| @@ -1025,6 +1062,9 @@ xfs_bmap_add_extent_delay_real( | |||
| 1025 | xfs_bmap_trace_post_update(fname, "LF", ip, idx + 1, | 1062 | xfs_bmap_trace_post_update(fname, "LF", ip, idx + 1, |
| 1026 | XFS_DATA_FORK); | 1063 | XFS_DATA_FORK); |
| 1027 | *dnew = temp; | 1064 | *dnew = temp; |
| 1065 | /* DELTA: One in-core extent is split in two. */ | ||
| 1066 | temp = PREV.br_startoff; | ||
| 1067 | temp2 = PREV.br_blockcount; | ||
| 1028 | break; | 1068 | break; |
| 1029 | 1069 | ||
| 1030 | case MASK2(RIGHT_FILLING, RIGHT_CONTIG): | 1070 | case MASK2(RIGHT_FILLING, RIGHT_CONTIG): |
| @@ -1067,6 +1107,10 @@ xfs_bmap_add_extent_delay_real( | |||
| 1067 | xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx, | 1107 | xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx, |
| 1068 | XFS_DATA_FORK); | 1108 | XFS_DATA_FORK); |
| 1069 | *dnew = temp; | 1109 | *dnew = temp; |
| 1110 | /* DELTA: The boundary between two in-core extents moved. */ | ||
| 1111 | temp = PREV.br_startoff; | ||
| 1112 | temp2 = PREV.br_blockcount + | ||
| 1113 | RIGHT.br_blockcount; | ||
| 1070 | break; | 1114 | break; |
| 1071 | 1115 | ||
| 1072 | case MASK(RIGHT_FILLING): | 1116 | case MASK(RIGHT_FILLING): |
| @@ -1112,6 +1156,9 @@ xfs_bmap_add_extent_delay_real( | |||
| 1112 | xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); | 1156 | xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); |
| 1113 | xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK); | 1157 | xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK); |
| 1114 | *dnew = temp; | 1158 | *dnew = temp; |
| 1159 | /* DELTA: One in-core extent is split in two. */ | ||
| 1160 | temp = PREV.br_startoff; | ||
| 1161 | temp2 = PREV.br_blockcount; | ||
| 1115 | break; | 1162 | break; |
| 1116 | 1163 | ||
| 1117 | case 0: | 1164 | case 0: |
| @@ -1194,6 +1241,9 @@ xfs_bmap_add_extent_delay_real( | |||
| 1194 | xfs_bmap_trace_post_update(fname, "0", ip, idx + 2, | 1241 | xfs_bmap_trace_post_update(fname, "0", ip, idx + 2, |
| 1195 | XFS_DATA_FORK); | 1242 | XFS_DATA_FORK); |
| 1196 | *dnew = temp + temp2; | 1243 | *dnew = temp + temp2; |
| 1244 | /* DELTA: One in-core extent is split in three. */ | ||
| 1245 | temp = PREV.br_startoff; | ||
| 1246 | temp2 = PREV.br_blockcount; | ||
| 1197 | break; | 1247 | break; |
| 1198 | 1248 | ||
| 1199 | case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): | 1249 | case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): |
| @@ -1209,6 +1259,13 @@ xfs_bmap_add_extent_delay_real( | |||
| 1209 | ASSERT(0); | 1259 | ASSERT(0); |
| 1210 | } | 1260 | } |
| 1211 | *curp = cur; | 1261 | *curp = cur; |
| 1262 | if (delta) { | ||
| 1263 | temp2 += temp; | ||
| 1264 | if (delta->xed_startoff > temp) | ||
| 1265 | delta->xed_startoff = temp; | ||
| 1266 | if (delta->xed_blockcount < temp2) | ||
| 1267 | delta->xed_blockcount = temp2; | ||
| 1268 | } | ||
| 1212 | done: | 1269 | done: |
| 1213 | *logflagsp = rval; | 1270 | *logflagsp = rval; |
| 1214 | return error; | 1271 | return error; |
| @@ -1235,7 +1292,8 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1235 | xfs_extnum_t idx, /* extent number to update/insert */ | 1292 | xfs_extnum_t idx, /* extent number to update/insert */ |
| 1236 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ | 1293 | xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ |
| 1237 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | 1294 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ |
| 1238 | int *logflagsp) /* inode logging flags */ | 1295 | int *logflagsp, /* inode logging flags */ |
| 1296 | xfs_extdelta_t *delta) /* Change made to incore extents */ | ||
| 1239 | { | 1297 | { |
| 1240 | xfs_btree_cur_t *cur; /* btree cursor */ | 1298 | xfs_btree_cur_t *cur; /* btree cursor */ |
| 1241 | xfs_bmbt_rec_t *ep; /* extent entry for idx */ | 1299 | xfs_bmbt_rec_t *ep; /* extent entry for idx */ |
| @@ -1252,6 +1310,8 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1252 | /* left is 0, right is 1, prev is 2 */ | 1310 | /* left is 0, right is 1, prev is 2 */ |
| 1253 | int rval=0; /* return value (logging flags) */ | 1311 | int rval=0; /* return value (logging flags) */ |
| 1254 | int state = 0;/* state bits, accessed thru macros */ | 1312 | int state = 0;/* state bits, accessed thru macros */ |
| 1313 | xfs_filblks_t temp=0; | ||
| 1314 | xfs_filblks_t temp2=0; | ||
| 1255 | enum { /* bit number definitions for state */ | 1315 | enum { /* bit number definitions for state */ |
| 1256 | LEFT_CONTIG, RIGHT_CONTIG, | 1316 | LEFT_CONTIG, RIGHT_CONTIG, |
| 1257 | LEFT_FILLING, RIGHT_FILLING, | 1317 | LEFT_FILLING, RIGHT_FILLING, |
| @@ -1380,6 +1440,11 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1380 | RIGHT.br_blockcount, LEFT.br_state))) | 1440 | RIGHT.br_blockcount, LEFT.br_state))) |
| 1381 | goto done; | 1441 | goto done; |
| 1382 | } | 1442 | } |
| 1443 | /* DELTA: Three in-core extents are replaced by one. */ | ||
| 1444 | temp = LEFT.br_startoff; | ||
| 1445 | temp2 = LEFT.br_blockcount + | ||
| 1446 | PREV.br_blockcount + | ||
| 1447 | RIGHT.br_blockcount; | ||
| 1383 | break; | 1448 | break; |
| 1384 | 1449 | ||
| 1385 | case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG): | 1450 | case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG): |
| @@ -1419,6 +1484,10 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1419 | LEFT.br_state))) | 1484 | LEFT.br_state))) |
| 1420 | goto done; | 1485 | goto done; |
| 1421 | } | 1486 | } |
| 1487 | /* DELTA: Two in-core extents are replaced by one. */ | ||
| 1488 | temp = LEFT.br_startoff; | ||
| 1489 | temp2 = LEFT.br_blockcount + | ||
| 1490 | PREV.br_blockcount; | ||
| 1422 | break; | 1491 | break; |
| 1423 | 1492 | ||
| 1424 | case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG): | 1493 | case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG): |
| @@ -1459,6 +1528,10 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1459 | newext))) | 1528 | newext))) |
| 1460 | goto done; | 1529 | goto done; |
| 1461 | } | 1530 | } |
| 1531 | /* DELTA: Two in-core extents are replaced by one. */ | ||
| 1532 | temp = PREV.br_startoff; | ||
| 1533 | temp2 = PREV.br_blockcount + | ||
| 1534 | RIGHT.br_blockcount; | ||
| 1462 | break; | 1535 | break; |
| 1463 | 1536 | ||
| 1464 | case MASK2(LEFT_FILLING, RIGHT_FILLING): | 1537 | case MASK2(LEFT_FILLING, RIGHT_FILLING): |
| @@ -1487,6 +1560,9 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1487 | newext))) | 1560 | newext))) |
| 1488 | goto done; | 1561 | goto done; |
| 1489 | } | 1562 | } |
| 1563 | /* DELTA: The in-core extent described by new changed type. */ | ||
| 1564 | temp = new->br_startoff; | ||
| 1565 | temp2 = new->br_blockcount; | ||
| 1490 | break; | 1566 | break; |
| 1491 | 1567 | ||
| 1492 | case MASK2(LEFT_FILLING, LEFT_CONTIG): | 1568 | case MASK2(LEFT_FILLING, LEFT_CONTIG): |
| @@ -1534,6 +1610,10 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1534 | LEFT.br_state)) | 1610 | LEFT.br_state)) |
| 1535 | goto done; | 1611 | goto done; |
| 1536 | } | 1612 | } |
| 1613 | /* DELTA: The boundary between two in-core extents moved. */ | ||
| 1614 | temp = LEFT.br_startoff; | ||
| 1615 | temp2 = LEFT.br_blockcount + | ||
| 1616 | PREV.br_blockcount; | ||
| 1537 | break; | 1617 | break; |
| 1538 | 1618 | ||
| 1539 | case MASK(LEFT_FILLING): | 1619 | case MASK(LEFT_FILLING): |
| @@ -1574,6 +1654,9 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1574 | goto done; | 1654 | goto done; |
| 1575 | ASSERT(i == 1); | 1655 | ASSERT(i == 1); |
| 1576 | } | 1656 | } |
| 1657 | /* DELTA: One in-core extent is split in two. */ | ||
| 1658 | temp = PREV.br_startoff; | ||
| 1659 | temp2 = PREV.br_blockcount; | ||
| 1577 | break; | 1660 | break; |
| 1578 | 1661 | ||
| 1579 | case MASK2(RIGHT_FILLING, RIGHT_CONTIG): | 1662 | case MASK2(RIGHT_FILLING, RIGHT_CONTIG): |
| @@ -1617,6 +1700,10 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1617 | newext))) | 1700 | newext))) |
| 1618 | goto done; | 1701 | goto done; |
| 1619 | } | 1702 | } |
| 1703 | /* DELTA: The boundary between two in-core extents moved. */ | ||
| 1704 | temp = PREV.br_startoff; | ||
| 1705 | temp2 = PREV.br_blockcount + | ||
| 1706 | RIGHT.br_blockcount; | ||
| 1620 | break; | 1707 | break; |
| 1621 | 1708 | ||
| 1622 | case MASK(RIGHT_FILLING): | 1709 | case MASK(RIGHT_FILLING): |
| @@ -1657,6 +1744,9 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1657 | goto done; | 1744 | goto done; |
| 1658 | ASSERT(i == 1); | 1745 | ASSERT(i == 1); |
| 1659 | } | 1746 | } |
| 1747 | /* DELTA: One in-core extent is split in two. */ | ||
| 1748 | temp = PREV.br_startoff; | ||
| 1749 | temp2 = PREV.br_blockcount; | ||
| 1660 | break; | 1750 | break; |
| 1661 | 1751 | ||
| 1662 | case 0: | 1752 | case 0: |
| @@ -1710,6 +1800,9 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1710 | goto done; | 1800 | goto done; |
| 1711 | ASSERT(i == 1); | 1801 | ASSERT(i == 1); |
| 1712 | } | 1802 | } |
| 1803 | /* DELTA: One in-core extent is split in three. */ | ||
| 1804 | temp = PREV.br_startoff; | ||
| 1805 | temp2 = PREV.br_blockcount; | ||
| 1713 | break; | 1806 | break; |
| 1714 | 1807 | ||
| 1715 | case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): | 1808 | case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): |
| @@ -1725,6 +1818,13 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1725 | ASSERT(0); | 1818 | ASSERT(0); |
| 1726 | } | 1819 | } |
| 1727 | *curp = cur; | 1820 | *curp = cur; |
| 1821 | if (delta) { | ||
| 1822 | temp2 += temp; | ||
| 1823 | if (delta->xed_startoff > temp) | ||
| 1824 | delta->xed_startoff = temp; | ||
| 1825 | if (delta->xed_blockcount < temp2) | ||
| 1826 | delta->xed_blockcount = temp2; | ||
| 1827 | } | ||
| 1728 | done: | 1828 | done: |
| 1729 | *logflagsp = rval; | 1829 | *logflagsp = rval; |
| 1730 | return error; | 1830 | return error; |
| @@ -1753,6 +1853,7 @@ xfs_bmap_add_extent_hole_delay( | |||
| 1753 | xfs_btree_cur_t *cur, /* if null, not a btree */ | 1853 | xfs_btree_cur_t *cur, /* if null, not a btree */ |
| 1754 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | 1854 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ |
| 1755 | int *logflagsp, /* inode logging flags */ | 1855 | int *logflagsp, /* inode logging flags */ |
| 1856 | xfs_extdelta_t *delta, /* Change made to incore extents */ | ||
| 1756 | int rsvd) /* OK to allocate reserved blocks */ | 1857 | int rsvd) /* OK to allocate reserved blocks */ |
| 1757 | { | 1858 | { |
| 1758 | xfs_bmbt_rec_t *ep; /* extent record for idx */ | 1859 | xfs_bmbt_rec_t *ep; /* extent record for idx */ |
| @@ -1765,7 +1866,8 @@ xfs_bmap_add_extent_hole_delay( | |||
| 1765 | xfs_filblks_t oldlen=0; /* old indirect size */ | 1866 | xfs_filblks_t oldlen=0; /* old indirect size */ |
| 1766 | xfs_bmbt_irec_t right; /* right neighbor extent entry */ | 1867 | xfs_bmbt_irec_t right; /* right neighbor extent entry */ |
| 1767 | int state; /* state bits, accessed thru macros */ | 1868 | int state; /* state bits, accessed thru macros */ |
| 1768 | xfs_filblks_t temp; /* temp for indirect calculations */ | 1869 | xfs_filblks_t temp=0; /* temp for indirect calculations */ |
| 1870 | xfs_filblks_t temp2=0; | ||
| 1769 | enum { /* bit number definitions for state */ | 1871 | enum { /* bit number definitions for state */ |
| 1770 | LEFT_CONTIG, RIGHT_CONTIG, | 1872 | LEFT_CONTIG, RIGHT_CONTIG, |
| 1771 | LEFT_DELAY, RIGHT_DELAY, | 1873 | LEFT_DELAY, RIGHT_DELAY, |
| @@ -1844,6 +1946,9 @@ xfs_bmap_add_extent_hole_delay( | |||
| 1844 | XFS_DATA_FORK); | 1946 | XFS_DATA_FORK); |
| 1845 | xfs_iext_remove(ifp, idx, 1); | 1947 | xfs_iext_remove(ifp, idx, 1); |
| 1846 | ip->i_df.if_lastex = idx - 1; | 1948 | ip->i_df.if_lastex = idx - 1; |
| 1949 | /* DELTA: Two in-core extents were replaced by one. */ | ||
| 1950 | temp2 = temp; | ||
| 1951 | temp = left.br_startoff; | ||
| 1847 | break; | 1952 | break; |
| 1848 | 1953 | ||
| 1849 | case MASK(LEFT_CONTIG): | 1954 | case MASK(LEFT_CONTIG): |
| @@ -1864,6 +1969,9 @@ xfs_bmap_add_extent_hole_delay( | |||
| 1864 | xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, | 1969 | xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, |
| 1865 | XFS_DATA_FORK); | 1970 | XFS_DATA_FORK); |
| 1866 | ip->i_df.if_lastex = idx - 1; | 1971 | ip->i_df.if_lastex = idx - 1; |
| 1972 | /* DELTA: One in-core extent grew into a hole. */ | ||
| 1973 | temp2 = temp; | ||
| 1974 | temp = left.br_startoff; | ||
| 1867 | break; | 1975 | break; |
| 1868 | 1976 | ||
| 1869 | case MASK(RIGHT_CONTIG): | 1977 | case MASK(RIGHT_CONTIG): |
| @@ -1881,6 +1989,9 @@ xfs_bmap_add_extent_hole_delay( | |||
| 1881 | NULLSTARTBLOCK((int)newlen), temp, right.br_state); | 1989 | NULLSTARTBLOCK((int)newlen), temp, right.br_state); |
| 1882 | xfs_bmap_trace_post_update(fname, "RC", ip, idx, XFS_DATA_FORK); | 1990 | xfs_bmap_trace_post_update(fname, "RC", ip, idx, XFS_DATA_FORK); |
| 1883 | ip->i_df.if_lastex = idx; | 1991 | ip->i_df.if_lastex = idx; |
| 1992 | /* DELTA: One in-core extent grew into a hole. */ | ||
| 1993 | temp2 = temp; | ||
| 1994 | temp = new->br_startoff; | ||
| 1884 | break; | 1995 | break; |
| 1885 | 1996 | ||
| 1886 | case 0: | 1997 | case 0: |
| @@ -1894,6 +2005,9 @@ xfs_bmap_add_extent_hole_delay( | |||
| 1894 | XFS_DATA_FORK); | 2005 | XFS_DATA_FORK); |
| 1895 | xfs_iext_insert(ifp, idx, 1, new); | 2006 | xfs_iext_insert(ifp, idx, 1, new); |
| 1896 | ip->i_df.if_lastex = idx; | 2007 | ip->i_df.if_lastex = idx; |
| 2008 | /* DELTA: A new in-core extent was added in a hole. */ | ||
| 2009 | temp2 = new->br_blockcount; | ||
| 2010 | temp = new->br_startoff; | ||
| 1897 | break; | 2011 | break; |
| 1898 | } | 2012 | } |
| 1899 | if (oldlen != newlen) { | 2013 | if (oldlen != newlen) { |
| @@ -1904,6 +2018,13 @@ xfs_bmap_add_extent_hole_delay( | |||
| 1904 | * Nothing to do for disk quota accounting here. | 2018 | * Nothing to do for disk quota accounting here. |
| 1905 | */ | 2019 | */ |
| 1906 | } | 2020 | } |
| 2021 | if (delta) { | ||
| 2022 | temp2 += temp; | ||
| 2023 | if (delta->xed_startoff > temp) | ||
| 2024 | delta->xed_startoff = temp; | ||
| 2025 | if (delta->xed_blockcount < temp2) | ||
| 2026 | delta->xed_blockcount = temp2; | ||
| 2027 | } | ||
| 1907 | *logflagsp = 0; | 2028 | *logflagsp = 0; |
| 1908 | return 0; | 2029 | return 0; |
| 1909 | #undef MASK | 2030 | #undef MASK |
| @@ -1925,6 +2046,7 @@ xfs_bmap_add_extent_hole_real( | |||
| 1925 | xfs_btree_cur_t *cur, /* if null, not a btree */ | 2046 | xfs_btree_cur_t *cur, /* if null, not a btree */ |
| 1926 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ | 2047 | xfs_bmbt_irec_t *new, /* new data to add to file extents */ |
| 1927 | int *logflagsp, /* inode logging flags */ | 2048 | int *logflagsp, /* inode logging flags */ |
| 2049 | xfs_extdelta_t *delta, /* Change made to incore extents */ | ||
| 1928 | int whichfork) /* data or attr fork */ | 2050 | int whichfork) /* data or attr fork */ |
| 1929 | { | 2051 | { |
| 1930 | xfs_bmbt_rec_t *ep; /* pointer to extent entry ins. point */ | 2052 | xfs_bmbt_rec_t *ep; /* pointer to extent entry ins. point */ |
| @@ -1936,7 +2058,10 @@ xfs_bmap_add_extent_hole_real( | |||
| 1936 | xfs_ifork_t *ifp; /* inode fork pointer */ | 2058 | xfs_ifork_t *ifp; /* inode fork pointer */ |
| 1937 | xfs_bmbt_irec_t left; /* left neighbor extent entry */ | 2059 | xfs_bmbt_irec_t left; /* left neighbor extent entry */ |
| 1938 | xfs_bmbt_irec_t right; /* right neighbor extent entry */ | 2060 | xfs_bmbt_irec_t right; /* right neighbor extent entry */ |
| 2061 | int rval=0; /* return value (logging flags) */ | ||
| 1939 | int state; /* state bits, accessed thru macros */ | 2062 | int state; /* state bits, accessed thru macros */ |
| 2063 | xfs_filblks_t temp=0; | ||
| 2064 | xfs_filblks_t temp2=0; | ||
| 1940 | enum { /* bit number definitions for state */ | 2065 | enum { /* bit number definitions for state */ |
| 1941 | LEFT_CONTIG, RIGHT_CONTIG, | 2066 | LEFT_CONTIG, RIGHT_CONTIG, |
| 1942 | LEFT_DELAY, RIGHT_DELAY, | 2067 | LEFT_DELAY, RIGHT_DELAY, |
| @@ -1993,6 +2118,7 @@ xfs_bmap_add_extent_hole_real( | |||
| 1993 | left.br_blockcount + new->br_blockcount + | 2118 | left.br_blockcount + new->br_blockcount + |
| 1994 | right.br_blockcount <= MAXEXTLEN)); | 2119 | right.br_blockcount <= MAXEXTLEN)); |
| 1995 | 2120 | ||
| 2121 | error = 0; | ||
| 1996 | /* | 2122 | /* |
| 1997 | * Select which case we're in here, and implement it. | 2123 | * Select which case we're in here, and implement it. |
| 1998 | */ | 2124 | */ |
| @@ -2018,25 +2144,35 @@ xfs_bmap_add_extent_hole_real( | |||
| 2018 | XFS_IFORK_NEXT_SET(ip, whichfork, | 2144 | XFS_IFORK_NEXT_SET(ip, whichfork, |
| 2019 | XFS_IFORK_NEXTENTS(ip, whichfork) - 1); | 2145 | XFS_IFORK_NEXTENTS(ip, whichfork) - 1); |
| 2020 | if (cur == NULL) { | 2146 | if (cur == NULL) { |
| 2021 | *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); | 2147 | rval = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); |
| 2022 | return 0; | 2148 | } else { |
| 2149 | rval = XFS_ILOG_CORE; | ||
| 2150 | if ((error = xfs_bmbt_lookup_eq(cur, | ||
| 2151 | right.br_startoff, | ||
| 2152 | right.br_startblock, | ||
| 2153 | right.br_blockcount, &i))) | ||
| 2154 | goto done; | ||
| 2155 | ASSERT(i == 1); | ||
| 2156 | if ((error = xfs_bmbt_delete(cur, &i))) | ||
| 2157 | goto done; | ||
| 2158 | ASSERT(i == 1); | ||
| 2159 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) | ||
| 2160 | goto done; | ||
| 2161 | ASSERT(i == 1); | ||
| 2162 | if ((error = xfs_bmbt_update(cur, left.br_startoff, | ||
| 2163 | left.br_startblock, | ||
| 2164 | left.br_blockcount + | ||
| 2165 | new->br_blockcount + | ||
| 2166 | right.br_blockcount, | ||
| 2167 | left.br_state))) | ||
| 2168 | goto done; | ||
| 2023 | } | 2169 | } |
| 2024 | *logflagsp = XFS_ILOG_CORE; | 2170 | /* DELTA: Two in-core extents were replaced by one. */ |
| 2025 | if ((error = xfs_bmbt_lookup_eq(cur, right.br_startoff, | 2171 | temp = left.br_startoff; |
| 2026 | right.br_startblock, right.br_blockcount, &i))) | 2172 | temp2 = left.br_blockcount + |
| 2027 | return error; | 2173 | new->br_blockcount + |
| 2028 | ASSERT(i == 1); | 2174 | right.br_blockcount; |
| 2029 | if ((error = xfs_bmbt_delete(cur, &i))) | 2175 | break; |
| 2030 | return error; | ||
| 2031 | ASSERT(i == 1); | ||
| 2032 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) | ||
| 2033 | return error; | ||
| 2034 | ASSERT(i == 1); | ||
| 2035 | error = xfs_bmbt_update(cur, left.br_startoff, | ||
| 2036 | left.br_startblock, | ||
| 2037 | left.br_blockcount + new->br_blockcount + | ||
| 2038 | right.br_blockcount, left.br_state); | ||
| 2039 | return error; | ||
| 2040 | 2176 | ||
| 2041 | case MASK(LEFT_CONTIG): | 2177 | case MASK(LEFT_CONTIG): |
| 2042 | /* | 2178 | /* |
| @@ -2050,19 +2186,27 @@ xfs_bmap_add_extent_hole_real( | |||
| 2050 | xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, whichfork); | 2186 | xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, whichfork); |
| 2051 | ifp->if_lastex = idx - 1; | 2187 | ifp->if_lastex = idx - 1; |
| 2052 | if (cur == NULL) { | 2188 | if (cur == NULL) { |
| 2053 | *logflagsp = XFS_ILOG_FEXT(whichfork); | 2189 | rval = XFS_ILOG_FEXT(whichfork); |
| 2054 | return 0; | 2190 | } else { |
| 2191 | rval = 0; | ||
| 2192 | if ((error = xfs_bmbt_lookup_eq(cur, | ||
| 2193 | left.br_startoff, | ||
| 2194 | left.br_startblock, | ||
| 2195 | left.br_blockcount, &i))) | ||
| 2196 | goto done; | ||
| 2197 | ASSERT(i == 1); | ||
| 2198 | if ((error = xfs_bmbt_update(cur, left.br_startoff, | ||
| 2199 | left.br_startblock, | ||
| 2200 | left.br_blockcount + | ||
| 2201 | new->br_blockcount, | ||
| 2202 | left.br_state))) | ||
| 2203 | goto done; | ||
| 2055 | } | 2204 | } |
| 2056 | *logflagsp = 0; | 2205 | /* DELTA: One in-core extent grew. */ |
| 2057 | if ((error = xfs_bmbt_lookup_eq(cur, left.br_startoff, | 2206 | temp = left.br_startoff; |
| 2058 | left.br_startblock, left.br_blockcount, &i))) | 2207 | temp2 = left.br_blockcount + |
| 2059 | return error; | 2208 | new->br_blockcount; |
| 2060 | ASSERT(i == 1); | 2209 | break; |
| 2061 | error = xfs_bmbt_update(cur, left.br_startoff, | ||
| 2062 | left.br_startblock, | ||
| 2063 | left.br_blockcount + new->br_blockcount, | ||
| 2064 | left.br_state); | ||
| 2065 | return error; | ||
| 2066 | 2210 | ||
| 2067 | case MASK(RIGHT_CONTIG): | 2211 | case MASK(RIGHT_CONTIG): |
| 2068 | /* | 2212 | /* |
| @@ -2077,19 +2221,27 @@ xfs_bmap_add_extent_hole_real( | |||
| 2077 | xfs_bmap_trace_post_update(fname, "RC", ip, idx, whichfork); | 2221 | xfs_bmap_trace_post_update(fname, "RC", ip, idx, whichfork); |
| 2078 | ifp->if_lastex = idx; | 2222 | ifp->if_lastex = idx; |
| 2079 | if (cur == NULL) { | 2223 | if (cur == NULL) { |
| 2080 | *logflagsp = XFS_ILOG_FEXT(whichfork); | 2224 | rval = XFS_ILOG_FEXT(whichfork); |
| 2081 | return 0; | 2225 | } else { |
| 2226 | rval = 0; | ||
| 2227 | if ((error = xfs_bmbt_lookup_eq(cur, | ||
| 2228 | right.br_startoff, | ||
| 2229 | right.br_startblock, | ||
| 2230 | right.br_blockcount, &i))) | ||
| 2231 | goto done; | ||
| 2232 | ASSERT(i == 1); | ||
| 2233 | if ((error = xfs_bmbt_update(cur, new->br_startoff, | ||
| 2234 | new->br_startblock, | ||
| 2235 | new->br_blockcount + | ||
| 2236 | right.br_blockcount, | ||
| 2237 | right.br_state))) | ||
| 2238 | goto done; | ||
| 2082 | } | 2239 | } |
| 2083 | *logflagsp = 0; | 2240 | /* DELTA: One in-core extent grew. */ |
| 2084 | if ((error = xfs_bmbt_lookup_eq(cur, right.br_startoff, | 2241 | temp = new->br_startoff; |
| 2085 | right.br_startblock, right.br_blockcount, &i))) | 2242 | temp2 = new->br_blockcount + |
| 2086 | return error; | 2243 | right.br_blockcount; |
| 2087 | ASSERT(i == 1); | 2244 | break; |
| 2088 | error = xfs_bmbt_update(cur, new->br_startoff, | ||
| 2089 | new->br_startblock, | ||
| 2090 | new->br_blockcount + right.br_blockcount, | ||
| 2091 | right.br_state); | ||
| 2092 | return error; | ||
| 2093 | 2245 | ||
| 2094 | case 0: | 2246 | case 0: |
| 2095 | /* | 2247 | /* |
| @@ -2104,29 +2256,41 @@ xfs_bmap_add_extent_hole_real( | |||
| 2104 | XFS_IFORK_NEXT_SET(ip, whichfork, | 2256 | XFS_IFORK_NEXT_SET(ip, whichfork, |
| 2105 | XFS_IFORK_NEXTENTS(ip, whichfork) + 1); | 2257 | XFS_IFORK_NEXTENTS(ip, whichfork) + 1); |
| 2106 | if (cur == NULL) { | 2258 | if (cur == NULL) { |
| 2107 | *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); | 2259 | rval = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); |
| 2108 | return 0; | 2260 | } else { |
| 2261 | rval = XFS_ILOG_CORE; | ||
| 2262 | if ((error = xfs_bmbt_lookup_eq(cur, | ||
| 2263 | new->br_startoff, | ||
| 2264 | new->br_startblock, | ||
| 2265 | new->br_blockcount, &i))) | ||
| 2266 | goto done; | ||
| 2267 | ASSERT(i == 0); | ||
| 2268 | cur->bc_rec.b.br_state = new->br_state; | ||
| 2269 | if ((error = xfs_bmbt_insert(cur, &i))) | ||
| 2270 | goto done; | ||
| 2271 | ASSERT(i == 1); | ||
| 2109 | } | 2272 | } |
| 2110 | *logflagsp = XFS_ILOG_CORE; | 2273 | /* DELTA: A new extent was added in a hole. */ |
| 2111 | if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, | 2274 | temp = new->br_startoff; |
| 2112 | new->br_startblock, new->br_blockcount, &i))) | 2275 | temp2 = new->br_blockcount; |
| 2113 | return error; | 2276 | break; |
| 2114 | ASSERT(i == 0); | 2277 | } |
| 2115 | cur->bc_rec.b.br_state = new->br_state; | 2278 | if (delta) { |
| 2116 | if ((error = xfs_bmbt_insert(cur, &i))) | 2279 | temp2 += temp; |
| 2117 | return error; | 2280 | if (delta->xed_startoff > temp) |
| 2118 | ASSERT(i == 1); | 2281 | delta->xed_startoff = temp; |
| 2119 | return 0; | 2282 | if (delta->xed_blockcount < temp2) |
| 2283 | delta->xed_blockcount = temp2; | ||
| 2120 | } | 2284 | } |
| 2285 | done: | ||
| 2286 | *logflagsp = rval; | ||
| 2287 | return error; | ||
| 2121 | #undef MASK | 2288 | #undef MASK |
| 2122 | #undef MASK2 | 2289 | #undef MASK2 |
| 2123 | #undef STATE_SET | 2290 | #undef STATE_SET |
| 2124 | #undef STATE_TEST | 2291 | #undef STATE_TEST |
| 2125 | #undef STATE_SET_TEST | 2292 | #undef STATE_SET_TEST |
| 2126 | #undef SWITCH_STATE | 2293 | #undef SWITCH_STATE |
| 2127 | /* NOTREACHED */ | ||
| 2128 | ASSERT(0); | ||
| 2129 | return 0; /* keep gcc quite */ | ||
| 2130 | } | 2294 | } |
| 2131 | 2295 | ||
| 2132 | /* | 2296 | /* |
| @@ -2598,6 +2762,7 @@ xfs_bmap_btalloc( | |||
| 2598 | args.mp = mp; | 2762 | args.mp = mp; |
| 2599 | args.fsbno = ap->rval; | 2763 | args.fsbno = ap->rval; |
| 2600 | args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks); | 2764 | args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks); |
| 2765 | args.firstblock = ap->firstblock; | ||
| 2601 | blen = 0; | 2766 | blen = 0; |
| 2602 | if (nullfb) { | 2767 | if (nullfb) { |
| 2603 | args.type = XFS_ALLOCTYPE_START_BNO; | 2768 | args.type = XFS_ALLOCTYPE_START_BNO; |
| @@ -2657,7 +2822,7 @@ xfs_bmap_btalloc( | |||
| 2657 | else | 2822 | else |
| 2658 | args.minlen = ap->alen; | 2823 | args.minlen = ap->alen; |
| 2659 | } else if (ap->low) { | 2824 | } else if (ap->low) { |
| 2660 | args.type = XFS_ALLOCTYPE_FIRST_AG; | 2825 | args.type = XFS_ALLOCTYPE_START_BNO; |
| 2661 | args.total = args.minlen = ap->minlen; | 2826 | args.total = args.minlen = ap->minlen; |
| 2662 | } else { | 2827 | } else { |
| 2663 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 2828 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
| @@ -2669,7 +2834,7 @@ xfs_bmap_btalloc( | |||
| 2669 | args.prod = ap->ip->i_d.di_extsize; | 2834 | args.prod = ap->ip->i_d.di_extsize; |
| 2670 | if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod))) | 2835 | if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod))) |
| 2671 | args.mod = (xfs_extlen_t)(args.prod - args.mod); | 2836 | args.mod = (xfs_extlen_t)(args.prod - args.mod); |
| 2672 | } else if (unlikely(mp->m_sb.sb_blocksize >= NBPP)) { | 2837 | } else if (mp->m_sb.sb_blocksize >= NBPP) { |
| 2673 | args.prod = 1; | 2838 | args.prod = 1; |
| 2674 | args.mod = 0; | 2839 | args.mod = 0; |
| 2675 | } else { | 2840 | } else { |
| @@ -2885,6 +3050,7 @@ xfs_bmap_del_extent( | |||
| 2885 | xfs_btree_cur_t *cur, /* if null, not a btree */ | 3050 | xfs_btree_cur_t *cur, /* if null, not a btree */ |
| 2886 | xfs_bmbt_irec_t *del, /* data to remove from extents */ | 3051 | xfs_bmbt_irec_t *del, /* data to remove from extents */ |
| 2887 | int *logflagsp, /* inode logging flags */ | 3052 | int *logflagsp, /* inode logging flags */ |
| 3053 | xfs_extdelta_t *delta, /* Change made to incore extents */ | ||
| 2888 | int whichfork, /* data or attr fork */ | 3054 | int whichfork, /* data or attr fork */ |
| 2889 | int rsvd) /* OK to allocate reserved blocks */ | 3055 | int rsvd) /* OK to allocate reserved blocks */ |
| 2890 | { | 3056 | { |
| @@ -3193,6 +3359,14 @@ xfs_bmap_del_extent( | |||
| 3193 | if (da_old > da_new) | 3359 | if (da_old > da_new) |
| 3194 | xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int)(da_old - da_new), | 3360 | xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int)(da_old - da_new), |
| 3195 | rsvd); | 3361 | rsvd); |
| 3362 | if (delta) { | ||
| 3363 | /* DELTA: report the original extent. */ | ||
| 3364 | if (delta->xed_startoff > got.br_startoff) | ||
| 3365 | delta->xed_startoff = got.br_startoff; | ||
| 3366 | if (delta->xed_blockcount < got.br_startoff+got.br_blockcount) | ||
| 3367 | delta->xed_blockcount = got.br_startoff + | ||
| 3368 | got.br_blockcount; | ||
| 3369 | } | ||
| 3196 | done: | 3370 | done: |
| 3197 | *logflagsp = flags; | 3371 | *logflagsp = flags; |
| 3198 | return error; | 3372 | return error; |
| @@ -3279,6 +3453,7 @@ xfs_bmap_extents_to_btree( | |||
| 3279 | XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); | 3453 | XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); |
| 3280 | args.tp = tp; | 3454 | args.tp = tp; |
| 3281 | args.mp = mp; | 3455 | args.mp = mp; |
| 3456 | args.firstblock = *firstblock; | ||
| 3282 | if (*firstblock == NULLFSBLOCK) { | 3457 | if (*firstblock == NULLFSBLOCK) { |
| 3283 | args.type = XFS_ALLOCTYPE_START_BNO; | 3458 | args.type = XFS_ALLOCTYPE_START_BNO; |
| 3284 | args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino); | 3459 | args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino); |
| @@ -3414,6 +3589,7 @@ xfs_bmap_local_to_extents( | |||
| 3414 | 3589 | ||
| 3415 | args.tp = tp; | 3590 | args.tp = tp; |
| 3416 | args.mp = ip->i_mount; | 3591 | args.mp = ip->i_mount; |
| 3592 | args.firstblock = *firstblock; | ||
| 3417 | ASSERT((ifp->if_flags & | 3593 | ASSERT((ifp->if_flags & |
| 3418 | (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE); | 3594 | (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE); |
| 3419 | /* | 3595 | /* |
| @@ -3753,7 +3929,7 @@ xfs_bunmap_trace( | |||
| 3753 | if (ip->i_rwtrace == NULL) | 3929 | if (ip->i_rwtrace == NULL) |
| 3754 | return; | 3930 | return; |
| 3755 | ktrace_enter(ip->i_rwtrace, | 3931 | ktrace_enter(ip->i_rwtrace, |
| 3756 | (void *)(__psint_t)XFS_BUNMAPI, | 3932 | (void *)(__psint_t)XFS_BUNMAP, |
| 3757 | (void *)ip, | 3933 | (void *)ip, |
| 3758 | (void *)(__psint_t)((ip->i_d.di_size >> 32) & 0xffffffff), | 3934 | (void *)(__psint_t)((ip->i_d.di_size >> 32) & 0xffffffff), |
| 3759 | (void *)(__psint_t)(ip->i_d.di_size & 0xffffffff), | 3935 | (void *)(__psint_t)(ip->i_d.di_size & 0xffffffff), |
| @@ -4087,8 +4263,8 @@ xfs_bmap_finish( | |||
| 4087 | if (!XFS_FORCED_SHUTDOWN(mp)) | 4263 | if (!XFS_FORCED_SHUTDOWN(mp)) |
| 4088 | xfs_force_shutdown(mp, | 4264 | xfs_force_shutdown(mp, |
| 4089 | (error == EFSCORRUPTED) ? | 4265 | (error == EFSCORRUPTED) ? |
| 4090 | XFS_CORRUPT_INCORE : | 4266 | SHUTDOWN_CORRUPT_INCORE : |
| 4091 | XFS_METADATA_IO_ERROR); | 4267 | SHUTDOWN_META_IO_ERROR); |
| 4092 | return error; | 4268 | return error; |
| 4093 | } | 4269 | } |
| 4094 | xfs_trans_log_efd_extent(ntp, efd, free->xbfi_startblock, | 4270 | xfs_trans_log_efd_extent(ntp, efd, free->xbfi_startblock, |
| @@ -4538,7 +4714,8 @@ xfs_bmapi( | |||
| 4538 | xfs_extlen_t total, /* total blocks needed */ | 4714 | xfs_extlen_t total, /* total blocks needed */ |
| 4539 | xfs_bmbt_irec_t *mval, /* output: map values */ | 4715 | xfs_bmbt_irec_t *mval, /* output: map values */ |
| 4540 | int *nmap, /* i/o: mval size/count */ | 4716 | int *nmap, /* i/o: mval size/count */ |
| 4541 | xfs_bmap_free_t *flist) /* i/o: list extents to free */ | 4717 | xfs_bmap_free_t *flist, /* i/o: list extents to free */ |
| 4718 | xfs_extdelta_t *delta) /* o: change made to incore extents */ | ||
| 4542 | { | 4719 | { |
| 4543 | xfs_fsblock_t abno; /* allocated block number */ | 4720 | xfs_fsblock_t abno; /* allocated block number */ |
| 4544 | xfs_extlen_t alen; /* allocated extent length */ | 4721 | xfs_extlen_t alen; /* allocated extent length */ |
| @@ -4650,6 +4827,10 @@ xfs_bmapi( | |||
| 4650 | end = bno + len; | 4827 | end = bno + len; |
| 4651 | obno = bno; | 4828 | obno = bno; |
| 4652 | bma.ip = NULL; | 4829 | bma.ip = NULL; |
| 4830 | if (delta) { | ||
| 4831 | delta->xed_startoff = NULLFILEOFF; | ||
| 4832 | delta->xed_blockcount = 0; | ||
| 4833 | } | ||
| 4653 | while (bno < end && n < *nmap) { | 4834 | while (bno < end && n < *nmap) { |
| 4654 | /* | 4835 | /* |
| 4655 | * Reading past eof, act as though there's a hole | 4836 | * Reading past eof, act as though there's a hole |
| @@ -4886,8 +5067,8 @@ xfs_bmapi( | |||
| 4886 | got.br_state = XFS_EXT_UNWRITTEN; | 5067 | got.br_state = XFS_EXT_UNWRITTEN; |
| 4887 | } | 5068 | } |
| 4888 | error = xfs_bmap_add_extent(ip, lastx, &cur, &got, | 5069 | error = xfs_bmap_add_extent(ip, lastx, &cur, &got, |
| 4889 | firstblock, flist, &tmp_logflags, whichfork, | 5070 | firstblock, flist, &tmp_logflags, delta, |
| 4890 | (flags & XFS_BMAPI_RSVBLOCKS)); | 5071 | whichfork, (flags & XFS_BMAPI_RSVBLOCKS)); |
| 4891 | logflags |= tmp_logflags; | 5072 | logflags |= tmp_logflags; |
| 4892 | if (error) | 5073 | if (error) |
| 4893 | goto error0; | 5074 | goto error0; |
| @@ -4983,8 +5164,8 @@ xfs_bmapi( | |||
| 4983 | } | 5164 | } |
| 4984 | mval->br_state = XFS_EXT_NORM; | 5165 | mval->br_state = XFS_EXT_NORM; |
| 4985 | error = xfs_bmap_add_extent(ip, lastx, &cur, mval, | 5166 | error = xfs_bmap_add_extent(ip, lastx, &cur, mval, |
| 4986 | firstblock, flist, &tmp_logflags, whichfork, | 5167 | firstblock, flist, &tmp_logflags, delta, |
| 4987 | (flags & XFS_BMAPI_RSVBLOCKS)); | 5168 | whichfork, (flags & XFS_BMAPI_RSVBLOCKS)); |
| 4988 | logflags |= tmp_logflags; | 5169 | logflags |= tmp_logflags; |
| 4989 | if (error) | 5170 | if (error) |
| 4990 | goto error0; | 5171 | goto error0; |
| @@ -5073,7 +5254,14 @@ xfs_bmapi( | |||
| 5073 | ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE || | 5254 | ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE || |
| 5074 | XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max); | 5255 | XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max); |
| 5075 | error = 0; | 5256 | error = 0; |
| 5076 | 5257 | if (delta && delta->xed_startoff != NULLFILEOFF) { | |
| 5258 | /* A change was actually made. | ||
| 5259 | * Note that delta->xed_blockount is an offset at this | ||
| 5260 | * point and needs to be converted to a block count. | ||
| 5261 | */ | ||
| 5262 | ASSERT(delta->xed_blockcount > delta->xed_startoff); | ||
| 5263 | delta->xed_blockcount -= delta->xed_startoff; | ||
| 5264 | } | ||
| 5077 | error0: | 5265 | error0: |
| 5078 | /* | 5266 | /* |
| 5079 | * Log everything. Do this after conversion, there's no point in | 5267 | * Log everything. Do this after conversion, there's no point in |
| @@ -5185,6 +5373,8 @@ xfs_bunmapi( | |||
| 5185 | xfs_fsblock_t *firstblock, /* first allocated block | 5373 | xfs_fsblock_t *firstblock, /* first allocated block |
| 5186 | controls a.g. for allocs */ | 5374 | controls a.g. for allocs */ |
| 5187 | xfs_bmap_free_t *flist, /* i/o: list extents to free */ | 5375 | xfs_bmap_free_t *flist, /* i/o: list extents to free */ |
| 5376 | xfs_extdelta_t *delta, /* o: change made to incore | ||
| 5377 | extents */ | ||
| 5188 | int *done) /* set if not done yet */ | 5378 | int *done) /* set if not done yet */ |
| 5189 | { | 5379 | { |
| 5190 | xfs_btree_cur_t *cur; /* bmap btree cursor */ | 5380 | xfs_btree_cur_t *cur; /* bmap btree cursor */ |
| @@ -5242,6 +5432,10 @@ xfs_bunmapi( | |||
| 5242 | bno = start + len - 1; | 5432 | bno = start + len - 1; |
| 5243 | ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, | 5433 | ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, |
| 5244 | &prev); | 5434 | &prev); |
| 5435 | if (delta) { | ||
| 5436 | delta->xed_startoff = NULLFILEOFF; | ||
| 5437 | delta->xed_blockcount = 0; | ||
| 5438 | } | ||
| 5245 | /* | 5439 | /* |
| 5246 | * Check to see if the given block number is past the end of the | 5440 | * Check to see if the given block number is past the end of the |
| 5247 | * file, back up to the last block if so... | 5441 | * file, back up to the last block if so... |
| @@ -5340,7 +5534,8 @@ xfs_bunmapi( | |||
| 5340 | } | 5534 | } |
| 5341 | del.br_state = XFS_EXT_UNWRITTEN; | 5535 | del.br_state = XFS_EXT_UNWRITTEN; |
| 5342 | error = xfs_bmap_add_extent(ip, lastx, &cur, &del, | 5536 | error = xfs_bmap_add_extent(ip, lastx, &cur, &del, |
| 5343 | firstblock, flist, &logflags, XFS_DATA_FORK, 0); | 5537 | firstblock, flist, &logflags, delta, |
| 5538 | XFS_DATA_FORK, 0); | ||
| 5344 | if (error) | 5539 | if (error) |
| 5345 | goto error0; | 5540 | goto error0; |
| 5346 | goto nodelete; | 5541 | goto nodelete; |
| @@ -5394,7 +5589,7 @@ xfs_bunmapi( | |||
| 5394 | prev.br_state = XFS_EXT_UNWRITTEN; | 5589 | prev.br_state = XFS_EXT_UNWRITTEN; |
| 5395 | error = xfs_bmap_add_extent(ip, lastx - 1, &cur, | 5590 | error = xfs_bmap_add_extent(ip, lastx - 1, &cur, |
| 5396 | &prev, firstblock, flist, &logflags, | 5591 | &prev, firstblock, flist, &logflags, |
| 5397 | XFS_DATA_FORK, 0); | 5592 | delta, XFS_DATA_FORK, 0); |
| 5398 | if (error) | 5593 | if (error) |
| 5399 | goto error0; | 5594 | goto error0; |
| 5400 | goto nodelete; | 5595 | goto nodelete; |
| @@ -5403,7 +5598,7 @@ xfs_bunmapi( | |||
| 5403 | del.br_state = XFS_EXT_UNWRITTEN; | 5598 | del.br_state = XFS_EXT_UNWRITTEN; |
| 5404 | error = xfs_bmap_add_extent(ip, lastx, &cur, | 5599 | error = xfs_bmap_add_extent(ip, lastx, &cur, |
| 5405 | &del, firstblock, flist, &logflags, | 5600 | &del, firstblock, flist, &logflags, |
| 5406 | XFS_DATA_FORK, 0); | 5601 | delta, XFS_DATA_FORK, 0); |
| 5407 | if (error) | 5602 | if (error) |
| 5408 | goto error0; | 5603 | goto error0; |
| 5409 | goto nodelete; | 5604 | goto nodelete; |
| @@ -5456,7 +5651,7 @@ xfs_bunmapi( | |||
| 5456 | goto error0; | 5651 | goto error0; |
| 5457 | } | 5652 | } |
| 5458 | error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del, | 5653 | error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del, |
| 5459 | &tmp_logflags, whichfork, rsvd); | 5654 | &tmp_logflags, delta, whichfork, rsvd); |
| 5460 | logflags |= tmp_logflags; | 5655 | logflags |= tmp_logflags; |
| 5461 | if (error) | 5656 | if (error) |
| 5462 | goto error0; | 5657 | goto error0; |
| @@ -5513,6 +5708,14 @@ nodelete: | |||
| 5513 | ASSERT(ifp->if_ext_max == | 5708 | ASSERT(ifp->if_ext_max == |
| 5514 | XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); | 5709 | XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); |
| 5515 | error = 0; | 5710 | error = 0; |
| 5711 | if (delta && delta->xed_startoff != NULLFILEOFF) { | ||
| 5712 | /* A change was actually made. | ||
| 5713 | * Note that delta->xed_blockount is an offset at this | ||
| 5714 | * point and needs to be converted to a block count. | ||
| 5715 | */ | ||
| 5716 | ASSERT(delta->xed_blockcount > delta->xed_startoff); | ||
| 5717 | delta->xed_blockcount -= delta->xed_startoff; | ||
| 5718 | } | ||
| 5516 | error0: | 5719 | error0: |
| 5517 | /* | 5720 | /* |
| 5518 | * Log everything. Do this after conversion, there's no point in | 5721 | * Log everything. Do this after conversion, there's no point in |
| @@ -5556,7 +5759,7 @@ xfs_getbmap( | |||
| 5556 | __int64_t fixlen; /* length for -1 case */ | 5759 | __int64_t fixlen; /* length for -1 case */ |
| 5557 | int i; /* extent number */ | 5760 | int i; /* extent number */ |
| 5558 | xfs_inode_t *ip; /* xfs incore inode pointer */ | 5761 | xfs_inode_t *ip; /* xfs incore inode pointer */ |
| 5559 | vnode_t *vp; /* corresponding vnode */ | 5762 | bhv_vnode_t *vp; /* corresponding vnode */ |
| 5560 | int lock; /* lock state */ | 5763 | int lock; /* lock state */ |
| 5561 | xfs_bmbt_irec_t *map; /* buffer for user's data */ | 5764 | xfs_bmbt_irec_t *map; /* buffer for user's data */ |
| 5562 | xfs_mount_t *mp; /* file system mount point */ | 5765 | xfs_mount_t *mp; /* file system mount point */ |
| @@ -5653,7 +5856,7 @@ xfs_getbmap( | |||
| 5653 | 5856 | ||
| 5654 | if (whichfork == XFS_DATA_FORK && ip->i_delayed_blks) { | 5857 | if (whichfork == XFS_DATA_FORK && ip->i_delayed_blks) { |
| 5655 | /* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */ | 5858 | /* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */ |
| 5656 | VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error); | 5859 | error = bhv_vop_flush_pages(vp, (xfs_off_t)0, -1, 0, FI_REMAPF); |
| 5657 | } | 5860 | } |
| 5658 | 5861 | ||
| 5659 | ASSERT(whichfork == XFS_ATTR_FORK || ip->i_delayed_blks == 0); | 5862 | ASSERT(whichfork == XFS_ATTR_FORK || ip->i_delayed_blks == 0); |
| @@ -5689,7 +5892,8 @@ xfs_getbmap( | |||
| 5689 | nmap = (nexleft > subnex) ? subnex : nexleft; | 5892 | nmap = (nexleft > subnex) ? subnex : nexleft; |
| 5690 | error = xfs_bmapi(NULL, ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset), | 5893 | error = xfs_bmapi(NULL, ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset), |
| 5691 | XFS_BB_TO_FSB(mp, bmv->bmv_length), | 5894 | XFS_BB_TO_FSB(mp, bmv->bmv_length), |
| 5692 | bmapi_flags, NULL, 0, map, &nmap, NULL); | 5895 | bmapi_flags, NULL, 0, map, &nmap, |
| 5896 | NULL, NULL); | ||
| 5693 | if (error) | 5897 | if (error) |
| 5694 | goto unlock_and_return; | 5898 | goto unlock_and_return; |
| 5695 | ASSERT(nmap <= subnex); | 5899 | ASSERT(nmap <= subnex); |
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index 8e0d73d9ccc4..80e93409b78d 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -26,6 +26,20 @@ struct xfs_mount; | |||
| 26 | struct xfs_trans; | 26 | struct xfs_trans; |
| 27 | 27 | ||
| 28 | /* | 28 | /* |
| 29 | * DELTA: describe a change to the in-core extent list. | ||
| 30 | * | ||
| 31 | * Internally the use of xed_blockount is somewhat funky. | ||
| 32 | * xed_blockcount contains an offset much of the time because this | ||
| 33 | * makes merging changes easier. (xfs_fileoff_t and xfs_filblks_t are | ||
| 34 | * the same underlying type). | ||
| 35 | */ | ||
| 36 | typedef struct xfs_extdelta | ||
| 37 | { | ||
| 38 | xfs_fileoff_t xed_startoff; /* offset of range */ | ||
| 39 | xfs_filblks_t xed_blockcount; /* blocks in range */ | ||
| 40 | } xfs_extdelta_t; | ||
| 41 | |||
| 42 | /* | ||
| 29 | * List of extents to be free "later". | 43 | * List of extents to be free "later". |
| 30 | * The list is kept sorted on xbf_startblock. | 44 | * The list is kept sorted on xbf_startblock. |
| 31 | */ | 45 | */ |
| @@ -275,7 +289,9 @@ xfs_bmapi( | |||
| 275 | xfs_extlen_t total, /* total blocks needed */ | 289 | xfs_extlen_t total, /* total blocks needed */ |
| 276 | struct xfs_bmbt_irec *mval, /* output: map values */ | 290 | struct xfs_bmbt_irec *mval, /* output: map values */ |
| 277 | int *nmap, /* i/o: mval size/count */ | 291 | int *nmap, /* i/o: mval size/count */ |
| 278 | xfs_bmap_free_t *flist); /* i/o: list extents to free */ | 292 | xfs_bmap_free_t *flist, /* i/o: list extents to free */ |
| 293 | xfs_extdelta_t *delta); /* o: change made to incore | ||
| 294 | extents */ | ||
| 279 | 295 | ||
| 280 | /* | 296 | /* |
| 281 | * Map file blocks to filesystem blocks, simple version. | 297 | * Map file blocks to filesystem blocks, simple version. |
| @@ -309,6 +325,8 @@ xfs_bunmapi( | |||
| 309 | xfs_fsblock_t *firstblock, /* first allocated block | 325 | xfs_fsblock_t *firstblock, /* first allocated block |
| 310 | controls a.g. for allocs */ | 326 | controls a.g. for allocs */ |
| 311 | xfs_bmap_free_t *flist, /* i/o: list extents to free */ | 327 | xfs_bmap_free_t *flist, /* i/o: list extents to free */ |
| 328 | xfs_extdelta_t *delta, /* o: change made to incore | ||
| 329 | extents */ | ||
| 312 | int *done); /* set if not done yet */ | 330 | int *done); /* set if not done yet */ |
| 313 | 331 | ||
| 314 | /* | 332 | /* |
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index bea44709afbe..18fb7385d719 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -1569,12 +1567,11 @@ xfs_bmbt_split( | |||
| 1569 | lbno = XFS_DADDR_TO_FSB(args.mp, XFS_BUF_ADDR(lbp)); | 1567 | lbno = XFS_DADDR_TO_FSB(args.mp, XFS_BUF_ADDR(lbp)); |
| 1570 | left = XFS_BUF_TO_BMBT_BLOCK(lbp); | 1568 | left = XFS_BUF_TO_BMBT_BLOCK(lbp); |
| 1571 | args.fsbno = cur->bc_private.b.firstblock; | 1569 | args.fsbno = cur->bc_private.b.firstblock; |
| 1570 | args.firstblock = args.fsbno; | ||
| 1572 | if (args.fsbno == NULLFSBLOCK) { | 1571 | if (args.fsbno == NULLFSBLOCK) { |
| 1573 | args.fsbno = lbno; | 1572 | args.fsbno = lbno; |
| 1574 | args.type = XFS_ALLOCTYPE_START_BNO; | 1573 | args.type = XFS_ALLOCTYPE_START_BNO; |
| 1575 | } else if (cur->bc_private.b.flist->xbf_low) | 1574 | } else |
| 1576 | args.type = XFS_ALLOCTYPE_FIRST_AG; | ||
| 1577 | else | ||
| 1578 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 1575 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
| 1579 | args.mod = args.minleft = args.alignment = args.total = args.isfl = | 1576 | args.mod = args.minleft = args.alignment = args.total = args.isfl = |
| 1580 | args.userdata = args.minalignslop = 0; | 1577 | args.userdata = args.minalignslop = 0; |
| @@ -2356,6 +2353,7 @@ xfs_bmbt_newroot( | |||
| 2356 | args.userdata = args.minalignslop = 0; | 2353 | args.userdata = args.minalignslop = 0; |
| 2357 | args.minlen = args.maxlen = args.prod = 1; | 2354 | args.minlen = args.maxlen = args.prod = 1; |
| 2358 | args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; | 2355 | args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; |
| 2356 | args.firstblock = args.fsbno; | ||
| 2359 | if (args.fsbno == NULLFSBLOCK) { | 2357 | if (args.fsbno == NULLFSBLOCK) { |
| 2360 | #ifdef DEBUG | 2358 | #ifdef DEBUG |
| 2361 | if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) { | 2359 | if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) { |
| @@ -2365,9 +2363,7 @@ xfs_bmbt_newroot( | |||
| 2365 | #endif | 2363 | #endif |
| 2366 | args.fsbno = INT_GET(*pp, ARCH_CONVERT); | 2364 | args.fsbno = INT_GET(*pp, ARCH_CONVERT); |
| 2367 | args.type = XFS_ALLOCTYPE_START_BNO; | 2365 | args.type = XFS_ALLOCTYPE_START_BNO; |
| 2368 | } else if (args.wasdel) | 2366 | } else |
| 2369 | args.type = XFS_ALLOCTYPE_FIRST_AG; | ||
| 2370 | else | ||
| 2371 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 2367 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
| 2372 | if ((error = xfs_alloc_vextent(&args))) { | 2368 | if ((error = xfs_alloc_vextent(&args))) { |
| 2373 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | 2369 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); |
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 52d5d095fc35..ee2255bd6562 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 5fed15682dda..a4aa53974f76 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_inum.h" | 23 | #include "xfs_inum.h" |
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dmapi.h" | 26 | #include "xfs_dmapi.h" |
| 28 | #include "xfs_mount.h" | 27 | #include "xfs_mount.h" |
| 29 | #include "xfs_buf_item.h" | 28 | #include "xfs_buf_item.h" |
| @@ -1030,9 +1029,9 @@ xfs_buf_iodone_callbacks( | |||
| 1030 | if ((XFS_BUF_TARGET(bp) != lasttarg) || | 1029 | if ((XFS_BUF_TARGET(bp) != lasttarg) || |
| 1031 | (time_after(jiffies, (lasttime + 5*HZ)))) { | 1030 | (time_after(jiffies, (lasttime + 5*HZ)))) { |
| 1032 | lasttime = jiffies; | 1031 | lasttime = jiffies; |
| 1033 | prdev("XFS write error in file system meta-data " | 1032 | cmn_err(CE_ALERT, "Device %s, XFS metadata write error" |
| 1034 | "block 0x%llx in %s", | 1033 | " block 0x%llx in %s", |
| 1035 | XFS_BUF_TARGET(bp), | 1034 | XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)), |
| 1036 | (__uint64_t)XFS_BUF_ADDR(bp), mp->m_fsname); | 1035 | (__uint64_t)XFS_BUF_ADDR(bp), mp->m_fsname); |
| 1037 | } | 1036 | } |
| 1038 | lasttarg = XFS_BUF_TARGET(bp); | 1037 | lasttarg = XFS_BUF_TARGET(bp); |
| @@ -1108,7 +1107,7 @@ xfs_buf_error_relse( | |||
| 1108 | XFS_BUF_ERROR(bp,0); | 1107 | XFS_BUF_ERROR(bp,0); |
| 1109 | xfs_buftrace("BUF_ERROR_RELSE", bp); | 1108 | xfs_buftrace("BUF_ERROR_RELSE", bp); |
| 1110 | if (! XFS_FORCED_SHUTDOWN(mp)) | 1109 | if (! XFS_FORCED_SHUTDOWN(mp)) |
| 1111 | xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); | 1110 | xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); |
| 1112 | /* | 1111 | /* |
| 1113 | * We have to unpin the pinned buffers so do the | 1112 | * We have to unpin the pinned buffers so do the |
| 1114 | * callbacks. | 1113 | * callbacks. |
diff --git a/fs/xfs/xfs_cap.h b/fs/xfs/xfs_cap.h index d0035c6e9514..7a0e482dd436 100644 --- a/fs/xfs/xfs_cap.h +++ b/fs/xfs/xfs_cap.h | |||
| @@ -49,12 +49,12 @@ typedef struct xfs_cap_set { | |||
| 49 | 49 | ||
| 50 | #include <linux/posix_cap_xattr.h> | 50 | #include <linux/posix_cap_xattr.h> |
| 51 | 51 | ||
| 52 | struct vnode; | 52 | struct bhv_vnode; |
| 53 | 53 | ||
| 54 | extern int xfs_cap_vhascap(struct vnode *); | 54 | extern int xfs_cap_vhascap(struct bhv_vnode *); |
| 55 | extern int xfs_cap_vset(struct vnode *, void *, size_t); | 55 | extern int xfs_cap_vset(struct bhv_vnode *, void *, size_t); |
| 56 | extern int xfs_cap_vget(struct vnode *, void *, size_t); | 56 | extern int xfs_cap_vget(struct bhv_vnode *, void *, size_t); |
| 57 | extern int xfs_cap_vremove(struct vnode *vp); | 57 | extern int xfs_cap_vremove(struct bhv_vnode *); |
| 58 | 58 | ||
| 59 | #define _CAP_EXISTS xfs_cap_vhascap | 59 | #define _CAP_EXISTS xfs_cap_vhascap |
| 60 | 60 | ||
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 8988b9051175..32ab61d17ace 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| @@ -43,7 +41,6 @@ | |||
| 43 | #include "xfs_bmap.h" | 41 | #include "xfs_bmap.h" |
| 44 | #include "xfs_attr.h" | 42 | #include "xfs_attr.h" |
| 45 | #include "xfs_attr_leaf.h" | 43 | #include "xfs_attr_leaf.h" |
| 46 | #include "xfs_dir_leaf.h" | ||
| 47 | #include "xfs_dir2_data.h" | 44 | #include "xfs_dir2_data.h" |
| 48 | #include "xfs_dir2_leaf.h" | 45 | #include "xfs_dir2_leaf.h" |
| 49 | #include "xfs_dir2_block.h" | 46 | #include "xfs_dir2_block.h" |
| @@ -159,7 +156,7 @@ xfs_da_split(xfs_da_state_t *state) | |||
| 159 | max = state->path.active - 1; | 156 | max = state->path.active - 1; |
| 160 | ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH)); | 157 | ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH)); |
| 161 | ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC || | 158 | ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC || |
| 162 | state->path.blk[max].magic == XFS_DIRX_LEAF_MAGIC(state->mp)); | 159 | state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC); |
| 163 | 160 | ||
| 164 | addblk = &state->path.blk[max]; /* initial dummy value */ | 161 | addblk = &state->path.blk[max]; /* initial dummy value */ |
| 165 | for (i = max; (i >= 0) && addblk; state->path.active--, i--) { | 162 | for (i = max; (i >= 0) && addblk; state->path.active--, i--) { |
| @@ -199,38 +196,7 @@ xfs_da_split(xfs_da_state_t *state) | |||
| 199 | return(error); /* GROT: attr inconsistent */ | 196 | return(error); /* GROT: attr inconsistent */ |
| 200 | addblk = newblk; | 197 | addblk = newblk; |
| 201 | break; | 198 | break; |
| 202 | case XFS_DIR_LEAF_MAGIC: | ||
| 203 | ASSERT(XFS_DIR_IS_V1(state->mp)); | ||
| 204 | error = xfs_dir_leaf_split(state, oldblk, newblk); | ||
| 205 | if ((error != 0) && (error != ENOSPC)) { | ||
| 206 | return(error); /* GROT: dir is inconsistent */ | ||
| 207 | } | ||
| 208 | if (!error) { | ||
| 209 | addblk = newblk; | ||
| 210 | break; | ||
| 211 | } | ||
| 212 | /* | ||
| 213 | * Entry wouldn't fit, split the leaf again. | ||
| 214 | */ | ||
| 215 | state->extravalid = 1; | ||
| 216 | if (state->inleaf) { | ||
| 217 | state->extraafter = 0; /* before newblk */ | ||
| 218 | error = xfs_dir_leaf_split(state, oldblk, | ||
| 219 | &state->extrablk); | ||
| 220 | if (error) | ||
| 221 | return(error); /* GROT: dir incon. */ | ||
| 222 | addblk = newblk; | ||
| 223 | } else { | ||
| 224 | state->extraafter = 1; /* after newblk */ | ||
| 225 | error = xfs_dir_leaf_split(state, newblk, | ||
| 226 | &state->extrablk); | ||
| 227 | if (error) | ||
| 228 | return(error); /* GROT: dir incon. */ | ||
| 229 | addblk = newblk; | ||
| 230 | } | ||
| 231 | break; | ||
| 232 | case XFS_DIR2_LEAFN_MAGIC: | 199 | case XFS_DIR2_LEAFN_MAGIC: |
| 233 | ASSERT(XFS_DIR_IS_V2(state->mp)); | ||
| 234 | error = xfs_dir2_leafn_split(state, oldblk, newblk); | 200 | error = xfs_dir2_leafn_split(state, oldblk, newblk); |
| 235 | if (error) | 201 | if (error) |
| 236 | return error; | 202 | return error; |
| @@ -363,7 +329,6 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, | |||
| 363 | size = (int)((char *)&oldroot->btree[be16_to_cpu(oldroot->hdr.count)] - | 329 | size = (int)((char *)&oldroot->btree[be16_to_cpu(oldroot->hdr.count)] - |
| 364 | (char *)oldroot); | 330 | (char *)oldroot); |
| 365 | } else { | 331 | } else { |
| 366 | ASSERT(XFS_DIR_IS_V2(mp)); | ||
| 367 | ASSERT(be16_to_cpu(oldroot->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC); | 332 | ASSERT(be16_to_cpu(oldroot->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC); |
| 368 | leaf = (xfs_dir2_leaf_t *)oldroot; | 333 | leaf = (xfs_dir2_leaf_t *)oldroot; |
| 369 | size = (int)((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] - | 334 | size = (int)((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] - |
| @@ -379,8 +344,7 @@ xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, | |||
| 379 | * Set up the new root node. | 344 | * Set up the new root node. |
| 380 | */ | 345 | */ |
| 381 | error = xfs_da_node_create(args, | 346 | error = xfs_da_node_create(args, |
| 382 | args->whichfork == XFS_DATA_FORK && | 347 | (args->whichfork == XFS_DATA_FORK) ? mp->m_dirleafblk : 0, |
| 383 | XFS_DIR_IS_V2(mp) ? mp->m_dirleafblk : 0, | ||
| 384 | be16_to_cpu(node->hdr.level) + 1, &bp, args->whichfork); | 348 | be16_to_cpu(node->hdr.level) + 1, &bp, args->whichfork); |
| 385 | if (error) | 349 | if (error) |
| 386 | return(error); | 350 | return(error); |
| @@ -427,10 +391,9 @@ xfs_da_node_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, | |||
| 427 | ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC); | 391 | ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC); |
| 428 | 392 | ||
| 429 | /* | 393 | /* |
| 430 | * With V2 the extra block is data or freespace. | 394 | * With V2 dirs the extra block is data or freespace. |
| 431 | */ | 395 | */ |
| 432 | useextra = state->extravalid && (XFS_DIR_IS_V1(state->mp) || | 396 | useextra = state->extravalid && state->args->whichfork == XFS_ATTR_FORK; |
| 433 | state->args->whichfork == XFS_ATTR_FORK); | ||
| 434 | newcount = 1 + useextra; | 397 | newcount = 1 + useextra; |
| 435 | /* | 398 | /* |
| 436 | * Do we have to split the node? | 399 | * Do we have to split the node? |
| @@ -624,7 +587,7 @@ xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, | |||
| 624 | ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC); | 587 | ASSERT(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC); |
| 625 | ASSERT((oldblk->index >= 0) && (oldblk->index <= be16_to_cpu(node->hdr.count))); | 588 | ASSERT((oldblk->index >= 0) && (oldblk->index <= be16_to_cpu(node->hdr.count))); |
| 626 | ASSERT(newblk->blkno != 0); | 589 | ASSERT(newblk->blkno != 0); |
| 627 | if (state->args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) | 590 | if (state->args->whichfork == XFS_DATA_FORK) |
| 628 | ASSERT(newblk->blkno >= mp->m_dirleafblk && | 591 | ASSERT(newblk->blkno >= mp->m_dirleafblk && |
| 629 | newblk->blkno < mp->m_dirfreeblk); | 592 | newblk->blkno < mp->m_dirfreeblk); |
| 630 | 593 | ||
| @@ -670,7 +633,7 @@ xfs_da_join(xfs_da_state_t *state) | |||
| 670 | save_blk = &state->altpath.blk[ state->path.active-1 ]; | 633 | save_blk = &state->altpath.blk[ state->path.active-1 ]; |
| 671 | ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC); | 634 | ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC); |
| 672 | ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC || | 635 | ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC || |
| 673 | drop_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp)); | 636 | drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); |
| 674 | 637 | ||
| 675 | /* | 638 | /* |
| 676 | * Walk back up the tree joining/deallocating as necessary. | 639 | * Walk back up the tree joining/deallocating as necessary. |
| @@ -693,17 +656,7 @@ xfs_da_join(xfs_da_state_t *state) | |||
| 693 | return(0); | 656 | return(0); |
| 694 | xfs_attr_leaf_unbalance(state, drop_blk, save_blk); | 657 | xfs_attr_leaf_unbalance(state, drop_blk, save_blk); |
| 695 | break; | 658 | break; |
| 696 | case XFS_DIR_LEAF_MAGIC: | ||
| 697 | ASSERT(XFS_DIR_IS_V1(state->mp)); | ||
| 698 | error = xfs_dir_leaf_toosmall(state, &action); | ||
| 699 | if (error) | ||
| 700 | return(error); | ||
| 701 | if (action == 0) | ||
| 702 | return(0); | ||
| 703 | xfs_dir_leaf_unbalance(state, drop_blk, save_blk); | ||
| 704 | break; | ||
| 705 | case XFS_DIR2_LEAFN_MAGIC: | 659 | case XFS_DIR2_LEAFN_MAGIC: |
| 706 | ASSERT(XFS_DIR_IS_V2(state->mp)); | ||
| 707 | error = xfs_dir2_leafn_toosmall(state, &action); | 660 | error = xfs_dir2_leafn_toosmall(state, &action); |
| 708 | if (error) | 661 | if (error) |
| 709 | return error; | 662 | return error; |
| @@ -790,7 +743,7 @@ xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk) | |||
| 790 | ASSERT(bp != NULL); | 743 | ASSERT(bp != NULL); |
| 791 | blkinfo = bp->data; | 744 | blkinfo = bp->data; |
| 792 | if (be16_to_cpu(oldroot->hdr.level) == 1) { | 745 | if (be16_to_cpu(oldroot->hdr.level) == 1) { |
| 793 | ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) || | 746 | ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DIR2_LEAFN_MAGIC || |
| 794 | be16_to_cpu(blkinfo->magic) == XFS_ATTR_LEAF_MAGIC); | 747 | be16_to_cpu(blkinfo->magic) == XFS_ATTR_LEAF_MAGIC); |
| 795 | } else { | 748 | } else { |
| 796 | ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DA_NODE_MAGIC); | 749 | ASSERT(be16_to_cpu(blkinfo->magic) == XFS_DA_NODE_MAGIC); |
| @@ -951,14 +904,7 @@ xfs_da_fixhashpath(xfs_da_state_t *state, xfs_da_state_path_t *path) | |||
| 951 | if (count == 0) | 904 | if (count == 0) |
| 952 | return; | 905 | return; |
| 953 | break; | 906 | break; |
| 954 | case XFS_DIR_LEAF_MAGIC: | ||
| 955 | ASSERT(XFS_DIR_IS_V1(state->mp)); | ||
| 956 | lasthash = xfs_dir_leaf_lasthash(blk->bp, &count); | ||
| 957 | if (count == 0) | ||
| 958 | return; | ||
| 959 | break; | ||
| 960 | case XFS_DIR2_LEAFN_MAGIC: | 907 | case XFS_DIR2_LEAFN_MAGIC: |
| 961 | ASSERT(XFS_DIR_IS_V2(state->mp)); | ||
| 962 | lasthash = xfs_dir2_leafn_lasthash(blk->bp, &count); | 908 | lasthash = xfs_dir2_leafn_lasthash(blk->bp, &count); |
| 963 | if (count == 0) | 909 | if (count == 0) |
| 964 | return; | 910 | return; |
| @@ -1117,10 +1063,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) | |||
| 1117 | * Descend thru the B-tree searching each level for the right | 1063 | * Descend thru the B-tree searching each level for the right |
| 1118 | * node to use, until the right hashval is found. | 1064 | * node to use, until the right hashval is found. |
| 1119 | */ | 1065 | */ |
| 1120 | if (args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(state->mp)) | 1066 | blkno = (args->whichfork == XFS_DATA_FORK)? state->mp->m_dirleafblk : 0; |
| 1121 | blkno = state->mp->m_dirleafblk; | ||
| 1122 | else | ||
| 1123 | blkno = 0; | ||
| 1124 | for (blk = &state->path.blk[0], state->path.active = 1; | 1067 | for (blk = &state->path.blk[0], state->path.active = 1; |
| 1125 | state->path.active <= XFS_DA_NODE_MAXDEPTH; | 1068 | state->path.active <= XFS_DA_NODE_MAXDEPTH; |
| 1126 | blk++, state->path.active++) { | 1069 | blk++, state->path.active++) { |
| @@ -1137,7 +1080,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) | |||
| 1137 | } | 1080 | } |
| 1138 | curr = blk->bp->data; | 1081 | curr = blk->bp->data; |
| 1139 | ASSERT(be16_to_cpu(curr->magic) == XFS_DA_NODE_MAGIC || | 1082 | ASSERT(be16_to_cpu(curr->magic) == XFS_DA_NODE_MAGIC || |
| 1140 | be16_to_cpu(curr->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) || | 1083 | be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC || |
| 1141 | be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC); | 1084 | be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC); |
| 1142 | 1085 | ||
| 1143 | /* | 1086 | /* |
| @@ -1190,16 +1133,10 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) | |||
| 1190 | blk->index = probe; | 1133 | blk->index = probe; |
| 1191 | blkno = be32_to_cpu(btree->before); | 1134 | blkno = be32_to_cpu(btree->before); |
| 1192 | } | 1135 | } |
| 1193 | } | 1136 | } else if (be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC) { |
| 1194 | else if (be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC) { | ||
| 1195 | blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); | 1137 | blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); |
| 1196 | break; | 1138 | break; |
| 1197 | } | 1139 | } else if (be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC) { |
| 1198 | else if (be16_to_cpu(curr->magic) == XFS_DIR_LEAF_MAGIC) { | ||
| 1199 | blk->hashval = xfs_dir_leaf_lasthash(blk->bp, NULL); | ||
| 1200 | break; | ||
| 1201 | } | ||
| 1202 | else if (be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC) { | ||
| 1203 | blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL); | 1140 | blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL); |
| 1204 | break; | 1141 | break; |
| 1205 | } | 1142 | } |
| @@ -1212,12 +1149,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) | |||
| 1212 | * next leaf and keep searching. | 1149 | * next leaf and keep searching. |
| 1213 | */ | 1150 | */ |
| 1214 | for (;;) { | 1151 | for (;;) { |
| 1215 | if (blk->magic == XFS_DIR_LEAF_MAGIC) { | 1152 | if (blk->magic == XFS_DIR2_LEAFN_MAGIC) { |
| 1216 | ASSERT(XFS_DIR_IS_V1(state->mp)); | ||
| 1217 | retval = xfs_dir_leaf_lookup_int(blk->bp, args, | ||
| 1218 | &blk->index); | ||
| 1219 | } else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) { | ||
| 1220 | ASSERT(XFS_DIR_IS_V2(state->mp)); | ||
| 1221 | retval = xfs_dir2_leafn_lookup_int(blk->bp, args, | 1153 | retval = xfs_dir2_leafn_lookup_int(blk->bp, args, |
| 1222 | &blk->index, state); | 1154 | &blk->index, state); |
| 1223 | } | 1155 | } |
| @@ -1270,7 +1202,7 @@ xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, | |||
| 1270 | old_info = old_blk->bp->data; | 1202 | old_info = old_blk->bp->data; |
| 1271 | new_info = new_blk->bp->data; | 1203 | new_info = new_blk->bp->data; |
| 1272 | ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC || | 1204 | ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC || |
| 1273 | old_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) || | 1205 | old_blk->magic == XFS_DIR2_LEAFN_MAGIC || |
| 1274 | old_blk->magic == XFS_ATTR_LEAF_MAGIC); | 1206 | old_blk->magic == XFS_ATTR_LEAF_MAGIC); |
| 1275 | ASSERT(old_blk->magic == be16_to_cpu(old_info->magic)); | 1207 | ASSERT(old_blk->magic == be16_to_cpu(old_info->magic)); |
| 1276 | ASSERT(new_blk->magic == be16_to_cpu(new_info->magic)); | 1208 | ASSERT(new_blk->magic == be16_to_cpu(new_info->magic)); |
| @@ -1280,12 +1212,7 @@ xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, | |||
| 1280 | case XFS_ATTR_LEAF_MAGIC: | 1212 | case XFS_ATTR_LEAF_MAGIC: |
| 1281 | before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp); | 1213 | before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp); |
| 1282 | break; | 1214 | break; |
| 1283 | case XFS_DIR_LEAF_MAGIC: | ||
| 1284 | ASSERT(XFS_DIR_IS_V1(state->mp)); | ||
| 1285 | before = xfs_dir_leaf_order(old_blk->bp, new_blk->bp); | ||
| 1286 | break; | ||
| 1287 | case XFS_DIR2_LEAFN_MAGIC: | 1215 | case XFS_DIR2_LEAFN_MAGIC: |
| 1288 | ASSERT(XFS_DIR_IS_V2(state->mp)); | ||
| 1289 | before = xfs_dir2_leafn_order(old_blk->bp, new_blk->bp); | 1216 | before = xfs_dir2_leafn_order(old_blk->bp, new_blk->bp); |
| 1290 | break; | 1217 | break; |
| 1291 | case XFS_DA_NODE_MAGIC: | 1218 | case XFS_DA_NODE_MAGIC: |
| @@ -1404,7 +1331,7 @@ xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, | |||
| 1404 | save_info = save_blk->bp->data; | 1331 | save_info = save_blk->bp->data; |
| 1405 | drop_info = drop_blk->bp->data; | 1332 | drop_info = drop_blk->bp->data; |
| 1406 | ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC || | 1333 | ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC || |
| 1407 | save_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) || | 1334 | save_blk->magic == XFS_DIR2_LEAFN_MAGIC || |
| 1408 | save_blk->magic == XFS_ATTR_LEAF_MAGIC); | 1335 | save_blk->magic == XFS_ATTR_LEAF_MAGIC); |
| 1409 | ASSERT(save_blk->magic == be16_to_cpu(save_info->magic)); | 1336 | ASSERT(save_blk->magic == be16_to_cpu(save_info->magic)); |
| 1410 | ASSERT(drop_blk->magic == be16_to_cpu(drop_info->magic)); | 1337 | ASSERT(drop_blk->magic == be16_to_cpu(drop_info->magic)); |
| @@ -1529,7 +1456,7 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, | |||
| 1529 | ASSERT(blk->bp != NULL); | 1456 | ASSERT(blk->bp != NULL); |
| 1530 | info = blk->bp->data; | 1457 | info = blk->bp->data; |
| 1531 | ASSERT(be16_to_cpu(info->magic) == XFS_DA_NODE_MAGIC || | 1458 | ASSERT(be16_to_cpu(info->magic) == XFS_DA_NODE_MAGIC || |
| 1532 | be16_to_cpu(info->magic) == XFS_DIRX_LEAF_MAGIC(state->mp) || | 1459 | be16_to_cpu(info->magic) == XFS_DIR2_LEAFN_MAGIC || |
| 1533 | be16_to_cpu(info->magic) == XFS_ATTR_LEAF_MAGIC); | 1460 | be16_to_cpu(info->magic) == XFS_ATTR_LEAF_MAGIC); |
| 1534 | blk->magic = be16_to_cpu(info->magic); | 1461 | blk->magic = be16_to_cpu(info->magic); |
| 1535 | if (blk->magic == XFS_DA_NODE_MAGIC) { | 1462 | if (blk->magic == XFS_DA_NODE_MAGIC) { |
| @@ -1548,20 +1475,13 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, | |||
| 1548 | blk->hashval = xfs_attr_leaf_lasthash(blk->bp, | 1475 | blk->hashval = xfs_attr_leaf_lasthash(blk->bp, |
| 1549 | NULL); | 1476 | NULL); |
| 1550 | break; | 1477 | break; |
| 1551 | case XFS_DIR_LEAF_MAGIC: | ||
| 1552 | ASSERT(XFS_DIR_IS_V1(state->mp)); | ||
| 1553 | blk->hashval = xfs_dir_leaf_lasthash(blk->bp, | ||
| 1554 | NULL); | ||
| 1555 | break; | ||
| 1556 | case XFS_DIR2_LEAFN_MAGIC: | 1478 | case XFS_DIR2_LEAFN_MAGIC: |
| 1557 | ASSERT(XFS_DIR_IS_V2(state->mp)); | ||
| 1558 | blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, | 1479 | blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, |
| 1559 | NULL); | 1480 | NULL); |
| 1560 | break; | 1481 | break; |
| 1561 | default: | 1482 | default: |
| 1562 | ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC || | 1483 | ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC || |
| 1563 | blk->magic == | 1484 | blk->magic == XFS_DIR2_LEAFN_MAGIC); |
| 1564 | XFS_DIRX_LEAF_MAGIC(state->mp)); | ||
| 1565 | break; | 1485 | break; |
| 1566 | } | 1486 | } |
| 1567 | } | 1487 | } |
| @@ -1620,7 +1540,6 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) | |||
| 1620 | xfs_bmbt_irec_t *mapp; | 1540 | xfs_bmbt_irec_t *mapp; |
| 1621 | xfs_inode_t *dp; | 1541 | xfs_inode_t *dp; |
| 1622 | int nmap, error, w, count, c, got, i, mapi; | 1542 | int nmap, error, w, count, c, got, i, mapi; |
| 1623 | xfs_fsize_t size; | ||
| 1624 | xfs_trans_t *tp; | 1543 | xfs_trans_t *tp; |
| 1625 | xfs_mount_t *mp; | 1544 | xfs_mount_t *mp; |
| 1626 | 1545 | ||
| @@ -1631,7 +1550,7 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) | |||
| 1631 | /* | 1550 | /* |
| 1632 | * For new directories adjust the file offset and block count. | 1551 | * For new directories adjust the file offset and block count. |
| 1633 | */ | 1552 | */ |
| 1634 | if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) { | 1553 | if (w == XFS_DATA_FORK) { |
| 1635 | bno = mp->m_dirleafblk; | 1554 | bno = mp->m_dirleafblk; |
| 1636 | count = mp->m_dirblkfsbs; | 1555 | count = mp->m_dirblkfsbs; |
| 1637 | } else { | 1556 | } else { |
| @@ -1641,10 +1560,9 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) | |||
| 1641 | /* | 1560 | /* |
| 1642 | * Find a spot in the file space to put the new block. | 1561 | * Find a spot in the file space to put the new block. |
| 1643 | */ | 1562 | */ |
| 1644 | if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, w))) { | 1563 | if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, w))) |
| 1645 | return error; | 1564 | return error; |
| 1646 | } | 1565 | if (w == XFS_DATA_FORK) |
| 1647 | if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) | ||
| 1648 | ASSERT(bno >= mp->m_dirleafblk && bno < mp->m_dirfreeblk); | 1566 | ASSERT(bno >= mp->m_dirleafblk && bno < mp->m_dirfreeblk); |
| 1649 | /* | 1567 | /* |
| 1650 | * Try mapping it in one filesystem block. | 1568 | * Try mapping it in one filesystem block. |
| @@ -1655,7 +1573,7 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) | |||
| 1655 | XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE|XFS_BMAPI_METADATA| | 1573 | XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE|XFS_BMAPI_METADATA| |
| 1656 | XFS_BMAPI_CONTIG, | 1574 | XFS_BMAPI_CONTIG, |
| 1657 | args->firstblock, args->total, &map, &nmap, | 1575 | args->firstblock, args->total, &map, &nmap, |
| 1658 | args->flist))) { | 1576 | args->flist, NULL))) { |
| 1659 | return error; | 1577 | return error; |
| 1660 | } | 1578 | } |
| 1661 | ASSERT(nmap <= 1); | 1579 | ASSERT(nmap <= 1); |
| @@ -1676,7 +1594,8 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) | |||
| 1676 | XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE| | 1594 | XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE| |
| 1677 | XFS_BMAPI_METADATA, | 1595 | XFS_BMAPI_METADATA, |
| 1678 | args->firstblock, args->total, | 1596 | args->firstblock, args->total, |
| 1679 | &mapp[mapi], &nmap, args->flist))) { | 1597 | &mapp[mapi], &nmap, args->flist, |
| 1598 | NULL))) { | ||
| 1680 | kmem_free(mapp, sizeof(*mapp) * count); | 1599 | kmem_free(mapp, sizeof(*mapp) * count); |
| 1681 | return error; | 1600 | return error; |
| 1682 | } | 1601 | } |
| @@ -1705,19 +1624,6 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) | |||
| 1705 | if (mapp != &map) | 1624 | if (mapp != &map) |
| 1706 | kmem_free(mapp, sizeof(*mapp) * count); | 1625 | kmem_free(mapp, sizeof(*mapp) * count); |
| 1707 | *new_blkno = (xfs_dablk_t)bno; | 1626 | *new_blkno = (xfs_dablk_t)bno; |
| 1708 | /* | ||
| 1709 | * For version 1 directories, adjust the file size if it changed. | ||
| 1710 | */ | ||
| 1711 | if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) { | ||
| 1712 | ASSERT(mapi == 1); | ||
| 1713 | if ((error = xfs_bmap_last_offset(tp, dp, &bno, w))) | ||
| 1714 | return error; | ||
| 1715 | size = XFS_FSB_TO_B(mp, bno); | ||
| 1716 | if (size != dp->i_d.di_size) { | ||
| 1717 | dp->i_d.di_size = size; | ||
| 1718 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | ||
| 1719 | } | ||
| 1720 | } | ||
| 1721 | return 0; | 1627 | return 0; |
| 1722 | } | 1628 | } |
| 1723 | 1629 | ||
| @@ -1742,7 +1648,6 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop, | |||
| 1742 | int error, w, entno, level, dead_level; | 1648 | int error, w, entno, level, dead_level; |
| 1743 | xfs_da_blkinfo_t *dead_info, *sib_info; | 1649 | xfs_da_blkinfo_t *dead_info, *sib_info; |
| 1744 | xfs_da_intnode_t *par_node, *dead_node; | 1650 | xfs_da_intnode_t *par_node, *dead_node; |
| 1745 | xfs_dir_leafblock_t *dead_leaf; | ||
| 1746 | xfs_dir2_leaf_t *dead_leaf2; | 1651 | xfs_dir2_leaf_t *dead_leaf2; |
| 1747 | xfs_dahash_t dead_hash; | 1652 | xfs_dahash_t dead_hash; |
| 1748 | 1653 | ||
| @@ -1753,11 +1658,8 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop, | |||
| 1753 | w = args->whichfork; | 1658 | w = args->whichfork; |
| 1754 | ASSERT(w == XFS_DATA_FORK); | 1659 | ASSERT(w == XFS_DATA_FORK); |
| 1755 | mp = ip->i_mount; | 1660 | mp = ip->i_mount; |
| 1756 | if (XFS_DIR_IS_V2(mp)) { | 1661 | lastoff = mp->m_dirfreeblk; |
| 1757 | lastoff = mp->m_dirfreeblk; | 1662 | error = xfs_bmap_last_before(tp, ip, &lastoff, w); |
| 1758 | error = xfs_bmap_last_before(tp, ip, &lastoff, w); | ||
| 1759 | } else | ||
| 1760 | error = xfs_bmap_last_offset(tp, ip, &lastoff, w); | ||
| 1761 | if (error) | 1663 | if (error) |
| 1762 | return error; | 1664 | return error; |
| 1763 | if (unlikely(lastoff == 0)) { | 1665 | if (unlikely(lastoff == 0)) { |
| @@ -1780,14 +1682,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop, | |||
| 1780 | /* | 1682 | /* |
| 1781 | * Get values from the moved block. | 1683 | * Get values from the moved block. |
| 1782 | */ | 1684 | */ |
| 1783 | if (be16_to_cpu(dead_info->magic) == XFS_DIR_LEAF_MAGIC) { | 1685 | if (be16_to_cpu(dead_info->magic) == XFS_DIR2_LEAFN_MAGIC) { |
| 1784 | ASSERT(XFS_DIR_IS_V1(mp)); | ||
| 1785 | dead_leaf = (xfs_dir_leafblock_t *)dead_info; | ||
| 1786 | dead_level = 0; | ||
| 1787 | dead_hash = | ||
| 1788 | INT_GET(dead_leaf->entries[INT_GET(dead_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); | ||
| 1789 | } else if (be16_to_cpu(dead_info->magic) == XFS_DIR2_LEAFN_MAGIC) { | ||
| 1790 | ASSERT(XFS_DIR_IS_V2(mp)); | ||
| 1791 | dead_leaf2 = (xfs_dir2_leaf_t *)dead_info; | 1686 | dead_leaf2 = (xfs_dir2_leaf_t *)dead_info; |
| 1792 | dead_level = 0; | 1687 | dead_level = 0; |
| 1793 | dead_hash = be32_to_cpu(dead_leaf2->ents[be16_to_cpu(dead_leaf2->hdr.count) - 1].hashval); | 1688 | dead_hash = be32_to_cpu(dead_leaf2->ents[be16_to_cpu(dead_leaf2->hdr.count) - 1].hashval); |
| @@ -1842,7 +1737,7 @@ xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop, | |||
| 1842 | xfs_da_buf_done(sib_buf); | 1737 | xfs_da_buf_done(sib_buf); |
| 1843 | sib_buf = NULL; | 1738 | sib_buf = NULL; |
| 1844 | } | 1739 | } |
| 1845 | par_blkno = XFS_DIR_IS_V1(mp) ? 0 : mp->m_dirleafblk; | 1740 | par_blkno = mp->m_dirleafblk; |
| 1846 | level = -1; | 1741 | level = -1; |
| 1847 | /* | 1742 | /* |
| 1848 | * Walk down the tree looking for the parent of the moved block. | 1743 | * Walk down the tree looking for the parent of the moved block. |
| @@ -1941,8 +1836,6 @@ xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, | |||
| 1941 | { | 1836 | { |
| 1942 | xfs_inode_t *dp; | 1837 | xfs_inode_t *dp; |
| 1943 | int done, error, w, count; | 1838 | int done, error, w, count; |
| 1944 | xfs_fileoff_t bno; | ||
| 1945 | xfs_fsize_t size; | ||
| 1946 | xfs_trans_t *tp; | 1839 | xfs_trans_t *tp; |
| 1947 | xfs_mount_t *mp; | 1840 | xfs_mount_t *mp; |
| 1948 | 1841 | ||
| @@ -1950,7 +1843,7 @@ xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, | |||
| 1950 | w = args->whichfork; | 1843 | w = args->whichfork; |
| 1951 | tp = args->trans; | 1844 | tp = args->trans; |
| 1952 | mp = dp->i_mount; | 1845 | mp = dp->i_mount; |
| 1953 | if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) | 1846 | if (w == XFS_DATA_FORK) |
| 1954 | count = mp->m_dirblkfsbs; | 1847 | count = mp->m_dirblkfsbs; |
| 1955 | else | 1848 | else |
| 1956 | count = 1; | 1849 | count = 1; |
| @@ -1961,34 +1854,17 @@ xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, | |||
| 1961 | */ | 1854 | */ |
| 1962 | if ((error = xfs_bunmapi(tp, dp, dead_blkno, count, | 1855 | if ((error = xfs_bunmapi(tp, dp, dead_blkno, count, |
| 1963 | XFS_BMAPI_AFLAG(w)|XFS_BMAPI_METADATA, | 1856 | XFS_BMAPI_AFLAG(w)|XFS_BMAPI_METADATA, |
| 1964 | 0, args->firstblock, args->flist, | 1857 | 0, args->firstblock, args->flist, NULL, |
| 1965 | &done)) == ENOSPC) { | 1858 | &done)) == ENOSPC) { |
| 1966 | if (w != XFS_DATA_FORK) | 1859 | if (w != XFS_DATA_FORK) |
| 1967 | goto done; | 1860 | break; |
| 1968 | if ((error = xfs_da_swap_lastblock(args, &dead_blkno, | 1861 | if ((error = xfs_da_swap_lastblock(args, &dead_blkno, |
| 1969 | &dead_buf))) | 1862 | &dead_buf))) |
| 1970 | goto done; | 1863 | break; |
| 1971 | } else if (error) | 1864 | } else { |
| 1972 | goto done; | ||
| 1973 | else | ||
| 1974 | break; | 1865 | break; |
| 1975 | } | ||
| 1976 | ASSERT(done); | ||
| 1977 | xfs_da_binval(tp, dead_buf); | ||
| 1978 | /* | ||
| 1979 | * Adjust the directory size for version 1. | ||
| 1980 | */ | ||
| 1981 | if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) { | ||
| 1982 | if ((error = xfs_bmap_last_offset(tp, dp, &bno, w))) | ||
| 1983 | return error; | ||
| 1984 | size = XFS_FSB_TO_B(dp->i_mount, bno); | ||
| 1985 | if (size != dp->i_d.di_size) { | ||
| 1986 | dp->i_d.di_size = size; | ||
| 1987 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | ||
| 1988 | } | 1866 | } |
| 1989 | } | 1867 | } |
| 1990 | return 0; | ||
| 1991 | done: | ||
| 1992 | xfs_da_binval(tp, dead_buf); | 1868 | xfs_da_binval(tp, dead_buf); |
| 1993 | return error; | 1869 | return error; |
| 1994 | } | 1870 | } |
| @@ -2049,10 +1925,7 @@ xfs_da_do_buf( | |||
| 2049 | xfs_dabuf_t *rbp; | 1925 | xfs_dabuf_t *rbp; |
| 2050 | 1926 | ||
| 2051 | mp = dp->i_mount; | 1927 | mp = dp->i_mount; |
| 2052 | if (whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) | 1928 | nfsb = (whichfork == XFS_DATA_FORK) ? mp->m_dirblkfsbs : 1; |
| 2053 | nfsb = mp->m_dirblkfsbs; | ||
| 2054 | else | ||
| 2055 | nfsb = 1; | ||
| 2056 | mappedbno = *mappedbnop; | 1929 | mappedbno = *mappedbnop; |
| 2057 | /* | 1930 | /* |
| 2058 | * Caller doesn't have a mapping. -2 means don't complain | 1931 | * Caller doesn't have a mapping. -2 means don't complain |
| @@ -2086,7 +1959,7 @@ xfs_da_do_buf( | |||
| 2086 | nfsb, | 1959 | nfsb, |
| 2087 | XFS_BMAPI_METADATA | | 1960 | XFS_BMAPI_METADATA | |
| 2088 | XFS_BMAPI_AFLAG(whichfork), | 1961 | XFS_BMAPI_AFLAG(whichfork), |
| 2089 | NULL, 0, mapp, &nmap, NULL))) | 1962 | NULL, 0, mapp, &nmap, NULL, NULL))) |
| 2090 | goto exit0; | 1963 | goto exit0; |
| 2091 | } | 1964 | } |
| 2092 | } else { | 1965 | } else { |
| @@ -2198,7 +2071,6 @@ xfs_da_do_buf( | |||
| 2198 | magic1 = be32_to_cpu(data->hdr.magic); | 2071 | magic1 = be32_to_cpu(data->hdr.magic); |
| 2199 | if (unlikely( | 2072 | if (unlikely( |
| 2200 | XFS_TEST_ERROR((magic != XFS_DA_NODE_MAGIC) && | 2073 | XFS_TEST_ERROR((magic != XFS_DA_NODE_MAGIC) && |
| 2201 | (magic != XFS_DIR_LEAF_MAGIC) && | ||
| 2202 | (magic != XFS_ATTR_LEAF_MAGIC) && | 2074 | (magic != XFS_ATTR_LEAF_MAGIC) && |
| 2203 | (magic != XFS_DIR2_LEAF1_MAGIC) && | 2075 | (magic != XFS_DIR2_LEAF1_MAGIC) && |
| 2204 | (magic != XFS_DIR2_LEAFN_MAGIC) && | 2076 | (magic != XFS_DIR2_LEAFN_MAGIC) && |
diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index 243a730d5ec8..4ab865ec8b82 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h | |||
| @@ -36,14 +36,10 @@ struct zone; | |||
| 36 | * level in the Btree, and to identify which type of block this is. | 36 | * level in the Btree, and to identify which type of block this is. |
| 37 | */ | 37 | */ |
| 38 | #define XFS_DA_NODE_MAGIC 0xfebe /* magic number: non-leaf blocks */ | 38 | #define XFS_DA_NODE_MAGIC 0xfebe /* magic number: non-leaf blocks */ |
| 39 | #define XFS_DIR_LEAF_MAGIC 0xfeeb /* magic number: directory leaf blks */ | ||
| 40 | #define XFS_ATTR_LEAF_MAGIC 0xfbee /* magic number: attribute leaf blks */ | 39 | #define XFS_ATTR_LEAF_MAGIC 0xfbee /* magic number: attribute leaf blks */ |
| 41 | #define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */ | 40 | #define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */ |
| 42 | #define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */ | 41 | #define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */ |
| 43 | 42 | ||
| 44 | #define XFS_DIRX_LEAF_MAGIC(mp) \ | ||
| 45 | (XFS_DIR_IS_V1(mp) ? XFS_DIR_LEAF_MAGIC : XFS_DIR2_LEAFN_MAGIC) | ||
| 46 | |||
| 47 | typedef struct xfs_da_blkinfo { | 43 | typedef struct xfs_da_blkinfo { |
| 48 | __be32 forw; /* previous block in list */ | 44 | __be32 forw; /* previous block in list */ |
| 49 | __be32 back; /* following block in list */ | 45 | __be32 back; /* following block in list */ |
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 4968a6358e61..80562b60fb95 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -54,24 +52,14 @@ xfs_swapext( | |||
| 54 | xfs_swapext_t __user *sxu) | 52 | xfs_swapext_t __user *sxu) |
| 55 | { | 53 | { |
| 56 | xfs_swapext_t *sxp; | 54 | xfs_swapext_t *sxp; |
| 57 | xfs_inode_t *ip=NULL, *tip=NULL, *ips[2]; | 55 | xfs_inode_t *ip=NULL, *tip=NULL; |
| 58 | xfs_trans_t *tp; | ||
| 59 | xfs_mount_t *mp; | 56 | xfs_mount_t *mp; |
| 60 | xfs_bstat_t *sbp; | ||
| 61 | struct file *fp = NULL, *tfp = NULL; | 57 | struct file *fp = NULL, *tfp = NULL; |
| 62 | vnode_t *vp, *tvp; | 58 | bhv_vnode_t *vp, *tvp; |
| 63 | static uint lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; | ||
| 64 | int ilf_fields, tilf_fields; | ||
| 65 | int error = 0; | 59 | int error = 0; |
| 66 | xfs_ifork_t *tempifp, *ifp, *tifp; | ||
| 67 | __uint64_t tmp; | ||
| 68 | int aforkblks = 0; | ||
| 69 | int taforkblks = 0; | ||
| 70 | char locked = 0; | ||
| 71 | 60 | ||
| 72 | sxp = kmem_alloc(sizeof(xfs_swapext_t), KM_MAYFAIL); | 61 | sxp = kmem_alloc(sizeof(xfs_swapext_t), KM_MAYFAIL); |
| 73 | tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); | 62 | if (!sxp) { |
| 74 | if (!sxp || !tempifp) { | ||
| 75 | error = XFS_ERROR(ENOMEM); | 63 | error = XFS_ERROR(ENOMEM); |
| 76 | goto error0; | 64 | goto error0; |
| 77 | } | 65 | } |
| @@ -118,14 +106,56 @@ xfs_swapext( | |||
| 118 | 106 | ||
| 119 | mp = ip->i_mount; | 107 | mp = ip->i_mount; |
| 120 | 108 | ||
| 121 | sbp = &sxp->sx_stat; | ||
| 122 | |||
| 123 | if (XFS_FORCED_SHUTDOWN(mp)) { | 109 | if (XFS_FORCED_SHUTDOWN(mp)) { |
| 124 | error = XFS_ERROR(EIO); | 110 | error = XFS_ERROR(EIO); |
| 125 | goto error0; | 111 | goto error0; |
| 126 | } | 112 | } |
| 127 | 113 | ||
| 128 | locked = 1; | 114 | error = XFS_SWAP_EXTENTS(mp, &ip->i_iocore, &tip->i_iocore, sxp); |
| 115 | |||
| 116 | error0: | ||
| 117 | if (fp != NULL) | ||
| 118 | fput(fp); | ||
| 119 | if (tfp != NULL) | ||
| 120 | fput(tfp); | ||
| 121 | |||
| 122 | if (sxp != NULL) | ||
| 123 | kmem_free(sxp, sizeof(xfs_swapext_t)); | ||
| 124 | |||
| 125 | return error; | ||
| 126 | } | ||
| 127 | |||
| 128 | int | ||
| 129 | xfs_swap_extents( | ||
| 130 | xfs_inode_t *ip, | ||
| 131 | xfs_inode_t *tip, | ||
| 132 | xfs_swapext_t *sxp) | ||
| 133 | { | ||
| 134 | xfs_mount_t *mp; | ||
| 135 | xfs_inode_t *ips[2]; | ||
| 136 | xfs_trans_t *tp; | ||
| 137 | xfs_bstat_t *sbp = &sxp->sx_stat; | ||
| 138 | bhv_vnode_t *vp, *tvp; | ||
| 139 | xfs_ifork_t *tempifp, *ifp, *tifp; | ||
| 140 | int ilf_fields, tilf_fields; | ||
| 141 | static uint lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; | ||
| 142 | int error = 0; | ||
| 143 | int aforkblks = 0; | ||
| 144 | int taforkblks = 0; | ||
| 145 | __uint64_t tmp; | ||
| 146 | char locked = 0; | ||
| 147 | |||
| 148 | mp = ip->i_mount; | ||
| 149 | |||
| 150 | tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); | ||
| 151 | if (!tempifp) { | ||
| 152 | error = XFS_ERROR(ENOMEM); | ||
| 153 | goto error0; | ||
| 154 | } | ||
| 155 | |||
| 156 | sbp = &sxp->sx_stat; | ||
| 157 | vp = XFS_ITOV(ip); | ||
| 158 | tvp = XFS_ITOV(tip); | ||
| 129 | 159 | ||
| 130 | /* Lock in i_ino order */ | 160 | /* Lock in i_ino order */ |
| 131 | if (ip->i_ino < tip->i_ino) { | 161 | if (ip->i_ino < tip->i_ino) { |
| @@ -137,6 +167,7 @@ xfs_swapext( | |||
| 137 | } | 167 | } |
| 138 | 168 | ||
| 139 | xfs_lock_inodes(ips, 2, 0, lock_flags); | 169 | xfs_lock_inodes(ips, 2, 0, lock_flags); |
| 170 | locked = 1; | ||
| 140 | 171 | ||
| 141 | /* Check permissions */ | 172 | /* Check permissions */ |
| 142 | error = xfs_iaccess(ip, S_IWUSR, NULL); | 173 | error = xfs_iaccess(ip, S_IWUSR, NULL); |
| @@ -169,7 +200,7 @@ xfs_swapext( | |||
| 169 | 200 | ||
| 170 | if (VN_CACHED(tvp) != 0) { | 201 | if (VN_CACHED(tvp) != 0) { |
| 171 | xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1); | 202 | xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1); |
| 172 | VOP_FLUSHINVAL_PAGES(tvp, 0, -1, FI_REMAPF_LOCKED); | 203 | bhv_vop_flushinval_pages(tvp, 0, -1, FI_REMAPF_LOCKED); |
| 173 | } | 204 | } |
| 174 | 205 | ||
| 175 | /* Verify O_DIRECT for ftmp */ | 206 | /* Verify O_DIRECT for ftmp */ |
| @@ -214,7 +245,7 @@ xfs_swapext( | |||
| 214 | /* We need to fail if the file is memory mapped. Once we have tossed | 245 | /* We need to fail if the file is memory mapped. Once we have tossed |
| 215 | * all existing pages, the page fault will have no option | 246 | * all existing pages, the page fault will have no option |
| 216 | * but to go to the filesystem for pages. By making the page fault call | 247 | * but to go to the filesystem for pages. By making the page fault call |
| 217 | * VOP_READ (or write in the case of autogrow) they block on the iolock | 248 | * vop_read (or write in the case of autogrow) they block on the iolock |
| 218 | * until we have switched the extents. | 249 | * until we have switched the extents. |
| 219 | */ | 250 | */ |
| 220 | if (VN_MAPPED(vp)) { | 251 | if (VN_MAPPED(vp)) { |
| @@ -233,7 +264,7 @@ xfs_swapext( | |||
| 233 | * fields change. | 264 | * fields change. |
| 234 | */ | 265 | */ |
| 235 | 266 | ||
| 236 | VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF); | 267 | bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF); |
| 237 | 268 | ||
| 238 | tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); | 269 | tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); |
| 239 | if ((error = xfs_trans_reserve(tp, 0, | 270 | if ((error = xfs_trans_reserve(tp, 0, |
| @@ -360,16 +391,7 @@ xfs_swapext( | |||
| 360 | xfs_iunlock(ip, lock_flags); | 391 | xfs_iunlock(ip, lock_flags); |
| 361 | xfs_iunlock(tip, lock_flags); | 392 | xfs_iunlock(tip, lock_flags); |
| 362 | } | 393 | } |
| 363 | |||
| 364 | if (fp != NULL) | ||
| 365 | fput(fp); | ||
| 366 | if (tfp != NULL) | ||
| 367 | fput(tfp); | ||
| 368 | |||
| 369 | if (sxp != NULL) | ||
| 370 | kmem_free(sxp, sizeof(xfs_swapext_t)); | ||
| 371 | if (tempifp != NULL) | 394 | if (tempifp != NULL) |
| 372 | kmem_free(tempifp, sizeof(xfs_ifork_t)); | 395 | kmem_free(tempifp, sizeof(xfs_ifork_t)); |
| 373 | |||
| 374 | return error; | 396 | return error; |
| 375 | } | 397 | } |
diff --git a/fs/xfs/xfs_dfrag.h b/fs/xfs/xfs_dfrag.h index f678559abc45..da178205be68 100644 --- a/fs/xfs/xfs_dfrag.h +++ b/fs/xfs/xfs_dfrag.h | |||
| @@ -48,6 +48,9 @@ typedef struct xfs_swapext | |||
| 48 | */ | 48 | */ |
| 49 | int xfs_swapext(struct xfs_swapext __user *sx); | 49 | int xfs_swapext(struct xfs_swapext __user *sx); |
| 50 | 50 | ||
| 51 | int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip, | ||
| 52 | struct xfs_swapext *sxp); | ||
| 53 | |||
| 51 | #endif /* __KERNEL__ */ | 54 | #endif /* __KERNEL__ */ |
| 52 | 55 | ||
| 53 | #endif /* __XFS_DFRAG_H__ */ | 56 | #endif /* __XFS_DFRAG_H__ */ |
diff --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h index 79d0d9e1fbab..b33826961c45 100644 --- a/fs/xfs/xfs_dinode.h +++ b/fs/xfs/xfs_dinode.h | |||
| @@ -85,7 +85,6 @@ typedef struct xfs_dinode | |||
| 85 | union { | 85 | union { |
| 86 | xfs_bmdr_block_t di_bmbt; /* btree root block */ | 86 | xfs_bmdr_block_t di_bmbt; /* btree root block */ |
| 87 | xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */ | 87 | xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */ |
| 88 | xfs_dir_shortform_t di_dirsf; /* shortform directory */ | ||
| 89 | xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */ | 88 | xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */ |
| 90 | char di_c[1]; /* local contents */ | 89 | char di_c[1]; /* local contents */ |
| 91 | xfs_dev_t di_dev; /* device for S_IFCHR/S_IFBLK */ | 90 | xfs_dev_t di_dev; /* device for S_IFCHR/S_IFBLK */ |
| @@ -257,6 +256,7 @@ typedef enum xfs_dinode_fmt | |||
| 257 | #define XFS_DIFLAG_NOSYMLINKS_BIT 10 /* disallow symlink creation */ | 256 | #define XFS_DIFLAG_NOSYMLINKS_BIT 10 /* disallow symlink creation */ |
| 258 | #define XFS_DIFLAG_EXTSIZE_BIT 11 /* inode extent size allocator hint */ | 257 | #define XFS_DIFLAG_EXTSIZE_BIT 11 /* inode extent size allocator hint */ |
| 259 | #define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */ | 258 | #define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */ |
| 259 | #define XFS_DIFLAG_NODEFRAG_BIT 13 /* do not reorganize/defragment */ | ||
| 260 | #define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) | 260 | #define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) |
| 261 | #define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) | 261 | #define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) |
| 262 | #define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) | 262 | #define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) |
| @@ -270,12 +270,13 @@ typedef enum xfs_dinode_fmt | |||
| 270 | #define XFS_DIFLAG_NOSYMLINKS (1 << XFS_DIFLAG_NOSYMLINKS_BIT) | 270 | #define XFS_DIFLAG_NOSYMLINKS (1 << XFS_DIFLAG_NOSYMLINKS_BIT) |
| 271 | #define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT) | 271 | #define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT) |
| 272 | #define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT) | 272 | #define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT) |
| 273 | #define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT) | ||
| 273 | 274 | ||
| 274 | #define XFS_DIFLAG_ANY \ | 275 | #define XFS_DIFLAG_ANY \ |
| 275 | (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \ | 276 | (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \ |
| 276 | XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ | 277 | XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ |
| 277 | XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \ | 278 | XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \ |
| 278 | XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \ | 279 | XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \ |
| 279 | XFS_DIFLAG_EXTSZINHERIT) | 280 | XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG) |
| 280 | 281 | ||
| 281 | #endif /* __XFS_DINODE_H__ */ | 282 | #endif /* __XFS_DINODE_H__ */ |
diff --git a/fs/xfs/xfs_dir.c b/fs/xfs/xfs_dir.c deleted file mode 100644 index 9cc702a839a3..000000000000 --- a/fs/xfs/xfs_dir.c +++ /dev/null | |||
| @@ -1,1217 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it would be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write the Free Software Foundation, | ||
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | #include "xfs.h" | ||
| 19 | #include "xfs_fs.h" | ||
| 20 | #include "xfs_types.h" | ||
| 21 | #include "xfs_log.h" | ||
| 22 | #include "xfs_inum.h" | ||
| 23 | #include "xfs_trans.h" | ||
| 24 | #include "xfs_sb.h" | ||
| 25 | #include "xfs_dir.h" | ||
| 26 | #include "xfs_dir2.h" | ||
| 27 | #include "xfs_dmapi.h" | ||
| 28 | #include "xfs_mount.h" | ||
| 29 | #include "xfs_da_btree.h" | ||
| 30 | #include "xfs_bmap_btree.h" | ||
| 31 | #include "xfs_alloc_btree.h" | ||
| 32 | #include "xfs_ialloc_btree.h" | ||
| 33 | #include "xfs_alloc.h" | ||
| 34 | #include "xfs_btree.h" | ||
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | ||
| 37 | #include "xfs_attr_sf.h" | ||
| 38 | #include "xfs_dinode.h" | ||
| 39 | #include "xfs_inode.h" | ||
| 40 | #include "xfs_bmap.h" | ||
| 41 | #include "xfs_dir_leaf.h" | ||
| 42 | #include "xfs_error.h" | ||
| 43 | |||
| 44 | /* | ||
| 45 | * xfs_dir.c | ||
| 46 | * | ||
| 47 | * Provide the external interfaces to manage directories. | ||
| 48 | */ | ||
| 49 | |||
| 50 | /*======================================================================== | ||
| 51 | * Function prototypes for the kernel. | ||
| 52 | *========================================================================*/ | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Functions for the dirops interfaces. | ||
| 56 | */ | ||
| 57 | static void xfs_dir_mount(struct xfs_mount *mp); | ||
| 58 | |||
| 59 | static int xfs_dir_isempty(struct xfs_inode *dp); | ||
| 60 | |||
| 61 | static int xfs_dir_init(struct xfs_trans *trans, | ||
| 62 | struct xfs_inode *dir, | ||
| 63 | struct xfs_inode *parent_dir); | ||
| 64 | |||
| 65 | static int xfs_dir_createname(struct xfs_trans *trans, | ||
| 66 | struct xfs_inode *dp, | ||
| 67 | char *name_string, | ||
| 68 | int name_len, | ||
| 69 | xfs_ino_t inode_number, | ||
| 70 | xfs_fsblock_t *firstblock, | ||
| 71 | xfs_bmap_free_t *flist, | ||
| 72 | xfs_extlen_t total); | ||
| 73 | |||
| 74 | static int xfs_dir_lookup(struct xfs_trans *tp, | ||
| 75 | struct xfs_inode *dp, | ||
| 76 | char *name_string, | ||
| 77 | int name_length, | ||
| 78 | xfs_ino_t *inode_number); | ||
| 79 | |||
| 80 | static int xfs_dir_removename(struct xfs_trans *trans, | ||
| 81 | struct xfs_inode *dp, | ||
| 82 | char *name_string, | ||
| 83 | int name_length, | ||
| 84 | xfs_ino_t ino, | ||
| 85 | xfs_fsblock_t *firstblock, | ||
| 86 | xfs_bmap_free_t *flist, | ||
| 87 | xfs_extlen_t total); | ||
| 88 | |||
| 89 | static int xfs_dir_getdents(struct xfs_trans *tp, | ||
| 90 | struct xfs_inode *dp, | ||
| 91 | struct uio *uiop, | ||
| 92 | int *eofp); | ||
| 93 | |||
| 94 | static int xfs_dir_replace(struct xfs_trans *tp, | ||
| 95 | struct xfs_inode *dp, | ||
| 96 | char *name_string, | ||
| 97 | int name_length, | ||
| 98 | xfs_ino_t inode_number, | ||
| 99 | xfs_fsblock_t *firstblock, | ||
| 100 | xfs_bmap_free_t *flist, | ||
| 101 | xfs_extlen_t total); | ||
| 102 | |||
| 103 | static int xfs_dir_canenter(struct xfs_trans *tp, | ||
| 104 | struct xfs_inode *dp, | ||
| 105 | char *name_string, | ||
| 106 | int name_length); | ||
| 107 | |||
| 108 | static int xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, | ||
| 109 | xfs_dinode_t *dip); | ||
| 110 | |||
| 111 | xfs_dirops_t xfsv1_dirops = { | ||
| 112 | .xd_mount = xfs_dir_mount, | ||
| 113 | .xd_isempty = xfs_dir_isempty, | ||
| 114 | .xd_init = xfs_dir_init, | ||
| 115 | .xd_createname = xfs_dir_createname, | ||
| 116 | .xd_lookup = xfs_dir_lookup, | ||
| 117 | .xd_removename = xfs_dir_removename, | ||
| 118 | .xd_getdents = xfs_dir_getdents, | ||
| 119 | .xd_replace = xfs_dir_replace, | ||
| 120 | .xd_canenter = xfs_dir_canenter, | ||
| 121 | .xd_shortform_validate_ondisk = xfs_dir_shortform_validate_ondisk, | ||
| 122 | .xd_shortform_to_single = xfs_dir_shortform_to_leaf, | ||
| 123 | }; | ||
| 124 | |||
| 125 | /* | ||
| 126 | * Internal routines when dirsize == XFS_LBSIZE(mp). | ||
| 127 | */ | ||
| 128 | STATIC int xfs_dir_leaf_lookup(xfs_da_args_t *args); | ||
| 129 | STATIC int xfs_dir_leaf_removename(xfs_da_args_t *args, int *number_entries, | ||
| 130 | int *total_namebytes); | ||
| 131 | STATIC int xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, | ||
| 132 | uio_t *uio, int *eofp, | ||
| 133 | xfs_dirent_t *dbp, | ||
| 134 | xfs_dir_put_t put); | ||
| 135 | STATIC int xfs_dir_leaf_replace(xfs_da_args_t *args); | ||
| 136 | |||
| 137 | /* | ||
| 138 | * Internal routines when dirsize > XFS_LBSIZE(mp). | ||
| 139 | */ | ||
| 140 | STATIC int xfs_dir_node_addname(xfs_da_args_t *args); | ||
| 141 | STATIC int xfs_dir_node_lookup(xfs_da_args_t *args); | ||
| 142 | STATIC int xfs_dir_node_removename(xfs_da_args_t *args); | ||
| 143 | STATIC int xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp, | ||
| 144 | uio_t *uio, int *eofp, | ||
| 145 | xfs_dirent_t *dbp, | ||
| 146 | xfs_dir_put_t put); | ||
| 147 | STATIC int xfs_dir_node_replace(xfs_da_args_t *args); | ||
| 148 | |||
| 149 | #if defined(XFS_DIR_TRACE) | ||
| 150 | ktrace_t *xfs_dir_trace_buf; | ||
| 151 | #endif | ||
| 152 | |||
| 153 | |||
| 154 | /*======================================================================== | ||
| 155 | * Overall external interface routines. | ||
| 156 | *========================================================================*/ | ||
| 157 | |||
| 158 | xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; | ||
| 159 | |||
| 160 | /* | ||
| 161 | * One-time startup routine called from xfs_init(). | ||
| 162 | */ | ||
| 163 | void | ||
| 164 | xfs_dir_startup(void) | ||
| 165 | { | ||
| 166 | xfs_dir_hash_dot = xfs_da_hashname(".", 1); | ||
| 167 | xfs_dir_hash_dotdot = xfs_da_hashname("..", 2); | ||
| 168 | } | ||
| 169 | |||
| 170 | /* | ||
| 171 | * Initialize directory-related fields in the mount structure. | ||
| 172 | */ | ||
| 173 | static void | ||
| 174 | xfs_dir_mount(xfs_mount_t *mp) | ||
| 175 | { | ||
| 176 | uint shortcount, leafcount, count; | ||
| 177 | |||
| 178 | mp->m_dirversion = 1; | ||
| 179 | if (!(mp->m_flags & XFS_MOUNT_ATTR2)) { | ||
| 180 | shortcount = (mp->m_attroffset - | ||
| 181 | (uint)sizeof(xfs_dir_sf_hdr_t)) / | ||
| 182 | (uint)sizeof(xfs_dir_sf_entry_t); | ||
| 183 | leafcount = (XFS_LBSIZE(mp) - | ||
| 184 | (uint)sizeof(xfs_dir_leaf_hdr_t)) / | ||
| 185 | ((uint)sizeof(xfs_dir_leaf_entry_t) + | ||
| 186 | (uint)sizeof(xfs_dir_leaf_name_t)); | ||
| 187 | } else { | ||
| 188 | shortcount = (XFS_BMDR_SPACE_CALC(MINABTPTRS) - | ||
| 189 | (uint)sizeof(xfs_dir_sf_hdr_t)) / | ||
| 190 | (uint)sizeof(xfs_dir_sf_entry_t); | ||
| 191 | leafcount = (XFS_LBSIZE(mp) - | ||
| 192 | (uint)sizeof(xfs_dir_leaf_hdr_t)) / | ||
| 193 | ((uint)sizeof(xfs_dir_leaf_entry_t) + | ||
| 194 | (uint)sizeof(xfs_dir_leaf_name_t)); | ||
| 195 | } | ||
| 196 | count = shortcount > leafcount ? shortcount : leafcount; | ||
| 197 | mp->m_dircook_elog = xfs_da_log2_roundup(count + 1); | ||
| 198 | ASSERT(mp->m_dircook_elog <= mp->m_sb.sb_blocklog); | ||
| 199 | mp->m_dir_node_ents = mp->m_attr_node_ents = | ||
| 200 | (XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) / | ||
| 201 | (uint)sizeof(xfs_da_node_entry_t); | ||
| 202 | mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100; | ||
| 203 | mp->m_dirblksize = mp->m_sb.sb_blocksize; | ||
| 204 | mp->m_dirblkfsbs = 1; | ||
| 205 | } | ||
| 206 | |||
| 207 | /* | ||
| 208 | * Return 1 if directory contains only "." and "..". | ||
| 209 | */ | ||
| 210 | static int | ||
| 211 | xfs_dir_isempty(xfs_inode_t *dp) | ||
| 212 | { | ||
| 213 | xfs_dir_sf_hdr_t *hdr; | ||
| 214 | |||
| 215 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | ||
| 216 | if (dp->i_d.di_size == 0) | ||
| 217 | return(1); | ||
| 218 | if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) | ||
| 219 | return(0); | ||
| 220 | hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data; | ||
| 221 | return(hdr->count == 0); | ||
| 222 | } | ||
| 223 | |||
| 224 | /* | ||
| 225 | * Initialize a directory with its "." and ".." entries. | ||
| 226 | */ | ||
| 227 | static int | ||
| 228 | xfs_dir_init(xfs_trans_t *trans, xfs_inode_t *dir, xfs_inode_t *parent_dir) | ||
| 229 | { | ||
| 230 | xfs_da_args_t args; | ||
| 231 | int error; | ||
| 232 | |||
| 233 | memset((char *)&args, 0, sizeof(args)); | ||
| 234 | args.dp = dir; | ||
| 235 | args.trans = trans; | ||
| 236 | |||
| 237 | ASSERT((dir->i_d.di_mode & S_IFMT) == S_IFDIR); | ||
| 238 | if ((error = xfs_dir_ino_validate(trans->t_mountp, parent_dir->i_ino))) | ||
| 239 | return error; | ||
| 240 | |||
| 241 | return(xfs_dir_shortform_create(&args, parent_dir->i_ino)); | ||
| 242 | } | ||
| 243 | |||
| 244 | /* | ||
| 245 | * Generic handler routine to add a name to a directory. | ||
| 246 | * Transitions directory from shortform to Btree as necessary. | ||
| 247 | */ | ||
| 248 | static int /* error */ | ||
| 249 | xfs_dir_createname(xfs_trans_t *trans, xfs_inode_t *dp, char *name, | ||
| 250 | int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock, | ||
| 251 | xfs_bmap_free_t *flist, xfs_extlen_t total) | ||
| 252 | { | ||
| 253 | xfs_da_args_t args; | ||
| 254 | int retval, newsize, done; | ||
| 255 | |||
| 256 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | ||
| 257 | |||
| 258 | if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) | ||
| 259 | return (retval); | ||
| 260 | |||
| 261 | XFS_STATS_INC(xs_dir_create); | ||
| 262 | /* | ||
| 263 | * Fill in the arg structure for this request. | ||
| 264 | */ | ||
| 265 | args.name = name; | ||
| 266 | args.namelen = namelen; | ||
| 267 | args.hashval = xfs_da_hashname(name, namelen); | ||
| 268 | args.inumber = inum; | ||
| 269 | args.dp = dp; | ||
| 270 | args.firstblock = firstblock; | ||
| 271 | args.flist = flist; | ||
| 272 | args.total = total; | ||
| 273 | args.whichfork = XFS_DATA_FORK; | ||
| 274 | args.trans = trans; | ||
| 275 | args.justcheck = 0; | ||
| 276 | args.addname = args.oknoent = 1; | ||
| 277 | |||
| 278 | /* | ||
| 279 | * Decide on what work routines to call based on the inode size. | ||
| 280 | */ | ||
| 281 | done = 0; | ||
| 282 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | ||
| 283 | newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen); | ||
| 284 | if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) { | ||
| 285 | retval = xfs_dir_shortform_addname(&args); | ||
| 286 | done = 1; | ||
| 287 | } else { | ||
| 288 | if (total == 0) | ||
| 289 | return XFS_ERROR(ENOSPC); | ||
| 290 | retval = xfs_dir_shortform_to_leaf(&args); | ||
| 291 | done = retval != 0; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | if (!done && xfs_bmap_one_block(dp, XFS_DATA_FORK)) { | ||
| 295 | retval = xfs_dir_leaf_addname(&args); | ||
| 296 | done = retval != ENOSPC; | ||
| 297 | if (!done) { | ||
| 298 | if (total == 0) | ||
| 299 | return XFS_ERROR(ENOSPC); | ||
| 300 | retval = xfs_dir_leaf_to_node(&args); | ||
| 301 | done = retval != 0; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | if (!done) { | ||
| 305 | retval = xfs_dir_node_addname(&args); | ||
| 306 | } | ||
| 307 | return(retval); | ||
| 308 | } | ||
| 309 | |||
| 310 | /* | ||
| 311 | * Generic handler routine to check if a name can be added to a directory, | ||
| 312 | * without adding any blocks to the directory. | ||
| 313 | */ | ||
| 314 | static int /* error */ | ||
| 315 | xfs_dir_canenter(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen) | ||
| 316 | { | ||
| 317 | xfs_da_args_t args; | ||
| 318 | int retval, newsize; | ||
| 319 | |||
| 320 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | ||
| 321 | /* | ||
| 322 | * Fill in the arg structure for this request. | ||
| 323 | */ | ||
| 324 | args.name = name; | ||
| 325 | args.namelen = namelen; | ||
| 326 | args.hashval = xfs_da_hashname(name, namelen); | ||
| 327 | args.inumber = 0; | ||
| 328 | args.dp = dp; | ||
| 329 | args.firstblock = NULL; | ||
| 330 | args.flist = NULL; | ||
| 331 | args.total = 0; | ||
| 332 | args.whichfork = XFS_DATA_FORK; | ||
| 333 | args.trans = trans; | ||
| 334 | args.justcheck = args.addname = args.oknoent = 1; | ||
| 335 | |||
| 336 | /* | ||
| 337 | * Decide on what work routines to call based on the inode size. | ||
| 338 | */ | ||
| 339 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | ||
| 340 | newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen); | ||
| 341 | if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) | ||
| 342 | retval = 0; | ||
| 343 | else | ||
| 344 | retval = XFS_ERROR(ENOSPC); | ||
| 345 | } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { | ||
| 346 | retval = xfs_dir_leaf_addname(&args); | ||
| 347 | } else { | ||
| 348 | retval = xfs_dir_node_addname(&args); | ||
| 349 | } | ||
| 350 | return(retval); | ||
| 351 | } | ||
| 352 | |||
| 353 | /* | ||
| 354 | * Generic handler routine to remove a name from a directory. | ||
| 355 | * Transitions directory from Btree to shortform as necessary. | ||
| 356 | */ | ||
| 357 | static int /* error */ | ||
| 358 | xfs_dir_removename(xfs_trans_t *trans, xfs_inode_t *dp, char *name, | ||
| 359 | int namelen, xfs_ino_t ino, xfs_fsblock_t *firstblock, | ||
| 360 | xfs_bmap_free_t *flist, xfs_extlen_t total) | ||
| 361 | { | ||
| 362 | xfs_da_args_t args; | ||
| 363 | int count, totallen, newsize, retval; | ||
| 364 | |||
| 365 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | ||
| 366 | XFS_STATS_INC(xs_dir_remove); | ||
| 367 | /* | ||
| 368 | * Fill in the arg structure for this request. | ||
| 369 | */ | ||
| 370 | args.name = name; | ||
| 371 | args.namelen = namelen; | ||
| 372 | args.hashval = xfs_da_hashname(name, namelen); | ||
| 373 | args.inumber = ino; | ||
| 374 | args.dp = dp; | ||
| 375 | args.firstblock = firstblock; | ||
| 376 | args.flist = flist; | ||
| 377 | args.total = total; | ||
| 378 | args.whichfork = XFS_DATA_FORK; | ||
| 379 | args.trans = trans; | ||
| 380 | args.justcheck = args.addname = args.oknoent = 0; | ||
| 381 | |||
| 382 | /* | ||
| 383 | * Decide on what work routines to call based on the inode size. | ||
| 384 | */ | ||
| 385 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | ||
| 386 | retval = xfs_dir_shortform_removename(&args); | ||
| 387 | } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { | ||
| 388 | retval = xfs_dir_leaf_removename(&args, &count, &totallen); | ||
| 389 | if (retval == 0) { | ||
| 390 | newsize = XFS_DIR_SF_ALLFIT(count, totallen); | ||
| 391 | if (newsize <= XFS_IFORK_DSIZE(dp)) { | ||
| 392 | retval = xfs_dir_leaf_to_shortform(&args); | ||
| 393 | } | ||
| 394 | } | ||
| 395 | } else { | ||
| 396 | retval = xfs_dir_node_removename(&args); | ||
| 397 | } | ||
| 398 | return(retval); | ||
| 399 | } | ||
| 400 | |||
| 401 | static int /* error */ | ||
| 402 | xfs_dir_lookup(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, | ||
| 403 | xfs_ino_t *inum) | ||
| 404 | { | ||
| 405 | xfs_da_args_t args; | ||
| 406 | int retval; | ||
| 407 | |||
| 408 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | ||
| 409 | |||
| 410 | XFS_STATS_INC(xs_dir_lookup); | ||
| 411 | /* | ||
| 412 | * Fill in the arg structure for this request. | ||
| 413 | */ | ||
| 414 | args.name = name; | ||
| 415 | args.namelen = namelen; | ||
| 416 | args.hashval = xfs_da_hashname(name, namelen); | ||
| 417 | args.inumber = 0; | ||
| 418 | args.dp = dp; | ||
| 419 | args.firstblock = NULL; | ||
| 420 | args.flist = NULL; | ||
| 421 | args.total = 0; | ||
| 422 | args.whichfork = XFS_DATA_FORK; | ||
| 423 | args.trans = trans; | ||
| 424 | args.justcheck = args.addname = 0; | ||
| 425 | args.oknoent = 1; | ||
| 426 | |||
| 427 | /* | ||
| 428 | * Decide on what work routines to call based on the inode size. | ||
| 429 | */ | ||
| 430 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | ||
| 431 | retval = xfs_dir_shortform_lookup(&args); | ||
| 432 | } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { | ||
| 433 | retval = xfs_dir_leaf_lookup(&args); | ||
| 434 | } else { | ||
| 435 | retval = xfs_dir_node_lookup(&args); | ||
| 436 | } | ||
| 437 | if (retval == EEXIST) | ||
| 438 | retval = 0; | ||
| 439 | *inum = args.inumber; | ||
| 440 | return(retval); | ||
| 441 | } | ||
| 442 | |||
| 443 | /* | ||
| 444 | * Implement readdir. | ||
| 445 | */ | ||
| 446 | static int /* error */ | ||
| 447 | xfs_dir_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, int *eofp) | ||
| 448 | { | ||
| 449 | xfs_dirent_t *dbp; | ||
| 450 | int alignment, retval; | ||
| 451 | xfs_dir_put_t put; | ||
| 452 | |||
| 453 | XFS_STATS_INC(xs_dir_getdents); | ||
| 454 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | ||
| 455 | |||
| 456 | /* | ||
| 457 | * If our caller has given us a single contiguous memory buffer, | ||
| 458 | * just work directly within that buffer. If it's in user memory, | ||
| 459 | * lock it down first. | ||
| 460 | */ | ||
| 461 | alignment = sizeof(xfs_off_t) - 1; | ||
| 462 | if ((uio->uio_iovcnt == 1) && | ||
| 463 | (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) && | ||
| 464 | ((uio->uio_iov[0].iov_len & alignment) == 0)) { | ||
| 465 | dbp = NULL; | ||
| 466 | put = xfs_dir_put_dirent64_direct; | ||
| 467 | } else { | ||
| 468 | dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP); | ||
| 469 | put = xfs_dir_put_dirent64_uio; | ||
| 470 | } | ||
| 471 | |||
| 472 | /* | ||
| 473 | * Decide on what work routines to call based on the inode size. | ||
| 474 | */ | ||
| 475 | *eofp = 0; | ||
| 476 | |||
| 477 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | ||
| 478 | retval = xfs_dir_shortform_getdents(dp, uio, eofp, dbp, put); | ||
| 479 | } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { | ||
| 480 | retval = xfs_dir_leaf_getdents(trans, dp, uio, eofp, dbp, put); | ||
| 481 | } else { | ||
| 482 | retval = xfs_dir_node_getdents(trans, dp, uio, eofp, dbp, put); | ||
| 483 | } | ||
| 484 | if (dbp != NULL) | ||
| 485 | kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN); | ||
| 486 | |||
| 487 | return(retval); | ||
| 488 | } | ||
| 489 | |||
| 490 | static int /* error */ | ||
| 491 | xfs_dir_replace(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, | ||
| 492 | xfs_ino_t inum, xfs_fsblock_t *firstblock, | ||
| 493 | xfs_bmap_free_t *flist, xfs_extlen_t total) | ||
| 494 | { | ||
| 495 | xfs_da_args_t args; | ||
| 496 | int retval; | ||
| 497 | |||
| 498 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | ||
| 499 | |||
| 500 | if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) | ||
| 501 | return retval; | ||
| 502 | |||
| 503 | /* | ||
| 504 | * Fill in the arg structure for this request. | ||
| 505 | */ | ||
| 506 | args.name = name; | ||
| 507 | args.namelen = namelen; | ||
| 508 | args.hashval = xfs_da_hashname(name, namelen); | ||
| 509 | args.inumber = inum; | ||
| 510 | args.dp = dp; | ||
| 511 | args.firstblock = firstblock; | ||
| 512 | args.flist = flist; | ||
| 513 | args.total = total; | ||
| 514 | args.whichfork = XFS_DATA_FORK; | ||
| 515 | args.trans = trans; | ||
| 516 | args.justcheck = args.addname = args.oknoent = 0; | ||
| 517 | |||
| 518 | /* | ||
| 519 | * Decide on what work routines to call based on the inode size. | ||
| 520 | */ | ||
| 521 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { | ||
| 522 | retval = xfs_dir_shortform_replace(&args); | ||
| 523 | } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { | ||
| 524 | retval = xfs_dir_leaf_replace(&args); | ||
| 525 | } else { | ||
| 526 | retval = xfs_dir_node_replace(&args); | ||
| 527 | } | ||
| 528 | |||
| 529 | return(retval); | ||
| 530 | } | ||
| 531 | |||
| 532 | static int | ||
| 533 | xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp) | ||
| 534 | { | ||
| 535 | xfs_ino_t ino; | ||
| 536 | int namelen_sum; | ||
| 537 | int count; | ||
| 538 | xfs_dir_shortform_t *sf; | ||
| 539 | xfs_dir_sf_entry_t *sfe; | ||
| 540 | int i; | ||
| 541 | |||
| 542 | |||
| 543 | |||
| 544 | if ((INT_GET(dp->di_core.di_mode, ARCH_CONVERT) & S_IFMT) != S_IFDIR) { | ||
| 545 | return 0; | ||
| 546 | } | ||
| 547 | if (INT_GET(dp->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_LOCAL) { | ||
| 548 | return 0; | ||
| 549 | } | ||
| 550 | if (INT_GET(dp->di_core.di_size, ARCH_CONVERT) < sizeof(sf->hdr)) { | ||
| 551 | xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p", | ||
| 552 | dp); | ||
| 553 | return 1; | ||
| 554 | } | ||
| 555 | sf = (xfs_dir_shortform_t *)(&dp->di_u.di_dirsf); | ||
| 556 | ino = XFS_GET_DIR_INO8(sf->hdr.parent); | ||
| 557 | if (xfs_dir_ino_validate(mp, ino)) | ||
| 558 | return 1; | ||
| 559 | |||
| 560 | count = sf->hdr.count; | ||
| 561 | if ((count < 0) || ((count * 10) > XFS_LITINO(mp))) { | ||
| 562 | xfs_fs_cmn_err(CE_WARN, mp, | ||
| 563 | "Invalid shortform count: dp 0x%p", dp); | ||
| 564 | return(1); | ||
| 565 | } | ||
| 566 | |||
| 567 | if (count == 0) { | ||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | namelen_sum = 0; | ||
| 572 | sfe = &sf->list[0]; | ||
| 573 | for (i = sf->hdr.count - 1; i >= 0; i--) { | ||
| 574 | ino = XFS_GET_DIR_INO8(sfe->inumber); | ||
| 575 | xfs_dir_ino_validate(mp, ino); | ||
| 576 | if (sfe->namelen >= XFS_LITINO(mp)) { | ||
| 577 | xfs_fs_cmn_err(CE_WARN, mp, | ||
| 578 | "Invalid shortform namelen: dp 0x%p", dp); | ||
| 579 | return 1; | ||
| 580 | } | ||
| 581 | namelen_sum += sfe->namelen; | ||
| 582 | sfe = XFS_DIR_SF_NEXTENTRY(sfe); | ||
| 583 | } | ||
| 584 | if (namelen_sum >= XFS_LITINO(mp)) { | ||
| 585 | xfs_fs_cmn_err(CE_WARN, mp, | ||
| 586 | "Invalid shortform namelen: dp 0x%p", dp); | ||
| 587 | return 1; | ||
| 588 | } | ||
| 589 | |||
| 590 | return 0; | ||
| 591 | } | ||
| 592 | |||
| 593 | /*======================================================================== | ||
| 594 | * External routines when dirsize == XFS_LBSIZE(dp->i_mount). | ||
| 595 | *========================================================================*/ | ||
| 596 | |||
| 597 | /* | ||
| 598 | * Add a name to the leaf directory structure | ||
| 599 | * This is the external routine. | ||
| 600 | */ | ||
| 601 | int | ||
| 602 | xfs_dir_leaf_addname(xfs_da_args_t *args) | ||
| 603 | { | ||
| 604 | int index, retval; | ||
| 605 | xfs_dabuf_t *bp; | ||
| 606 | |||
| 607 | retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, | ||
| 608 | XFS_DATA_FORK); | ||
| 609 | if (retval) | ||
| 610 | return(retval); | ||
| 611 | ASSERT(bp != NULL); | ||
| 612 | |||
| 613 | retval = xfs_dir_leaf_lookup_int(bp, args, &index); | ||
| 614 | if (retval == ENOENT) | ||
| 615 | retval = xfs_dir_leaf_add(bp, args, index); | ||
| 616 | xfs_da_buf_done(bp); | ||
| 617 | return(retval); | ||
| 618 | } | ||
| 619 | |||
| 620 | /* | ||
| 621 | * Remove a name from the leaf directory structure | ||
| 622 | * This is the external routine. | ||
| 623 | */ | ||
| 624 | STATIC int | ||
| 625 | xfs_dir_leaf_removename(xfs_da_args_t *args, int *count, int *totallen) | ||
| 626 | { | ||
| 627 | xfs_dir_leafblock_t *leaf; | ||
| 628 | int index, retval; | ||
| 629 | xfs_dabuf_t *bp; | ||
| 630 | |||
| 631 | retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, | ||
| 632 | XFS_DATA_FORK); | ||
| 633 | if (retval) | ||
| 634 | return(retval); | ||
| 635 | ASSERT(bp != NULL); | ||
| 636 | leaf = bp->data; | ||
| 637 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 638 | retval = xfs_dir_leaf_lookup_int(bp, args, &index); | ||
| 639 | if (retval == EEXIST) { | ||
| 640 | (void)xfs_dir_leaf_remove(args->trans, bp, index); | ||
| 641 | *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); | ||
| 642 | *totallen = INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); | ||
| 643 | retval = 0; | ||
| 644 | } | ||
| 645 | xfs_da_buf_done(bp); | ||
| 646 | return(retval); | ||
| 647 | } | ||
| 648 | |||
| 649 | /* | ||
| 650 | * Look up a name in a leaf directory structure. | ||
| 651 | * This is the external routine. | ||
| 652 | */ | ||
| 653 | STATIC int | ||
| 654 | xfs_dir_leaf_lookup(xfs_da_args_t *args) | ||
| 655 | { | ||
| 656 | int index, retval; | ||
| 657 | xfs_dabuf_t *bp; | ||
| 658 | |||
| 659 | retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, | ||
| 660 | XFS_DATA_FORK); | ||
| 661 | if (retval) | ||
| 662 | return(retval); | ||
| 663 | ASSERT(bp != NULL); | ||
| 664 | retval = xfs_dir_leaf_lookup_int(bp, args, &index); | ||
| 665 | xfs_da_brelse(args->trans, bp); | ||
| 666 | return(retval); | ||
| 667 | } | ||
| 668 | |||
| 669 | /* | ||
| 670 | * Copy out directory entries for getdents(), for leaf directories. | ||
| 671 | */ | ||
| 672 | STATIC int | ||
| 673 | xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, | ||
| 674 | int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put) | ||
| 675 | { | ||
| 676 | xfs_dabuf_t *bp; | ||
| 677 | int retval, eob; | ||
| 678 | |||
| 679 | retval = xfs_da_read_buf(dp->i_transp, dp, 0, -1, &bp, XFS_DATA_FORK); | ||
| 680 | if (retval) | ||
| 681 | return(retval); | ||
| 682 | ASSERT(bp != NULL); | ||
| 683 | retval = xfs_dir_leaf_getdents_int(bp, dp, 0, uio, &eob, dbp, put, -1); | ||
| 684 | xfs_da_brelse(trans, bp); | ||
| 685 | *eofp = (eob == 0); | ||
| 686 | return(retval); | ||
| 687 | } | ||
| 688 | |||
| 689 | /* | ||
| 690 | * Look up a name in a leaf directory structure, replace the inode number. | ||
| 691 | * This is the external routine. | ||
| 692 | */ | ||
| 693 | STATIC int | ||
| 694 | xfs_dir_leaf_replace(xfs_da_args_t *args) | ||
| 695 | { | ||
| 696 | int index, retval; | ||
| 697 | xfs_dabuf_t *bp; | ||
| 698 | xfs_ino_t inum; | ||
| 699 | xfs_dir_leafblock_t *leaf; | ||
| 700 | xfs_dir_leaf_entry_t *entry; | ||
| 701 | xfs_dir_leaf_name_t *namest; | ||
| 702 | |||
| 703 | inum = args->inumber; | ||
| 704 | retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, | ||
| 705 | XFS_DATA_FORK); | ||
| 706 | if (retval) | ||
| 707 | return(retval); | ||
| 708 | ASSERT(bp != NULL); | ||
| 709 | retval = xfs_dir_leaf_lookup_int(bp, args, &index); | ||
| 710 | if (retval == EEXIST) { | ||
| 711 | leaf = bp->data; | ||
| 712 | entry = &leaf->entries[index]; | ||
| 713 | namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); | ||
| 714 | /* XXX - replace assert? */ | ||
| 715 | XFS_DIR_SF_PUT_DIRINO(&inum, &namest->inumber); | ||
| 716 | xfs_da_log_buf(args->trans, bp, | ||
| 717 | XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); | ||
| 718 | xfs_da_buf_done(bp); | ||
| 719 | retval = 0; | ||
| 720 | } else | ||
| 721 | xfs_da_brelse(args->trans, bp); | ||
| 722 | return(retval); | ||
| 723 | } | ||
| 724 | |||
| 725 | |||
| 726 | /*======================================================================== | ||
| 727 | * External routines when dirsize > XFS_LBSIZE(mp). | ||
| 728 | *========================================================================*/ | ||
| 729 | |||
| 730 | /* | ||
| 731 | * Add a name to a Btree-format directory. | ||
| 732 | * | ||
| 733 | * This will involve walking down the Btree, and may involve splitting | ||
| 734 | * leaf nodes and even splitting intermediate nodes up to and including | ||
| 735 | * the root node (a special case of an intermediate node). | ||
| 736 | */ | ||
| 737 | STATIC int | ||
| 738 | xfs_dir_node_addname(xfs_da_args_t *args) | ||
| 739 | { | ||
| 740 | xfs_da_state_t *state; | ||
| 741 | xfs_da_state_blk_t *blk; | ||
| 742 | int retval, error; | ||
| 743 | |||
| 744 | /* | ||
| 745 | * Fill in bucket of arguments/results/context to carry around. | ||
| 746 | */ | ||
| 747 | state = xfs_da_state_alloc(); | ||
| 748 | state->args = args; | ||
| 749 | state->mp = args->dp->i_mount; | ||
| 750 | state->blocksize = state->mp->m_sb.sb_blocksize; | ||
| 751 | state->node_ents = state->mp->m_dir_node_ents; | ||
| 752 | |||
| 753 | /* | ||
| 754 | * Search to see if name already exists, and get back a pointer | ||
| 755 | * to where it should go. | ||
| 756 | */ | ||
| 757 | error = xfs_da_node_lookup_int(state, &retval); | ||
| 758 | if (error) | ||
| 759 | retval = error; | ||
| 760 | if (retval != ENOENT) | ||
| 761 | goto error; | ||
| 762 | blk = &state->path.blk[ state->path.active-1 ]; | ||
| 763 | ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); | ||
| 764 | retval = xfs_dir_leaf_add(blk->bp, args, blk->index); | ||
| 765 | if (retval == 0) { | ||
| 766 | /* | ||
| 767 | * Addition succeeded, update Btree hashvals. | ||
| 768 | */ | ||
| 769 | if (!args->justcheck) | ||
| 770 | xfs_da_fixhashpath(state, &state->path); | ||
| 771 | } else { | ||
| 772 | /* | ||
| 773 | * Addition failed, split as many Btree elements as required. | ||
| 774 | */ | ||
| 775 | if (args->total == 0) { | ||
| 776 | ASSERT(retval == ENOSPC); | ||
| 777 | goto error; | ||
| 778 | } | ||
| 779 | retval = xfs_da_split(state); | ||
| 780 | } | ||
| 781 | error: | ||
| 782 | xfs_da_state_free(state); | ||
| 783 | |||
| 784 | return(retval); | ||
| 785 | } | ||
| 786 | |||
| 787 | /* | ||
| 788 | * Remove a name from a B-tree directory. | ||
| 789 | * | ||
| 790 | * This will involve walking down the Btree, and may involve joining | ||
| 791 | * leaf nodes and even joining intermediate nodes up to and including | ||
| 792 | * the root node (a special case of an intermediate node). | ||
| 793 | */ | ||
| 794 | STATIC int | ||
| 795 | xfs_dir_node_removename(xfs_da_args_t *args) | ||
| 796 | { | ||
| 797 | xfs_da_state_t *state; | ||
| 798 | xfs_da_state_blk_t *blk; | ||
| 799 | int retval, error; | ||
| 800 | |||
| 801 | state = xfs_da_state_alloc(); | ||
| 802 | state->args = args; | ||
| 803 | state->mp = args->dp->i_mount; | ||
| 804 | state->blocksize = state->mp->m_sb.sb_blocksize; | ||
| 805 | state->node_ents = state->mp->m_dir_node_ents; | ||
| 806 | |||
| 807 | /* | ||
| 808 | * Search to see if name exists, and get back a pointer to it. | ||
| 809 | */ | ||
| 810 | error = xfs_da_node_lookup_int(state, &retval); | ||
| 811 | if (error) | ||
| 812 | retval = error; | ||
| 813 | if (retval != EEXIST) { | ||
| 814 | xfs_da_state_free(state); | ||
| 815 | return(retval); | ||
| 816 | } | ||
| 817 | |||
| 818 | /* | ||
| 819 | * Remove the name and update the hashvals in the tree. | ||
| 820 | */ | ||
| 821 | blk = &state->path.blk[ state->path.active-1 ]; | ||
| 822 | ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); | ||
| 823 | retval = xfs_dir_leaf_remove(args->trans, blk->bp, blk->index); | ||
| 824 | xfs_da_fixhashpath(state, &state->path); | ||
| 825 | |||
| 826 | /* | ||
| 827 | * Check to see if the tree needs to be collapsed. | ||
| 828 | */ | ||
| 829 | error = 0; | ||
| 830 | if (retval) { | ||
| 831 | error = xfs_da_join(state); | ||
| 832 | } | ||
| 833 | |||
| 834 | xfs_da_state_free(state); | ||
| 835 | if (error) | ||
| 836 | return(error); | ||
| 837 | return(0); | ||
| 838 | } | ||
| 839 | |||
| 840 | /* | ||
| 841 | * Look up a filename in a int directory. | ||
| 842 | * Use an internal routine to actually do all the work. | ||
| 843 | */ | ||
| 844 | STATIC int | ||
| 845 | xfs_dir_node_lookup(xfs_da_args_t *args) | ||
| 846 | { | ||
| 847 | xfs_da_state_t *state; | ||
| 848 | int retval, error, i; | ||
| 849 | |||
| 850 | state = xfs_da_state_alloc(); | ||
| 851 | state->args = args; | ||
| 852 | state->mp = args->dp->i_mount; | ||
| 853 | state->blocksize = state->mp->m_sb.sb_blocksize; | ||
| 854 | state->node_ents = state->mp->m_dir_node_ents; | ||
| 855 | |||
| 856 | /* | ||
| 857 | * Search to see if name exists, | ||
| 858 | * and get back a pointer to it. | ||
| 859 | */ | ||
| 860 | error = xfs_da_node_lookup_int(state, &retval); | ||
| 861 | if (error) { | ||
| 862 | retval = error; | ||
| 863 | } | ||
| 864 | |||
| 865 | /* | ||
| 866 | * If not in a transaction, we have to release all the buffers. | ||
| 867 | */ | ||
| 868 | for (i = 0; i < state->path.active; i++) { | ||
| 869 | xfs_da_brelse(args->trans, state->path.blk[i].bp); | ||
| 870 | state->path.blk[i].bp = NULL; | ||
| 871 | } | ||
| 872 | |||
| 873 | xfs_da_state_free(state); | ||
| 874 | return(retval); | ||
| 875 | } | ||
| 876 | |||
| 877 | STATIC int | ||
| 878 | xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, | ||
| 879 | int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put) | ||
| 880 | { | ||
| 881 | xfs_da_intnode_t *node; | ||
| 882 | xfs_da_node_entry_t *btree; | ||
| 883 | xfs_dir_leafblock_t *leaf = NULL; | ||
| 884 | xfs_dablk_t bno, nextbno; | ||
| 885 | xfs_dahash_t cookhash; | ||
| 886 | xfs_mount_t *mp; | ||
| 887 | int error, eob, i; | ||
| 888 | xfs_dabuf_t *bp; | ||
| 889 | xfs_daddr_t nextda; | ||
| 890 | |||
| 891 | /* | ||
| 892 | * Pick up our context. | ||
| 893 | */ | ||
| 894 | mp = dp->i_mount; | ||
| 895 | bp = NULL; | ||
| 896 | bno = XFS_DA_COOKIE_BNO(mp, uio->uio_offset); | ||
| 897 | cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset); | ||
| 898 | |||
| 899 | xfs_dir_trace_g_du("node: start", dp, uio); | ||
| 900 | |||
| 901 | /* | ||
| 902 | * Re-find our place, even if we're confused about what our place is. | ||
| 903 | * | ||
| 904 | * First we check the block number from the magic cookie, it is a | ||
| 905 | * cache of where we ended last time. If we find a leaf block, and | ||
| 906 | * the starting hashval in that block is less than our desired | ||
| 907 | * hashval, then we run with it. | ||
| 908 | */ | ||
| 909 | if (bno > 0) { | ||
| 910 | error = xfs_da_read_buf(trans, dp, bno, -2, &bp, XFS_DATA_FORK); | ||
| 911 | if ((error != 0) && (error != EFSCORRUPTED)) | ||
| 912 | return(error); | ||
| 913 | if (bp) | ||
| 914 | leaf = bp->data; | ||
| 915 | if (bp && be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) { | ||
| 916 | xfs_dir_trace_g_dub("node: block not a leaf", | ||
| 917 | dp, uio, bno); | ||
| 918 | xfs_da_brelse(trans, bp); | ||
| 919 | bp = NULL; | ||
| 920 | } | ||
| 921 | if (bp && INT_GET(leaf->entries[0].hashval, ARCH_CONVERT) > cookhash) { | ||
| 922 | xfs_dir_trace_g_dub("node: leaf hash too large", | ||
| 923 | dp, uio, bno); | ||
| 924 | xfs_da_brelse(trans, bp); | ||
| 925 | bp = NULL; | ||
| 926 | } | ||
| 927 | if (bp && | ||
| 928 | cookhash > INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT)) { | ||
| 929 | xfs_dir_trace_g_dub("node: leaf hash too small", | ||
| 930 | dp, uio, bno); | ||
| 931 | xfs_da_brelse(trans, bp); | ||
| 932 | bp = NULL; | ||
| 933 | } | ||
| 934 | } | ||
| 935 | |||
| 936 | /* | ||
| 937 | * If we did not find a leaf block from the blockno in the cookie, | ||
| 938 | * or we there was no blockno in the cookie (eg: first time thru), | ||
| 939 | * the we start at the top of the Btree and re-find our hashval. | ||
| 940 | */ | ||
| 941 | if (bp == NULL) { | ||
| 942 | xfs_dir_trace_g_du("node: start at root" , dp, uio); | ||
| 943 | bno = 0; | ||
| 944 | for (;;) { | ||
| 945 | error = xfs_da_read_buf(trans, dp, bno, -1, &bp, | ||
| 946 | XFS_DATA_FORK); | ||
| 947 | if (error) | ||
| 948 | return(error); | ||
| 949 | if (bp == NULL) | ||
| 950 | return(XFS_ERROR(EFSCORRUPTED)); | ||
| 951 | node = bp->data; | ||
| 952 | if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) | ||
| 953 | break; | ||
| 954 | btree = &node->btree[0]; | ||
| 955 | xfs_dir_trace_g_dun("node: node detail", dp, uio, node); | ||
| 956 | for (i = 0; i < be16_to_cpu(node->hdr.count); btree++, i++) { | ||
| 957 | if (be32_to_cpu(btree->hashval) >= cookhash) { | ||
| 958 | bno = be32_to_cpu(btree->before); | ||
| 959 | break; | ||
| 960 | } | ||
| 961 | } | ||
| 962 | if (i == be16_to_cpu(node->hdr.count)) { | ||
| 963 | xfs_da_brelse(trans, bp); | ||
| 964 | xfs_dir_trace_g_du("node: hash beyond EOF", | ||
| 965 | dp, uio); | ||
| 966 | uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0, | ||
| 967 | XFS_DA_MAXHASH); | ||
| 968 | *eofp = 1; | ||
| 969 | return(0); | ||
| 970 | } | ||
| 971 | xfs_dir_trace_g_dub("node: going to block", | ||
| 972 | dp, uio, bno); | ||
| 973 | xfs_da_brelse(trans, bp); | ||
| 974 | } | ||
| 975 | } | ||
| 976 | ASSERT(cookhash != XFS_DA_MAXHASH); | ||
| 977 | |||
| 978 | /* | ||
| 979 | * We've dropped down to the (first) leaf block that contains the | ||
| 980 | * hashval we are interested in. Continue rolling upward thru the | ||
| 981 | * leaf blocks until we fill up our buffer. | ||
| 982 | */ | ||
| 983 | for (;;) { | ||
| 984 | leaf = bp->data; | ||
| 985 | if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC)) { | ||
| 986 | xfs_dir_trace_g_dul("node: not a leaf", dp, uio, leaf); | ||
| 987 | xfs_da_brelse(trans, bp); | ||
| 988 | XFS_CORRUPTION_ERROR("xfs_dir_node_getdents(1)", | ||
| 989 | XFS_ERRLEVEL_LOW, mp, leaf); | ||
| 990 | return XFS_ERROR(EFSCORRUPTED); | ||
| 991 | } | ||
| 992 | xfs_dir_trace_g_dul("node: leaf detail", dp, uio, leaf); | ||
| 993 | if ((nextbno = be32_to_cpu(leaf->hdr.info.forw))) { | ||
| 994 | nextda = xfs_da_reada_buf(trans, dp, nextbno, | ||
| 995 | XFS_DATA_FORK); | ||
| 996 | } else | ||
| 997 | nextda = -1; | ||
| 998 | error = xfs_dir_leaf_getdents_int(bp, dp, bno, uio, &eob, dbp, | ||
| 999 | put, nextda); | ||
| 1000 | xfs_da_brelse(trans, bp); | ||
| 1001 | bno = nextbno; | ||
| 1002 | if (eob) { | ||
| 1003 | xfs_dir_trace_g_dub("node: E-O-B", dp, uio, bno); | ||
| 1004 | *eofp = 0; | ||
| 1005 | return(error); | ||
| 1006 | } | ||
| 1007 | if (bno == 0) | ||
| 1008 | break; | ||
| 1009 | error = xfs_da_read_buf(trans, dp, bno, nextda, &bp, | ||
| 1010 | XFS_DATA_FORK); | ||
| 1011 | if (error) | ||
| 1012 | return(error); | ||
| 1013 | if (unlikely(bp == NULL)) { | ||
| 1014 | XFS_ERROR_REPORT("xfs_dir_node_getdents(2)", | ||
| 1015 | XFS_ERRLEVEL_LOW, mp); | ||
| 1016 | return(XFS_ERROR(EFSCORRUPTED)); | ||
| 1017 | } | ||
| 1018 | } | ||
| 1019 | *eofp = 1; | ||
| 1020 | xfs_dir_trace_g_du("node: E-O-F", dp, uio); | ||
| 1021 | return(0); | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | /* | ||
| 1025 | * Look up a filename in an int directory, replace the inode number. | ||
| 1026 | * Use an internal routine to actually do the lookup. | ||
| 1027 | */ | ||
| 1028 | STATIC int | ||
| 1029 | xfs_dir_node_replace(xfs_da_args_t *args) | ||
| 1030 | { | ||
| 1031 | xfs_da_state_t *state; | ||
| 1032 | xfs_da_state_blk_t *blk; | ||
| 1033 | xfs_dir_leafblock_t *leaf; | ||
| 1034 | xfs_dir_leaf_entry_t *entry; | ||
| 1035 | xfs_dir_leaf_name_t *namest; | ||
| 1036 | xfs_ino_t inum; | ||
| 1037 | int retval, error, i; | ||
| 1038 | xfs_dabuf_t *bp; | ||
| 1039 | |||
| 1040 | state = xfs_da_state_alloc(); | ||
| 1041 | state->args = args; | ||
| 1042 | state->mp = args->dp->i_mount; | ||
| 1043 | state->blocksize = state->mp->m_sb.sb_blocksize; | ||
| 1044 | state->node_ents = state->mp->m_dir_node_ents; | ||
| 1045 | inum = args->inumber; | ||
| 1046 | |||
| 1047 | /* | ||
| 1048 | * Search to see if name exists, | ||
| 1049 | * and get back a pointer to it. | ||
| 1050 | */ | ||
| 1051 | error = xfs_da_node_lookup_int(state, &retval); | ||
| 1052 | if (error) { | ||
| 1053 | retval = error; | ||
| 1054 | } | ||
| 1055 | |||
| 1056 | if (retval == EEXIST) { | ||
| 1057 | blk = &state->path.blk[state->path.active - 1]; | ||
| 1058 | ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); | ||
| 1059 | bp = blk->bp; | ||
| 1060 | leaf = bp->data; | ||
| 1061 | entry = &leaf->entries[blk->index]; | ||
| 1062 | namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); | ||
| 1063 | /* XXX - replace assert ? */ | ||
| 1064 | XFS_DIR_SF_PUT_DIRINO(&inum, &namest->inumber); | ||
| 1065 | xfs_da_log_buf(args->trans, bp, | ||
| 1066 | XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); | ||
| 1067 | xfs_da_buf_done(bp); | ||
| 1068 | blk->bp = NULL; | ||
| 1069 | retval = 0; | ||
| 1070 | } else { | ||
| 1071 | i = state->path.active - 1; | ||
| 1072 | xfs_da_brelse(args->trans, state->path.blk[i].bp); | ||
| 1073 | state->path.blk[i].bp = NULL; | ||
| 1074 | } | ||
| 1075 | for (i = 0; i < state->path.active - 1; i++) { | ||
| 1076 | xfs_da_brelse(args->trans, state->path.blk[i].bp); | ||
| 1077 | state->path.blk[i].bp = NULL; | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | xfs_da_state_free(state); | ||
| 1081 | return(retval); | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | #if defined(XFS_DIR_TRACE) | ||
| 1085 | /* | ||
| 1086 | * Add a trace buffer entry for an inode and a uio. | ||
| 1087 | */ | ||
| 1088 | void | ||
| 1089 | xfs_dir_trace_g_du(char *where, xfs_inode_t *dp, uio_t *uio) | ||
| 1090 | { | ||
| 1091 | xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DU, where, | ||
| 1092 | (void *)dp, (void *)dp->i_mount, | ||
| 1093 | (void *)((unsigned long)(uio->uio_offset >> 32)), | ||
| 1094 | (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), | ||
| 1095 | (void *)(unsigned long)uio->uio_resid, | ||
| 1096 | NULL, NULL, NULL, NULL, NULL, NULL, NULL); | ||
| 1097 | } | ||
| 1098 | |||
| 1099 | /* | ||
| 1100 | * Add a trace buffer entry for an inode and a uio. | ||
| 1101 | */ | ||
| 1102 | void | ||
| 1103 | xfs_dir_trace_g_dub(char *where, xfs_inode_t *dp, uio_t *uio, xfs_dablk_t bno) | ||
| 1104 | { | ||
| 1105 | xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUB, where, | ||
| 1106 | (void *)dp, (void *)dp->i_mount, | ||
| 1107 | (void *)((unsigned long)(uio->uio_offset >> 32)), | ||
| 1108 | (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), | ||
| 1109 | (void *)(unsigned long)uio->uio_resid, | ||
| 1110 | (void *)(unsigned long)bno, | ||
| 1111 | NULL, NULL, NULL, NULL, NULL, NULL); | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | /* | ||
| 1115 | * Add a trace buffer entry for an inode and a uio. | ||
| 1116 | */ | ||
| 1117 | void | ||
| 1118 | xfs_dir_trace_g_dun(char *where, xfs_inode_t *dp, uio_t *uio, | ||
| 1119 | xfs_da_intnode_t *node) | ||
| 1120 | { | ||
| 1121 | int last = be16_to_cpu(node->hdr.count) - 1; | ||
| 1122 | |||
| 1123 | xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUN, where, | ||
| 1124 | (void *)dp, (void *)dp->i_mount, | ||
| 1125 | (void *)((unsigned long)(uio->uio_offset >> 32)), | ||
| 1126 | (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), | ||
| 1127 | (void *)(unsigned long)uio->uio_resid, | ||
| 1128 | (void *)(unsigned long)be32_to_cpu(node->hdr.info.forw), | ||
| 1129 | (void *)(unsigned long) | ||
| 1130 | be16_to_cpu(node->hdr.count), | ||
| 1131 | (void *)(unsigned long) | ||
| 1132 | be32_to_cpu(node->btree[0].hashval), | ||
| 1133 | (void *)(unsigned long) | ||
| 1134 | be32_to_cpu(node->btree[last].hashval), | ||
| 1135 | NULL, NULL, NULL); | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | /* | ||
| 1139 | * Add a trace buffer entry for an inode and a uio. | ||
| 1140 | */ | ||
| 1141 | void | ||
| 1142 | xfs_dir_trace_g_dul(char *where, xfs_inode_t *dp, uio_t *uio, | ||
| 1143 | xfs_dir_leafblock_t *leaf) | ||
| 1144 | { | ||
| 1145 | int last = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1; | ||
| 1146 | |||
| 1147 | xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUL, where, | ||
| 1148 | (void *)dp, (void *)dp->i_mount, | ||
| 1149 | (void *)((unsigned long)(uio->uio_offset >> 32)), | ||
| 1150 | (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), | ||
| 1151 | (void *)(unsigned long)uio->uio_resid, | ||
| 1152 | (void *)(unsigned long)be32_to_cpu(leaf->hdr.info.forw), | ||
| 1153 | (void *)(unsigned long) | ||
| 1154 | INT_GET(leaf->hdr.count, ARCH_CONVERT), | ||
| 1155 | (void *)(unsigned long) | ||
| 1156 | INT_GET(leaf->entries[0].hashval, ARCH_CONVERT), | ||
| 1157 | (void *)(unsigned long) | ||
| 1158 | INT_GET(leaf->entries[last].hashval, ARCH_CONVERT), | ||
| 1159 | NULL, NULL, NULL); | ||
| 1160 | } | ||
| 1161 | |||
| 1162 | /* | ||
| 1163 | * Add a trace buffer entry for an inode and a uio. | ||
| 1164 | */ | ||
| 1165 | void | ||
| 1166 | xfs_dir_trace_g_due(char *where, xfs_inode_t *dp, uio_t *uio, | ||
| 1167 | xfs_dir_leaf_entry_t *entry) | ||
| 1168 | { | ||
| 1169 | xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUE, where, | ||
| 1170 | (void *)dp, (void *)dp->i_mount, | ||
| 1171 | (void *)((unsigned long)(uio->uio_offset >> 32)), | ||
| 1172 | (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), | ||
| 1173 | (void *)(unsigned long)uio->uio_resid, | ||
| 1174 | (void *)(unsigned long) | ||
| 1175 | INT_GET(entry->hashval, ARCH_CONVERT), | ||
| 1176 | NULL, NULL, NULL, NULL, NULL, NULL); | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | /* | ||
| 1180 | * Add a trace buffer entry for an inode and a uio. | ||
| 1181 | */ | ||
| 1182 | void | ||
| 1183 | xfs_dir_trace_g_duc(char *where, xfs_inode_t *dp, uio_t *uio, xfs_off_t cookie) | ||
| 1184 | { | ||
| 1185 | xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUC, where, | ||
| 1186 | (void *)dp, (void *)dp->i_mount, | ||
| 1187 | (void *)((unsigned long)(uio->uio_offset >> 32)), | ||
| 1188 | (void *)((unsigned long)(uio->uio_offset & 0xFFFFFFFF)), | ||
| 1189 | (void *)(unsigned long)uio->uio_resid, | ||
| 1190 | (void *)((unsigned long)(cookie >> 32)), | ||
| 1191 | (void *)((unsigned long)(cookie & 0xFFFFFFFF)), | ||
| 1192 | NULL, NULL, NULL, NULL, NULL); | ||
| 1193 | } | ||
| 1194 | |||
| 1195 | /* | ||
| 1196 | * Add a trace buffer entry for the arguments given to the routine, | ||
| 1197 | * generic form. | ||
| 1198 | */ | ||
| 1199 | void | ||
| 1200 | xfs_dir_trace_enter(int type, char *where, | ||
| 1201 | void * a0, void * a1, | ||
| 1202 | void * a2, void * a3, | ||
| 1203 | void * a4, void * a5, | ||
| 1204 | void * a6, void * a7, | ||
| 1205 | void * a8, void * a9, | ||
| 1206 | void * a10, void * a11) | ||
| 1207 | { | ||
| 1208 | ASSERT(xfs_dir_trace_buf); | ||
| 1209 | ktrace_enter(xfs_dir_trace_buf, (void *)(unsigned long)type, | ||
| 1210 | (void *)where, | ||
| 1211 | (void *)a0, (void *)a1, (void *)a2, | ||
| 1212 | (void *)a3, (void *)a4, (void *)a5, | ||
| 1213 | (void *)a6, (void *)a7, (void *)a8, | ||
| 1214 | (void *)a9, (void *)a10, (void *)a11, | ||
| 1215 | NULL, NULL); | ||
| 1216 | } | ||
| 1217 | #endif /* XFS_DIR_TRACE */ | ||
diff --git a/fs/xfs/xfs_dir.h b/fs/xfs/xfs_dir.h deleted file mode 100644 index 8cc8afb9f6c0..000000000000 --- a/fs/xfs/xfs_dir.h +++ /dev/null | |||
| @@ -1,142 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000,2005 Silicon Graphics, Inc. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it would be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write the Free Software Foundation, | ||
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | #ifndef __XFS_DIR_H__ | ||
| 19 | #define __XFS_DIR_H__ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Large directories are structured around Btrees where all the data | ||
| 23 | * elements are in the leaf nodes. Filenames are hashed into an int, | ||
| 24 | * then that int is used as the index into the Btree. Since the hashval | ||
| 25 | * of a filename may not be unique, we may have duplicate keys. The | ||
| 26 | * internal links in the Btree are logical block offsets into the file. | ||
| 27 | * | ||
| 28 | * Small directories use a different format and are packed as tightly | ||
| 29 | * as possible so as to fit into the literal area of the inode. | ||
| 30 | */ | ||
| 31 | |||
| 32 | /*======================================================================== | ||
| 33 | * Function prototypes for the kernel. | ||
| 34 | *========================================================================*/ | ||
| 35 | |||
| 36 | struct uio; | ||
| 37 | struct xfs_bmap_free; | ||
| 38 | struct xfs_da_args; | ||
| 39 | struct xfs_dinode; | ||
| 40 | struct xfs_inode; | ||
| 41 | struct xfs_mount; | ||
| 42 | struct xfs_trans; | ||
| 43 | |||
| 44 | /* | ||
| 45 | * Directory function types. | ||
| 46 | * Put in structures (xfs_dirops_t) for v1 and v2 directories. | ||
| 47 | */ | ||
| 48 | typedef void (*xfs_dir_mount_t)(struct xfs_mount *mp); | ||
| 49 | typedef int (*xfs_dir_isempty_t)(struct xfs_inode *dp); | ||
| 50 | typedef int (*xfs_dir_init_t)(struct xfs_trans *tp, | ||
| 51 | struct xfs_inode *dp, | ||
| 52 | struct xfs_inode *pdp); | ||
| 53 | typedef int (*xfs_dir_createname_t)(struct xfs_trans *tp, | ||
| 54 | struct xfs_inode *dp, | ||
| 55 | char *name, | ||
| 56 | int namelen, | ||
| 57 | xfs_ino_t inum, | ||
| 58 | xfs_fsblock_t *first, | ||
| 59 | struct xfs_bmap_free *flist, | ||
| 60 | xfs_extlen_t total); | ||
| 61 | typedef int (*xfs_dir_lookup_t)(struct xfs_trans *tp, | ||
| 62 | struct xfs_inode *dp, | ||
| 63 | char *name, | ||
| 64 | int namelen, | ||
| 65 | xfs_ino_t *inum); | ||
| 66 | typedef int (*xfs_dir_removename_t)(struct xfs_trans *tp, | ||
| 67 | struct xfs_inode *dp, | ||
| 68 | char *name, | ||
| 69 | int namelen, | ||
| 70 | xfs_ino_t ino, | ||
| 71 | xfs_fsblock_t *first, | ||
| 72 | struct xfs_bmap_free *flist, | ||
| 73 | xfs_extlen_t total); | ||
| 74 | typedef int (*xfs_dir_getdents_t)(struct xfs_trans *tp, | ||
| 75 | struct xfs_inode *dp, | ||
| 76 | struct uio *uio, | ||
| 77 | int *eofp); | ||
| 78 | typedef int (*xfs_dir_replace_t)(struct xfs_trans *tp, | ||
| 79 | struct xfs_inode *dp, | ||
| 80 | char *name, | ||
| 81 | int namelen, | ||
| 82 | xfs_ino_t inum, | ||
| 83 | xfs_fsblock_t *first, | ||
| 84 | struct xfs_bmap_free *flist, | ||
| 85 | xfs_extlen_t total); | ||
| 86 | typedef int (*xfs_dir_canenter_t)(struct xfs_trans *tp, | ||
| 87 | struct xfs_inode *dp, | ||
| 88 | char *name, | ||
| 89 | int namelen); | ||
| 90 | typedef int (*xfs_dir_shortform_validate_ondisk_t)(struct xfs_mount *mp, | ||
| 91 | struct xfs_dinode *dip); | ||
| 92 | typedef int (*xfs_dir_shortform_to_single_t)(struct xfs_da_args *args); | ||
| 93 | |||
| 94 | typedef struct xfs_dirops { | ||
| 95 | xfs_dir_mount_t xd_mount; | ||
| 96 | xfs_dir_isempty_t xd_isempty; | ||
| 97 | xfs_dir_init_t xd_init; | ||
| 98 | xfs_dir_createname_t xd_createname; | ||
| 99 | xfs_dir_lookup_t xd_lookup; | ||
| 100 | xfs_dir_removename_t xd_removename; | ||
| 101 | xfs_dir_getdents_t xd_getdents; | ||
| 102 | xfs_dir_replace_t xd_replace; | ||
| 103 | xfs_dir_canenter_t xd_canenter; | ||
| 104 | xfs_dir_shortform_validate_ondisk_t xd_shortform_validate_ondisk; | ||
| 105 | xfs_dir_shortform_to_single_t xd_shortform_to_single; | ||
| 106 | } xfs_dirops_t; | ||
| 107 | |||
| 108 | /* | ||
| 109 | * Overall external interface routines. | ||
| 110 | */ | ||
| 111 | void xfs_dir_startup(void); /* called exactly once */ | ||
| 112 | |||
| 113 | #define XFS_DIR_MOUNT(mp) \ | ||
| 114 | ((mp)->m_dirops.xd_mount(mp)) | ||
| 115 | #define XFS_DIR_ISEMPTY(mp,dp) \ | ||
| 116 | ((mp)->m_dirops.xd_isempty(dp)) | ||
| 117 | #define XFS_DIR_INIT(mp,tp,dp,pdp) \ | ||
| 118 | ((mp)->m_dirops.xd_init(tp,dp,pdp)) | ||
| 119 | #define XFS_DIR_CREATENAME(mp,tp,dp,name,namelen,inum,first,flist,total) \ | ||
| 120 | ((mp)->m_dirops.xd_createname(tp,dp,name,namelen,inum,first,flist,\ | ||
| 121 | total)) | ||
| 122 | #define XFS_DIR_LOOKUP(mp,tp,dp,name,namelen,inum) \ | ||
| 123 | ((mp)->m_dirops.xd_lookup(tp,dp,name,namelen,inum)) | ||
| 124 | #define XFS_DIR_REMOVENAME(mp,tp,dp,name,namelen,ino,first,flist,total) \ | ||
| 125 | ((mp)->m_dirops.xd_removename(tp,dp,name,namelen,ino,first,flist,total)) | ||
| 126 | #define XFS_DIR_GETDENTS(mp,tp,dp,uio,eofp) \ | ||
| 127 | ((mp)->m_dirops.xd_getdents(tp,dp,uio,eofp)) | ||
| 128 | #define XFS_DIR_REPLACE(mp,tp,dp,name,namelen,inum,first,flist,total) \ | ||
| 129 | ((mp)->m_dirops.xd_replace(tp,dp,name,namelen,inum,first,flist,total)) | ||
| 130 | #define XFS_DIR_CANENTER(mp,tp,dp,name,namelen) \ | ||
| 131 | ((mp)->m_dirops.xd_canenter(tp,dp,name,namelen)) | ||
| 132 | #define XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp,dip) \ | ||
| 133 | ((mp)->m_dirops.xd_shortform_validate_ondisk(mp,dip)) | ||
| 134 | #define XFS_DIR_SHORTFORM_TO_SINGLE(mp,args) \ | ||
| 135 | ((mp)->m_dirops.xd_shortform_to_single(args)) | ||
| 136 | |||
| 137 | #define XFS_DIR_IS_V1(mp) ((mp)->m_dirversion == 1) | ||
| 138 | #define XFS_DIR_IS_V2(mp) ((mp)->m_dirversion == 2) | ||
| 139 | extern xfs_dirops_t xfsv1_dirops; | ||
| 140 | extern xfs_dirops_t xfsv2_dirops; | ||
| 141 | |||
| 142 | #endif /* __XFS_DIR_H__ */ | ||
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index 022c8398ab62..8edbe1adb95b 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c | |||
| @@ -24,21 +24,18 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_da_btree.h" | 30 | #include "xfs_da_btree.h" |
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| 38 | #include "xfs_inode.h" | 36 | #include "xfs_inode.h" |
| 39 | #include "xfs_inode_item.h" | 37 | #include "xfs_inode_item.h" |
| 40 | #include "xfs_bmap.h" | 38 | #include "xfs_bmap.h" |
| 41 | #include "xfs_dir_leaf.h" | ||
| 42 | #include "xfs_dir2_data.h" | 39 | #include "xfs_dir2_data.h" |
| 43 | #include "xfs_dir2_leaf.h" | 40 | #include "xfs_dir2_leaf.h" |
| 44 | #include "xfs_dir2_block.h" | 41 | #include "xfs_dir2_block.h" |
| @@ -46,69 +43,14 @@ | |||
| 46 | #include "xfs_dir2_trace.h" | 43 | #include "xfs_dir2_trace.h" |
| 47 | #include "xfs_error.h" | 44 | #include "xfs_error.h" |
| 48 | 45 | ||
| 49 | /* | ||
| 50 | * Declarations for interface routines. | ||
| 51 | */ | ||
| 52 | static void xfs_dir2_mount(xfs_mount_t *mp); | ||
| 53 | static int xfs_dir2_isempty(xfs_inode_t *dp); | ||
| 54 | static int xfs_dir2_init(xfs_trans_t *tp, xfs_inode_t *dp, | ||
| 55 | xfs_inode_t *pdp); | ||
| 56 | static int xfs_dir2_createname(xfs_trans_t *tp, xfs_inode_t *dp, | ||
| 57 | char *name, int namelen, xfs_ino_t inum, | ||
| 58 | xfs_fsblock_t *first, | ||
| 59 | xfs_bmap_free_t *flist, xfs_extlen_t total); | ||
| 60 | static int xfs_dir2_lookup(xfs_trans_t *tp, xfs_inode_t *dp, char *name, | ||
| 61 | int namelen, xfs_ino_t *inum); | ||
| 62 | static int xfs_dir2_removename(xfs_trans_t *tp, xfs_inode_t *dp, | ||
| 63 | char *name, int namelen, xfs_ino_t ino, | ||
| 64 | xfs_fsblock_t *first, | ||
| 65 | xfs_bmap_free_t *flist, xfs_extlen_t total); | ||
| 66 | static int xfs_dir2_getdents(xfs_trans_t *tp, xfs_inode_t *dp, uio_t *uio, | ||
| 67 | int *eofp); | ||
| 68 | static int xfs_dir2_replace(xfs_trans_t *tp, xfs_inode_t *dp, char *name, | ||
| 69 | int namelen, xfs_ino_t inum, | ||
| 70 | xfs_fsblock_t *first, xfs_bmap_free_t *flist, | ||
| 71 | xfs_extlen_t total); | ||
| 72 | static int xfs_dir2_canenter(xfs_trans_t *tp, xfs_inode_t *dp, char *name, | ||
| 73 | int namelen); | ||
| 74 | static int xfs_dir2_shortform_validate_ondisk(xfs_mount_t *mp, | ||
| 75 | xfs_dinode_t *dip); | ||
| 76 | |||
| 77 | /* | ||
| 78 | * Utility routine declarations. | ||
| 79 | */ | ||
| 80 | static int xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa); | 46 | static int xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa); |
| 81 | static int xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa); | 47 | static int xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa); |
| 82 | 48 | ||
| 83 | /* | 49 | void |
| 84 | * Directory operations vector. | 50 | xfs_dir_mount( |
| 85 | */ | 51 | xfs_mount_t *mp) |
| 86 | xfs_dirops_t xfsv2_dirops = { | ||
| 87 | .xd_mount = xfs_dir2_mount, | ||
| 88 | .xd_isempty = xfs_dir2_isempty, | ||
| 89 | .xd_init = xfs_dir2_init, | ||
| 90 | .xd_createname = xfs_dir2_createname, | ||
| 91 | .xd_lookup = xfs_dir2_lookup, | ||
| 92 | .xd_removename = xfs_dir2_removename, | ||
| 93 | .xd_getdents = xfs_dir2_getdents, | ||
| 94 | .xd_replace = xfs_dir2_replace, | ||
| 95 | .xd_canenter = xfs_dir2_canenter, | ||
| 96 | .xd_shortform_validate_ondisk = xfs_dir2_shortform_validate_ondisk, | ||
| 97 | .xd_shortform_to_single = xfs_dir2_sf_to_block, | ||
| 98 | }; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * Interface routines. | ||
| 102 | */ | ||
| 103 | |||
| 104 | /* | ||
| 105 | * Initialize directory-related fields in the mount structure. | ||
| 106 | */ | ||
| 107 | static void | ||
| 108 | xfs_dir2_mount( | ||
| 109 | xfs_mount_t *mp) /* filesystem mount point */ | ||
| 110 | { | 52 | { |
| 111 | mp->m_dirversion = 2; | 53 | ASSERT(XFS_SB_VERSION_HASDIRV2(&mp->m_sb)); |
| 112 | ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <= | 54 | ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <= |
| 113 | XFS_MAX_BLOCKSIZE); | 55 | XFS_MAX_BLOCKSIZE); |
| 114 | mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog); | 56 | mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog); |
| @@ -128,19 +70,15 @@ xfs_dir2_mount( | |||
| 128 | /* | 70 | /* |
| 129 | * Return 1 if directory contains only "." and "..". | 71 | * Return 1 if directory contains only "." and "..". |
| 130 | */ | 72 | */ |
| 131 | static int /* return code */ | 73 | int |
| 132 | xfs_dir2_isempty( | 74 | xfs_dir_isempty( |
| 133 | xfs_inode_t *dp) /* incore inode structure */ | 75 | xfs_inode_t *dp) |
| 134 | { | 76 | { |
| 135 | xfs_dir2_sf_t *sfp; /* shortform directory structure */ | 77 | xfs_dir2_sf_t *sfp; |
| 136 | 78 | ||
| 137 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 79 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 138 | /* | 80 | if (dp->i_d.di_size == 0) /* might happen during shutdown. */ |
| 139 | * Might happen during shutdown. | ||
| 140 | */ | ||
| 141 | if (dp->i_d.di_size == 0) { | ||
| 142 | return 1; | 81 | return 1; |
| 143 | } | ||
| 144 | if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) | 82 | if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) |
| 145 | return 0; | 83 | return 0; |
| 146 | sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; | 84 | sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; |
| @@ -148,53 +86,83 @@ xfs_dir2_isempty( | |||
| 148 | } | 86 | } |
| 149 | 87 | ||
| 150 | /* | 88 | /* |
| 89 | * Validate a given inode number. | ||
| 90 | */ | ||
| 91 | int | ||
| 92 | xfs_dir_ino_validate( | ||
| 93 | xfs_mount_t *mp, | ||
| 94 | xfs_ino_t ino) | ||
| 95 | { | ||
| 96 | xfs_agblock_t agblkno; | ||
| 97 | xfs_agino_t agino; | ||
| 98 | xfs_agnumber_t agno; | ||
| 99 | int ino_ok; | ||
| 100 | int ioff; | ||
| 101 | |||
| 102 | agno = XFS_INO_TO_AGNO(mp, ino); | ||
| 103 | agblkno = XFS_INO_TO_AGBNO(mp, ino); | ||
| 104 | ioff = XFS_INO_TO_OFFSET(mp, ino); | ||
| 105 | agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff); | ||
| 106 | ino_ok = | ||
| 107 | agno < mp->m_sb.sb_agcount && | ||
| 108 | agblkno < mp->m_sb.sb_agblocks && | ||
| 109 | agblkno != 0 && | ||
| 110 | ioff < (1 << mp->m_sb.sb_inopblog) && | ||
| 111 | XFS_AGINO_TO_INO(mp, agno, agino) == ino; | ||
| 112 | if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE, | ||
| 113 | XFS_RANDOM_DIR_INO_VALIDATE))) { | ||
| 114 | xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx", | ||
| 115 | (unsigned long long) ino); | ||
| 116 | XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp); | ||
| 117 | return XFS_ERROR(EFSCORRUPTED); | ||
| 118 | } | ||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* | ||
| 151 | * Initialize a directory with its "." and ".." entries. | 123 | * Initialize a directory with its "." and ".." entries. |
| 152 | */ | 124 | */ |
| 153 | static int /* error */ | 125 | int |
| 154 | xfs_dir2_init( | 126 | xfs_dir_init( |
| 155 | xfs_trans_t *tp, /* transaction pointer */ | 127 | xfs_trans_t *tp, |
| 156 | xfs_inode_t *dp, /* incore directory inode */ | 128 | xfs_inode_t *dp, |
| 157 | xfs_inode_t *pdp) /* incore parent directory inode */ | 129 | xfs_inode_t *pdp) |
| 158 | { | 130 | { |
| 159 | xfs_da_args_t args; /* operation arguments */ | 131 | xfs_da_args_t args; |
| 160 | int error; /* error return value */ | 132 | int error; |
| 161 | 133 | ||
| 162 | memset((char *)&args, 0, sizeof(args)); | 134 | memset((char *)&args, 0, sizeof(args)); |
| 163 | args.dp = dp; | 135 | args.dp = dp; |
| 164 | args.trans = tp; | 136 | args.trans = tp; |
| 165 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 137 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 166 | if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) { | 138 | if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) |
| 167 | return error; | 139 | return error; |
| 168 | } | ||
| 169 | return xfs_dir2_sf_create(&args, pdp->i_ino); | 140 | return xfs_dir2_sf_create(&args, pdp->i_ino); |
| 170 | } | 141 | } |
| 171 | 142 | ||
| 172 | /* | 143 | /* |
| 173 | Enter a name in a directory. | 144 | Enter a name in a directory. |
| 174 | */ | 145 | */ |
| 175 | static int /* error */ | 146 | int |
| 176 | xfs_dir2_createname( | 147 | xfs_dir_createname( |
| 177 | xfs_trans_t *tp, /* transaction pointer */ | 148 | xfs_trans_t *tp, |
| 178 | xfs_inode_t *dp, /* incore directory inode */ | 149 | xfs_inode_t *dp, |
| 179 | char *name, /* new entry name */ | 150 | char *name, |
| 180 | int namelen, /* new entry name length */ | 151 | int namelen, |
| 181 | xfs_ino_t inum, /* new entry inode number */ | 152 | xfs_ino_t inum, /* new entry inode number */ |
| 182 | xfs_fsblock_t *first, /* bmap's firstblock */ | 153 | xfs_fsblock_t *first, /* bmap's firstblock */ |
| 183 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ | 154 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ |
| 184 | xfs_extlen_t total) /* bmap's total block count */ | 155 | xfs_extlen_t total) /* bmap's total block count */ |
| 185 | { | 156 | { |
| 186 | xfs_da_args_t args; /* operation arguments */ | 157 | xfs_da_args_t args; |
| 187 | int rval; /* return value */ | 158 | int rval; |
| 188 | int v; /* type-checking value */ | 159 | int v; /* type-checking value */ |
| 189 | 160 | ||
| 190 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 161 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 191 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) { | 162 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) |
| 192 | return rval; | 163 | return rval; |
| 193 | } | ||
| 194 | XFS_STATS_INC(xs_dir_create); | 164 | XFS_STATS_INC(xs_dir_create); |
| 195 | /* | 165 | |
| 196 | * Fill in the arg structure for this request. | ||
| 197 | */ | ||
| 198 | args.name = name; | 166 | args.name = name; |
| 199 | args.namelen = namelen; | 167 | args.namelen = namelen; |
| 200 | args.hashval = xfs_da_hashname(name, namelen); | 168 | args.hashval = xfs_da_hashname(name, namelen); |
| @@ -207,18 +175,16 @@ xfs_dir2_createname( | |||
| 207 | args.trans = tp; | 175 | args.trans = tp; |
| 208 | args.justcheck = 0; | 176 | args.justcheck = 0; |
| 209 | args.addname = args.oknoent = 1; | 177 | args.addname = args.oknoent = 1; |
| 210 | /* | 178 | |
| 211 | * Decide on what work routines to call based on the inode size. | ||
| 212 | */ | ||
| 213 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 179 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 214 | rval = xfs_dir2_sf_addname(&args); | 180 | rval = xfs_dir2_sf_addname(&args); |
| 215 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { | 181 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
| 216 | return rval; | 182 | return rval; |
| 217 | } else if (v) | 183 | else if (v) |
| 218 | rval = xfs_dir2_block_addname(&args); | 184 | rval = xfs_dir2_block_addname(&args); |
| 219 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { | 185 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) |
| 220 | return rval; | 186 | return rval; |
| 221 | } else if (v) | 187 | else if (v) |
| 222 | rval = xfs_dir2_leaf_addname(&args); | 188 | rval = xfs_dir2_leaf_addname(&args); |
| 223 | else | 189 | else |
| 224 | rval = xfs_dir2_node_addname(&args); | 190 | rval = xfs_dir2_node_addname(&args); |
| @@ -228,24 +194,21 @@ xfs_dir2_createname( | |||
| 228 | /* | 194 | /* |
| 229 | * Lookup a name in a directory, give back the inode number. | 195 | * Lookup a name in a directory, give back the inode number. |
| 230 | */ | 196 | */ |
| 231 | static int /* error */ | 197 | int |
| 232 | xfs_dir2_lookup( | 198 | xfs_dir_lookup( |
| 233 | xfs_trans_t *tp, /* transaction pointer */ | 199 | xfs_trans_t *tp, |
| 234 | xfs_inode_t *dp, /* incore directory inode */ | 200 | xfs_inode_t *dp, |
| 235 | char *name, /* lookup name */ | 201 | char *name, |
| 236 | int namelen, /* lookup name length */ | 202 | int namelen, |
| 237 | xfs_ino_t *inum) /* out: inode number */ | 203 | xfs_ino_t *inum) /* out: inode number */ |
| 238 | { | 204 | { |
| 239 | xfs_da_args_t args; /* operation arguments */ | 205 | xfs_da_args_t args; |
| 240 | int rval; /* return value */ | 206 | int rval; |
| 241 | int v; /* type-checking value */ | 207 | int v; /* type-checking value */ |
| 242 | 208 | ||
| 243 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 209 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 244 | XFS_STATS_INC(xs_dir_lookup); | 210 | XFS_STATS_INC(xs_dir_lookup); |
| 245 | 211 | ||
| 246 | /* | ||
| 247 | * Fill in the arg structure for this request. | ||
| 248 | */ | ||
| 249 | args.name = name; | 212 | args.name = name; |
| 250 | args.namelen = namelen; | 213 | args.namelen = namelen; |
| 251 | args.hashval = xfs_da_hashname(name, namelen); | 214 | args.hashval = xfs_da_hashname(name, namelen); |
| @@ -258,18 +221,16 @@ xfs_dir2_lookup( | |||
| 258 | args.trans = tp; | 221 | args.trans = tp; |
| 259 | args.justcheck = args.addname = 0; | 222 | args.justcheck = args.addname = 0; |
| 260 | args.oknoent = 1; | 223 | args.oknoent = 1; |
| 261 | /* | 224 | |
| 262 | * Decide on what work routines to call based on the inode size. | ||
| 263 | */ | ||
| 264 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 225 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 265 | rval = xfs_dir2_sf_lookup(&args); | 226 | rval = xfs_dir2_sf_lookup(&args); |
| 266 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { | 227 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
| 267 | return rval; | 228 | return rval; |
| 268 | } else if (v) | 229 | else if (v) |
| 269 | rval = xfs_dir2_block_lookup(&args); | 230 | rval = xfs_dir2_block_lookup(&args); |
| 270 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { | 231 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) |
| 271 | return rval; | 232 | return rval; |
| 272 | } else if (v) | 233 | else if (v) |
| 273 | rval = xfs_dir2_leaf_lookup(&args); | 234 | rval = xfs_dir2_leaf_lookup(&args); |
| 274 | else | 235 | else |
| 275 | rval = xfs_dir2_node_lookup(&args); | 236 | rval = xfs_dir2_node_lookup(&args); |
| @@ -283,26 +244,24 @@ xfs_dir2_lookup( | |||
| 283 | /* | 244 | /* |
| 284 | * Remove an entry from a directory. | 245 | * Remove an entry from a directory. |
| 285 | */ | 246 | */ |
| 286 | static int /* error */ | 247 | int |
| 287 | xfs_dir2_removename( | 248 | xfs_dir_removename( |
| 288 | xfs_trans_t *tp, /* transaction pointer */ | 249 | xfs_trans_t *tp, |
| 289 | xfs_inode_t *dp, /* incore directory inode */ | 250 | xfs_inode_t *dp, |
| 290 | char *name, /* name of entry to remove */ | 251 | char *name, |
| 291 | int namelen, /* name length of entry to remove */ | 252 | int namelen, |
| 292 | xfs_ino_t ino, /* inode number of entry to remove */ | 253 | xfs_ino_t ino, |
| 293 | xfs_fsblock_t *first, /* bmap's firstblock */ | 254 | xfs_fsblock_t *first, /* bmap's firstblock */ |
| 294 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ | 255 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ |
| 295 | xfs_extlen_t total) /* bmap's total block count */ | 256 | xfs_extlen_t total) /* bmap's total block count */ |
| 296 | { | 257 | { |
| 297 | xfs_da_args_t args; /* operation arguments */ | 258 | xfs_da_args_t args; |
| 298 | int rval; /* return value */ | 259 | int rval; |
| 299 | int v; /* type-checking value */ | 260 | int v; /* type-checking value */ |
| 300 | 261 | ||
| 301 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 262 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 302 | XFS_STATS_INC(xs_dir_remove); | 263 | XFS_STATS_INC(xs_dir_remove); |
| 303 | /* | 264 | |
| 304 | * Fill in the arg structure for this request. | ||
| 305 | */ | ||
| 306 | args.name = name; | 265 | args.name = name; |
| 307 | args.namelen = namelen; | 266 | args.namelen = namelen; |
| 308 | args.hashval = xfs_da_hashname(name, namelen); | 267 | args.hashval = xfs_da_hashname(name, namelen); |
| @@ -314,18 +273,16 @@ xfs_dir2_removename( | |||
| 314 | args.whichfork = XFS_DATA_FORK; | 273 | args.whichfork = XFS_DATA_FORK; |
| 315 | args.trans = tp; | 274 | args.trans = tp; |
| 316 | args.justcheck = args.addname = args.oknoent = 0; | 275 | args.justcheck = args.addname = args.oknoent = 0; |
| 317 | /* | 276 | |
| 318 | * Decide on what work routines to call based on the inode size. | ||
| 319 | */ | ||
| 320 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 277 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 321 | rval = xfs_dir2_sf_removename(&args); | 278 | rval = xfs_dir2_sf_removename(&args); |
| 322 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { | 279 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
| 323 | return rval; | 280 | return rval; |
| 324 | } else if (v) | 281 | else if (v) |
| 325 | rval = xfs_dir2_block_removename(&args); | 282 | rval = xfs_dir2_block_removename(&args); |
| 326 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { | 283 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) |
| 327 | return rval; | 284 | return rval; |
| 328 | } else if (v) | 285 | else if (v) |
| 329 | rval = xfs_dir2_leaf_removename(&args); | 286 | rval = xfs_dir2_leaf_removename(&args); |
| 330 | else | 287 | else |
| 331 | rval = xfs_dir2_node_removename(&args); | 288 | rval = xfs_dir2_node_removename(&args); |
| @@ -335,10 +292,10 @@ xfs_dir2_removename( | |||
| 335 | /* | 292 | /* |
| 336 | * Read a directory. | 293 | * Read a directory. |
| 337 | */ | 294 | */ |
| 338 | static int /* error */ | 295 | int |
| 339 | xfs_dir2_getdents( | 296 | xfs_dir_getdents( |
| 340 | xfs_trans_t *tp, /* transaction pointer */ | 297 | xfs_trans_t *tp, |
| 341 | xfs_inode_t *dp, /* incore directory inode */ | 298 | xfs_inode_t *dp, |
| 342 | uio_t *uio, /* caller's buffer control */ | 299 | uio_t *uio, /* caller's buffer control */ |
| 343 | int *eofp) /* out: eof reached */ | 300 | int *eofp) /* out: eof reached */ |
| 344 | { | 301 | { |
| @@ -367,14 +324,11 @@ xfs_dir2_getdents( | |||
| 367 | } | 324 | } |
| 368 | 325 | ||
| 369 | *eofp = 0; | 326 | *eofp = 0; |
| 370 | /* | ||
| 371 | * Decide on what work routines to call based on the inode size. | ||
| 372 | */ | ||
| 373 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 327 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 374 | rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put); | 328 | rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put); |
| 375 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { | 329 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
| 376 | ; | 330 | ; |
| 377 | } else if (v) | 331 | else if (v) |
| 378 | rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put); | 332 | rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put); |
| 379 | else | 333 | else |
| 380 | rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put); | 334 | rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put); |
| @@ -386,29 +340,26 @@ xfs_dir2_getdents( | |||
| 386 | /* | 340 | /* |
| 387 | * Replace the inode number of a directory entry. | 341 | * Replace the inode number of a directory entry. |
| 388 | */ | 342 | */ |
| 389 | static int /* error */ | 343 | int |
| 390 | xfs_dir2_replace( | 344 | xfs_dir_replace( |
| 391 | xfs_trans_t *tp, /* transaction pointer */ | 345 | xfs_trans_t *tp, |
| 392 | xfs_inode_t *dp, /* incore directory inode */ | 346 | xfs_inode_t *dp, |
| 393 | char *name, /* name of entry to replace */ | 347 | char *name, /* name of entry to replace */ |
| 394 | int namelen, /* name length of entry to replace */ | 348 | int namelen, |
| 395 | xfs_ino_t inum, /* new inode number */ | 349 | xfs_ino_t inum, /* new inode number */ |
| 396 | xfs_fsblock_t *first, /* bmap's firstblock */ | 350 | xfs_fsblock_t *first, /* bmap's firstblock */ |
| 397 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ | 351 | xfs_bmap_free_t *flist, /* bmap's freeblock list */ |
| 398 | xfs_extlen_t total) /* bmap's total block count */ | 352 | xfs_extlen_t total) /* bmap's total block count */ |
| 399 | { | 353 | { |
| 400 | xfs_da_args_t args; /* operation arguments */ | 354 | xfs_da_args_t args; |
| 401 | int rval; /* return value */ | 355 | int rval; |
| 402 | int v; /* type-checking value */ | 356 | int v; /* type-checking value */ |
| 403 | 357 | ||
| 404 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 358 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 405 | 359 | ||
| 406 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) { | 360 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) |
| 407 | return rval; | 361 | return rval; |
| 408 | } | 362 | |
| 409 | /* | ||
| 410 | * Fill in the arg structure for this request. | ||
| 411 | */ | ||
| 412 | args.name = name; | 363 | args.name = name; |
| 413 | args.namelen = namelen; | 364 | args.namelen = namelen; |
| 414 | args.hashval = xfs_da_hashname(name, namelen); | 365 | args.hashval = xfs_da_hashname(name, namelen); |
| @@ -420,18 +371,16 @@ xfs_dir2_replace( | |||
| 420 | args.whichfork = XFS_DATA_FORK; | 371 | args.whichfork = XFS_DATA_FORK; |
| 421 | args.trans = tp; | 372 | args.trans = tp; |
| 422 | args.justcheck = args.addname = args.oknoent = 0; | 373 | args.justcheck = args.addname = args.oknoent = 0; |
| 423 | /* | 374 | |
| 424 | * Decide on what work routines to call based on the inode size. | ||
| 425 | */ | ||
| 426 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 375 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 427 | rval = xfs_dir2_sf_replace(&args); | 376 | rval = xfs_dir2_sf_replace(&args); |
| 428 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { | 377 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
| 429 | return rval; | 378 | return rval; |
| 430 | } else if (v) | 379 | else if (v) |
| 431 | rval = xfs_dir2_block_replace(&args); | 380 | rval = xfs_dir2_block_replace(&args); |
| 432 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { | 381 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) |
| 433 | return rval; | 382 | return rval; |
| 434 | } else if (v) | 383 | else if (v) |
| 435 | rval = xfs_dir2_leaf_replace(&args); | 384 | rval = xfs_dir2_leaf_replace(&args); |
| 436 | else | 385 | else |
| 437 | rval = xfs_dir2_node_replace(&args); | 386 | rval = xfs_dir2_node_replace(&args); |
| @@ -441,21 +390,19 @@ xfs_dir2_replace( | |||
| 441 | /* | 390 | /* |
| 442 | * See if this entry can be added to the directory without allocating space. | 391 | * See if this entry can be added to the directory without allocating space. |
| 443 | */ | 392 | */ |
| 444 | static int /* error */ | 393 | int |
| 445 | xfs_dir2_canenter( | 394 | xfs_dir_canenter( |
| 446 | xfs_trans_t *tp, /* transaction pointer */ | 395 | xfs_trans_t *tp, |
| 447 | xfs_inode_t *dp, /* incore directory inode */ | 396 | xfs_inode_t *dp, |
| 448 | char *name, /* name of entry to add */ | 397 | char *name, /* name of entry to add */ |
| 449 | int namelen) /* name length of entry to add */ | 398 | int namelen) |
| 450 | { | 399 | { |
| 451 | xfs_da_args_t args; /* operation arguments */ | 400 | xfs_da_args_t args; |
| 452 | int rval; /* return value */ | 401 | int rval; |
| 453 | int v; /* type-checking value */ | 402 | int v; /* type-checking value */ |
| 454 | 403 | ||
| 455 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 404 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 456 | /* | 405 | |
| 457 | * Fill in the arg structure for this request. | ||
| 458 | */ | ||
| 459 | args.name = name; | 406 | args.name = name; |
| 460 | args.namelen = namelen; | 407 | args.namelen = namelen; |
| 461 | args.hashval = xfs_da_hashname(name, namelen); | 408 | args.hashval = xfs_da_hashname(name, namelen); |
| @@ -467,18 +414,16 @@ xfs_dir2_canenter( | |||
| 467 | args.whichfork = XFS_DATA_FORK; | 414 | args.whichfork = XFS_DATA_FORK; |
| 468 | args.trans = tp; | 415 | args.trans = tp; |
| 469 | args.justcheck = args.addname = args.oknoent = 1; | 416 | args.justcheck = args.addname = args.oknoent = 1; |
| 470 | /* | 417 | |
| 471 | * Decide on what work routines to call based on the inode size. | ||
| 472 | */ | ||
| 473 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 418 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 474 | rval = xfs_dir2_sf_addname(&args); | 419 | rval = xfs_dir2_sf_addname(&args); |
| 475 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { | 420 | else if ((rval = xfs_dir2_isblock(tp, dp, &v))) |
| 476 | return rval; | 421 | return rval; |
| 477 | } else if (v) | 422 | else if (v) |
| 478 | rval = xfs_dir2_block_addname(&args); | 423 | rval = xfs_dir2_block_addname(&args); |
| 479 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { | 424 | else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) |
| 480 | return rval; | 425 | return rval; |
| 481 | } else if (v) | 426 | else if (v) |
| 482 | rval = xfs_dir2_leaf_addname(&args); | 427 | rval = xfs_dir2_leaf_addname(&args); |
| 483 | else | 428 | else |
| 484 | rval = xfs_dir2_node_addname(&args); | 429 | rval = xfs_dir2_node_addname(&args); |
| @@ -486,19 +431,6 @@ xfs_dir2_canenter( | |||
| 486 | } | 431 | } |
| 487 | 432 | ||
| 488 | /* | 433 | /* |
| 489 | * Dummy routine for shortform inode validation. | ||
| 490 | * Can't really do this. | ||
| 491 | */ | ||
| 492 | /* ARGSUSED */ | ||
| 493 | static int /* error */ | ||
| 494 | xfs_dir2_shortform_validate_ondisk( | ||
| 495 | xfs_mount_t *mp, /* filesystem mount point */ | ||
| 496 | xfs_dinode_t *dip) /* ondisk inode */ | ||
| 497 | { | ||
| 498 | return 0; | ||
| 499 | } | ||
| 500 | |||
| 501 | /* | ||
| 502 | * Utility routines. | 434 | * Utility routines. |
| 503 | */ | 435 | */ |
| 504 | 436 | ||
| @@ -507,24 +439,24 @@ xfs_dir2_shortform_validate_ondisk( | |||
| 507 | * This routine is for data and free blocks, not leaf/node blocks | 439 | * This routine is for data and free blocks, not leaf/node blocks |
| 508 | * which are handled by xfs_da_grow_inode. | 440 | * which are handled by xfs_da_grow_inode. |
| 509 | */ | 441 | */ |
| 510 | int /* error */ | 442 | int |
| 511 | xfs_dir2_grow_inode( | 443 | xfs_dir2_grow_inode( |
| 512 | xfs_da_args_t *args, /* operation arguments */ | 444 | xfs_da_args_t *args, |
| 513 | int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ | 445 | int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ |
| 514 | xfs_dir2_db_t *dbp) /* out: block number added */ | 446 | xfs_dir2_db_t *dbp) /* out: block number added */ |
| 515 | { | 447 | { |
| 516 | xfs_fileoff_t bno; /* directory offset of new block */ | 448 | xfs_fileoff_t bno; /* directory offset of new block */ |
| 517 | int count; /* count of filesystem blocks */ | 449 | int count; /* count of filesystem blocks */ |
| 518 | xfs_inode_t *dp; /* incore directory inode */ | 450 | xfs_inode_t *dp; /* incore directory inode */ |
| 519 | int error; /* error return value */ | 451 | int error; |
| 520 | int got; /* blocks actually mapped */ | 452 | int got; /* blocks actually mapped */ |
| 521 | int i; /* temp mapping index */ | 453 | int i; |
| 522 | xfs_bmbt_irec_t map; /* single structure for bmap */ | 454 | xfs_bmbt_irec_t map; /* single structure for bmap */ |
| 523 | int mapi; /* mapping index */ | 455 | int mapi; /* mapping index */ |
| 524 | xfs_bmbt_irec_t *mapp; /* bmap mapping structure(s) */ | 456 | xfs_bmbt_irec_t *mapp; /* bmap mapping structure(s) */ |
| 525 | xfs_mount_t *mp; /* filesystem mount point */ | 457 | xfs_mount_t *mp; |
| 526 | int nmap; /* number of bmap entries */ | 458 | int nmap; /* number of bmap entries */ |
| 527 | xfs_trans_t *tp; /* transaction pointer */ | 459 | xfs_trans_t *tp; |
| 528 | 460 | ||
| 529 | xfs_dir2_trace_args_s("grow_inode", args, space); | 461 | xfs_dir2_trace_args_s("grow_inode", args, space); |
| 530 | dp = args->dp; | 462 | dp = args->dp; |
| @@ -538,9 +470,8 @@ xfs_dir2_grow_inode( | |||
| 538 | /* | 470 | /* |
| 539 | * Find the first hole for our block. | 471 | * Find the first hole for our block. |
| 540 | */ | 472 | */ |
| 541 | if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK))) { | 473 | if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK))) |
| 542 | return error; | 474 | return error; |
| 543 | } | ||
| 544 | nmap = 1; | 475 | nmap = 1; |
| 545 | ASSERT(args->firstblock != NULL); | 476 | ASSERT(args->firstblock != NULL); |
| 546 | /* | 477 | /* |
| @@ -549,13 +480,9 @@ xfs_dir2_grow_inode( | |||
| 549 | if ((error = xfs_bmapi(tp, dp, bno, count, | 480 | if ((error = xfs_bmapi(tp, dp, bno, count, |
| 550 | XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, | 481 | XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, |
| 551 | args->firstblock, args->total, &map, &nmap, | 482 | args->firstblock, args->total, &map, &nmap, |
| 552 | args->flist))) { | 483 | args->flist, NULL))) |
| 553 | return error; | 484 | return error; |
| 554 | } | ||
| 555 | ASSERT(nmap <= 1); | 485 | ASSERT(nmap <= 1); |
| 556 | /* | ||
| 557 | * Got it in 1. | ||
| 558 | */ | ||
| 559 | if (nmap == 1) { | 486 | if (nmap == 1) { |
| 560 | mapp = ↦ | 487 | mapp = ↦ |
| 561 | mapi = 1; | 488 | mapi = 1; |
| @@ -585,7 +512,8 @@ xfs_dir2_grow_inode( | |||
| 585 | if ((error = xfs_bmapi(tp, dp, b, c, | 512 | if ((error = xfs_bmapi(tp, dp, b, c, |
| 586 | XFS_BMAPI_WRITE|XFS_BMAPI_METADATA, | 513 | XFS_BMAPI_WRITE|XFS_BMAPI_METADATA, |
| 587 | args->firstblock, args->total, | 514 | args->firstblock, args->total, |
| 588 | &mapp[mapi], &nmap, args->flist))) { | 515 | &mapp[mapi], &nmap, args->flist, |
| 516 | NULL))) { | ||
| 589 | kmem_free(mapp, sizeof(*mapp) * count); | 517 | kmem_free(mapp, sizeof(*mapp) * count); |
| 590 | return error; | 518 | return error; |
| 591 | } | 519 | } |
| @@ -645,20 +573,19 @@ xfs_dir2_grow_inode( | |||
| 645 | /* | 573 | /* |
| 646 | * See if the directory is a single-block form directory. | 574 | * See if the directory is a single-block form directory. |
| 647 | */ | 575 | */ |
| 648 | int /* error */ | 576 | int |
| 649 | xfs_dir2_isblock( | 577 | xfs_dir2_isblock( |
| 650 | xfs_trans_t *tp, /* transaction pointer */ | 578 | xfs_trans_t *tp, |
| 651 | xfs_inode_t *dp, /* incore directory inode */ | 579 | xfs_inode_t *dp, |
| 652 | int *vp) /* out: 1 is block, 0 is not block */ | 580 | int *vp) /* out: 1 is block, 0 is not block */ |
| 653 | { | 581 | { |
| 654 | xfs_fileoff_t last; /* last file offset */ | 582 | xfs_fileoff_t last; /* last file offset */ |
| 655 | xfs_mount_t *mp; /* filesystem mount point */ | 583 | xfs_mount_t *mp; |
| 656 | int rval; /* return value */ | 584 | int rval; |
| 657 | 585 | ||
| 658 | mp = dp->i_mount; | 586 | mp = dp->i_mount; |
| 659 | if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) { | 587 | if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) |
| 660 | return rval; | 588 | return rval; |
| 661 | } | ||
| 662 | rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize; | 589 | rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize; |
| 663 | ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize); | 590 | ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize); |
| 664 | *vp = rval; | 591 | *vp = rval; |
| @@ -668,20 +595,19 @@ xfs_dir2_isblock( | |||
| 668 | /* | 595 | /* |
| 669 | * See if the directory is a single-leaf form directory. | 596 | * See if the directory is a single-leaf form directory. |
| 670 | */ | 597 | */ |
| 671 | int /* error */ | 598 | int |
| 672 | xfs_dir2_isleaf( | 599 | xfs_dir2_isleaf( |
| 673 | xfs_trans_t *tp, /* transaction pointer */ | 600 | xfs_trans_t *tp, |
| 674 | xfs_inode_t *dp, /* incore directory inode */ | 601 | xfs_inode_t *dp, |
| 675 | int *vp) /* out: 1 is leaf, 0 is not leaf */ | 602 | int *vp) /* out: 1 is leaf, 0 is not leaf */ |
| 676 | { | 603 | { |
| 677 | xfs_fileoff_t last; /* last file offset */ | 604 | xfs_fileoff_t last; /* last file offset */ |
| 678 | xfs_mount_t *mp; /* filesystem mount point */ | 605 | xfs_mount_t *mp; |
| 679 | int rval; /* return value */ | 606 | int rval; |
| 680 | 607 | ||
| 681 | mp = dp->i_mount; | 608 | mp = dp->i_mount; |
| 682 | if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) { | 609 | if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) |
| 683 | return rval; | 610 | return rval; |
| 684 | } | ||
| 685 | *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog); | 611 | *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog); |
| 686 | return 0; | 612 | return 0; |
| 687 | } | 613 | } |
| @@ -689,9 +615,9 @@ xfs_dir2_isleaf( | |||
| 689 | /* | 615 | /* |
| 690 | * Getdents put routine for 64-bit ABI, direct form. | 616 | * Getdents put routine for 64-bit ABI, direct form. |
| 691 | */ | 617 | */ |
| 692 | static int /* error */ | 618 | static int |
| 693 | xfs_dir2_put_dirent64_direct( | 619 | xfs_dir2_put_dirent64_direct( |
| 694 | xfs_dir2_put_args_t *pa) /* argument bundle */ | 620 | xfs_dir2_put_args_t *pa) |
| 695 | { | 621 | { |
| 696 | xfs_dirent_t *idbp; /* dirent pointer */ | 622 | xfs_dirent_t *idbp; /* dirent pointer */ |
| 697 | iovec_t *iovp; /* io vector */ | 623 | iovec_t *iovp; /* io vector */ |
| @@ -726,9 +652,9 @@ xfs_dir2_put_dirent64_direct( | |||
| 726 | /* | 652 | /* |
| 727 | * Getdents put routine for 64-bit ABI, uio form. | 653 | * Getdents put routine for 64-bit ABI, uio form. |
| 728 | */ | 654 | */ |
| 729 | static int /* error */ | 655 | static int |
| 730 | xfs_dir2_put_dirent64_uio( | 656 | xfs_dir2_put_dirent64_uio( |
| 731 | xfs_dir2_put_args_t *pa) /* argument bundle */ | 657 | xfs_dir2_put_args_t *pa) |
| 732 | { | 658 | { |
| 733 | xfs_dirent_t *idbp; /* dirent pointer */ | 659 | xfs_dirent_t *idbp; /* dirent pointer */ |
| 734 | int namelen; /* entry name length */ | 660 | int namelen; /* entry name length */ |
| @@ -764,17 +690,17 @@ xfs_dir2_put_dirent64_uio( | |||
| 764 | */ | 690 | */ |
| 765 | int | 691 | int |
| 766 | xfs_dir2_shrink_inode( | 692 | xfs_dir2_shrink_inode( |
| 767 | xfs_da_args_t *args, /* operation arguments */ | 693 | xfs_da_args_t *args, |
| 768 | xfs_dir2_db_t db, /* directory block number */ | 694 | xfs_dir2_db_t db, |
| 769 | xfs_dabuf_t *bp) /* block's buffer */ | 695 | xfs_dabuf_t *bp) |
| 770 | { | 696 | { |
| 771 | xfs_fileoff_t bno; /* directory file offset */ | 697 | xfs_fileoff_t bno; /* directory file offset */ |
| 772 | xfs_dablk_t da; /* directory file offset */ | 698 | xfs_dablk_t da; /* directory file offset */ |
| 773 | int done; /* bunmap is finished */ | 699 | int done; /* bunmap is finished */ |
| 774 | xfs_inode_t *dp; /* incore directory inode */ | 700 | xfs_inode_t *dp; |
| 775 | int error; /* error return value */ | 701 | int error; |
| 776 | xfs_mount_t *mp; /* filesystem mount point */ | 702 | xfs_mount_t *mp; |
| 777 | xfs_trans_t *tp; /* transaction pointer */ | 703 | xfs_trans_t *tp; |
| 778 | 704 | ||
| 779 | xfs_dir2_trace_args_db("shrink_inode", args, db, bp); | 705 | xfs_dir2_trace_args_db("shrink_inode", args, db, bp); |
| 780 | dp = args->dp; | 706 | dp = args->dp; |
| @@ -786,7 +712,7 @@ xfs_dir2_shrink_inode( | |||
| 786 | */ | 712 | */ |
| 787 | if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs, | 713 | if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs, |
| 788 | XFS_BMAPI_METADATA, 0, args->firstblock, args->flist, | 714 | XFS_BMAPI_METADATA, 0, args->firstblock, args->flist, |
| 789 | &done))) { | 715 | NULL, &done))) { |
| 790 | /* | 716 | /* |
| 791 | * ENOSPC actually can happen if we're in a removename with | 717 | * ENOSPC actually can happen if we're in a removename with |
| 792 | * no space reservation, and the resulting block removal | 718 | * no space reservation, and the resulting block removal |
diff --git a/fs/xfs/xfs_dir2.h b/fs/xfs/xfs_dir2.h index 7dd364b1e038..86560b6f794c 100644 --- a/fs/xfs/xfs_dir2.h +++ b/fs/xfs/xfs_dir2.h | |||
| @@ -22,7 +22,9 @@ struct uio; | |||
| 22 | struct xfs_dabuf; | 22 | struct xfs_dabuf; |
| 23 | struct xfs_da_args; | 23 | struct xfs_da_args; |
| 24 | struct xfs_dir2_put_args; | 24 | struct xfs_dir2_put_args; |
| 25 | struct xfs_bmap_free; | ||
| 25 | struct xfs_inode; | 26 | struct xfs_inode; |
| 27 | struct xfs_mount; | ||
| 26 | struct xfs_trans; | 28 | struct xfs_trans; |
| 27 | 29 | ||
| 28 | /* | 30 | /* |
| @@ -73,7 +75,35 @@ typedef struct xfs_dir2_put_args { | |||
| 73 | } xfs_dir2_put_args_t; | 75 | } xfs_dir2_put_args_t; |
| 74 | 76 | ||
| 75 | /* | 77 | /* |
| 76 | * Other interfaces used by the rest of the dir v2 code. | 78 | * Generic directory interface routines |
| 79 | */ | ||
| 80 | extern void xfs_dir_startup(void); | ||
| 81 | extern void xfs_dir_mount(struct xfs_mount *mp); | ||
| 82 | extern int xfs_dir_isempty(struct xfs_inode *dp); | ||
| 83 | extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp, | ||
| 84 | struct xfs_inode *pdp); | ||
| 85 | extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp, | ||
| 86 | char *name, int namelen, xfs_ino_t inum, | ||
| 87 | xfs_fsblock_t *first, | ||
| 88 | struct xfs_bmap_free *flist, xfs_extlen_t tot); | ||
| 89 | extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp, | ||
| 90 | char *name, int namelen, xfs_ino_t *inum); | ||
| 91 | extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, | ||
| 92 | char *name, int namelen, xfs_ino_t ino, | ||
| 93 | xfs_fsblock_t *first, | ||
| 94 | struct xfs_bmap_free *flist, xfs_extlen_t tot); | ||
| 95 | extern int xfs_dir_getdents(struct xfs_trans *tp, struct xfs_inode *dp, | ||
| 96 | uio_t *uio, int *eofp); | ||
| 97 | extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp, | ||
| 98 | char *name, int namelen, xfs_ino_t inum, | ||
| 99 | xfs_fsblock_t *first, | ||
| 100 | struct xfs_bmap_free *flist, xfs_extlen_t tot); | ||
| 101 | extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp, | ||
| 102 | char *name, int namelen); | ||
| 103 | extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); | ||
| 104 | |||
| 105 | /* | ||
| 106 | * Utility routines for v2 directories. | ||
| 77 | */ | 107 | */ |
| 78 | extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space, | 108 | extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space, |
| 79 | xfs_dir2_db_t *dbp); | 109 | xfs_dir2_db_t *dbp); |
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index 972ded595476..9d7438bba30d 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c | |||
| @@ -22,19 +22,16 @@ | |||
| 22 | #include "xfs_inum.h" | 22 | #include "xfs_inum.h" |
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_dir.h" | ||
| 26 | #include "xfs_dir2.h" | 25 | #include "xfs_dir2.h" |
| 27 | #include "xfs_dmapi.h" | 26 | #include "xfs_dmapi.h" |
| 28 | #include "xfs_mount.h" | 27 | #include "xfs_mount.h" |
| 29 | #include "xfs_da_btree.h" | 28 | #include "xfs_da_btree.h" |
| 30 | #include "xfs_bmap_btree.h" | 29 | #include "xfs_bmap_btree.h" |
| 31 | #include "xfs_dir_sf.h" | ||
| 32 | #include "xfs_dir2_sf.h" | 30 | #include "xfs_dir2_sf.h" |
| 33 | #include "xfs_attr_sf.h" | 31 | #include "xfs_attr_sf.h" |
| 34 | #include "xfs_dinode.h" | 32 | #include "xfs_dinode.h" |
| 35 | #include "xfs_inode.h" | 33 | #include "xfs_inode.h" |
| 36 | #include "xfs_inode_item.h" | 34 | #include "xfs_inode_item.h" |
| 37 | #include "xfs_dir_leaf.h" | ||
| 38 | #include "xfs_dir2_data.h" | 35 | #include "xfs_dir2_data.h" |
| 39 | #include "xfs_dir2_leaf.h" | 36 | #include "xfs_dir2_leaf.h" |
| 40 | #include "xfs_dir2_block.h" | 37 | #include "xfs_dir2_block.h" |
| @@ -51,6 +48,18 @@ static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **bpp, | |||
| 51 | int *entno); | 48 | int *entno); |
| 52 | static int xfs_dir2_block_sort(const void *a, const void *b); | 49 | static int xfs_dir2_block_sort(const void *a, const void *b); |
| 53 | 50 | ||
| 51 | static xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; | ||
| 52 | |||
| 53 | /* | ||
| 54 | * One-time startup routine called from xfs_init(). | ||
| 55 | */ | ||
| 56 | void | ||
| 57 | xfs_dir_startup(void) | ||
| 58 | { | ||
| 59 | xfs_dir_hash_dot = xfs_da_hashname(".", 1); | ||
| 60 | xfs_dir_hash_dotdot = xfs_da_hashname("..", 2); | ||
| 61 | } | ||
| 62 | |||
| 54 | /* | 63 | /* |
| 55 | * Add an entry to a block directory. | 64 | * Add an entry to a block directory. |
| 56 | */ | 65 | */ |
| @@ -400,7 +409,7 @@ xfs_dir2_block_addname( | |||
| 400 | /* | 409 | /* |
| 401 | * Create the new data entry. | 410 | * Create the new data entry. |
| 402 | */ | 411 | */ |
| 403 | INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); | 412 | dep->inumber = cpu_to_be64(args->inumber); |
| 404 | dep->namelen = args->namelen; | 413 | dep->namelen = args->namelen; |
| 405 | memcpy(dep->name, args->name, args->namelen); | 414 | memcpy(dep->name, args->name, args->namelen); |
| 406 | tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); | 415 | tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); |
| @@ -508,7 +517,7 @@ xfs_dir2_block_getdents( | |||
| 508 | 517 | ||
| 509 | p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, | 518 | p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, |
| 510 | ptr - (char *)block); | 519 | ptr - (char *)block); |
| 511 | p.ino = INT_GET(dep->inumber, ARCH_CONVERT); | 520 | p.ino = be64_to_cpu(dep->inumber); |
| 512 | #if XFS_BIG_INUMS | 521 | #if XFS_BIG_INUMS |
| 513 | p.ino += mp->m_inoadd; | 522 | p.ino += mp->m_inoadd; |
| 514 | #endif | 523 | #endif |
| @@ -626,7 +635,7 @@ xfs_dir2_block_lookup( | |||
| 626 | /* | 635 | /* |
| 627 | * Fill in inode number, release the block. | 636 | * Fill in inode number, release the block. |
| 628 | */ | 637 | */ |
| 629 | args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); | 638 | args->inumber = be64_to_cpu(dep->inumber); |
| 630 | xfs_da_brelse(args->trans, bp); | 639 | xfs_da_brelse(args->trans, bp); |
| 631 | return XFS_ERROR(EEXIST); | 640 | return XFS_ERROR(EEXIST); |
| 632 | } | 641 | } |
| @@ -844,11 +853,11 @@ xfs_dir2_block_replace( | |||
| 844 | */ | 853 | */ |
| 845 | dep = (xfs_dir2_data_entry_t *) | 854 | dep = (xfs_dir2_data_entry_t *) |
| 846 | ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address))); | 855 | ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address))); |
| 847 | ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) != args->inumber); | 856 | ASSERT(be64_to_cpu(dep->inumber) != args->inumber); |
| 848 | /* | 857 | /* |
| 849 | * Change the inode number to the new value. | 858 | * Change the inode number to the new value. |
| 850 | */ | 859 | */ |
| 851 | INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); | 860 | dep->inumber = cpu_to_be64(args->inumber); |
| 852 | xfs_dir2_data_log_entry(args->trans, bp, dep); | 861 | xfs_dir2_data_log_entry(args->trans, bp, dep); |
| 853 | xfs_dir2_data_check(dp, bp); | 862 | xfs_dir2_data_check(dp, bp); |
| 854 | xfs_da_buf_done(bp); | 863 | xfs_da_buf_done(bp); |
| @@ -1130,7 +1139,7 @@ xfs_dir2_sf_to_block( | |||
| 1130 | */ | 1139 | */ |
| 1131 | dep = (xfs_dir2_data_entry_t *) | 1140 | dep = (xfs_dir2_data_entry_t *) |
| 1132 | ((char *)block + XFS_DIR2_DATA_DOT_OFFSET); | 1141 | ((char *)block + XFS_DIR2_DATA_DOT_OFFSET); |
| 1133 | INT_SET(dep->inumber, ARCH_CONVERT, dp->i_ino); | 1142 | dep->inumber = cpu_to_be64(dp->i_ino); |
| 1134 | dep->namelen = 1; | 1143 | dep->namelen = 1; |
| 1135 | dep->name[0] = '.'; | 1144 | dep->name[0] = '.'; |
| 1136 | tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); | 1145 | tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); |
| @@ -1144,7 +1153,7 @@ xfs_dir2_sf_to_block( | |||
| 1144 | */ | 1153 | */ |
| 1145 | dep = (xfs_dir2_data_entry_t *) | 1154 | dep = (xfs_dir2_data_entry_t *) |
| 1146 | ((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET); | 1155 | ((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET); |
| 1147 | INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent)); | 1156 | dep->inumber = cpu_to_be64(XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent)); |
| 1148 | dep->namelen = 2; | 1157 | dep->namelen = 2; |
| 1149 | dep->name[0] = dep->name[1] = '.'; | 1158 | dep->name[0] = dep->name[1] = '.'; |
| 1150 | tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); | 1159 | tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); |
| @@ -1193,7 +1202,7 @@ xfs_dir2_sf_to_block( | |||
| 1193 | * Copy a real entry. | 1202 | * Copy a real entry. |
| 1194 | */ | 1203 | */ |
| 1195 | dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset); | 1204 | dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset); |
| 1196 | INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER(sfp, | 1205 | dep->inumber = cpu_to_be64(XFS_DIR2_SF_GET_INUMBER(sfp, |
| 1197 | XFS_DIR2_SF_INUMBERP(sfep))); | 1206 | XFS_DIR2_SF_INUMBERP(sfep))); |
| 1198 | dep->namelen = sfep->namelen; | 1207 | dep->namelen = sfep->namelen; |
| 1199 | memcpy(dep->name, sfep->name, dep->namelen); | 1208 | memcpy(dep->name, sfep->name, dep->namelen); |
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c index bb3d03ff002b..f7c799217072 100644 --- a/fs/xfs/xfs_dir2_data.c +++ b/fs/xfs/xfs_dir2_data.c | |||
| @@ -22,18 +22,15 @@ | |||
| 22 | #include "xfs_inum.h" | 22 | #include "xfs_inum.h" |
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_dir.h" | ||
| 26 | #include "xfs_dir2.h" | 25 | #include "xfs_dir2.h" |
| 27 | #include "xfs_dmapi.h" | 26 | #include "xfs_dmapi.h" |
| 28 | #include "xfs_mount.h" | 27 | #include "xfs_mount.h" |
| 29 | #include "xfs_da_btree.h" | 28 | #include "xfs_da_btree.h" |
| 30 | #include "xfs_bmap_btree.h" | 29 | #include "xfs_bmap_btree.h" |
| 31 | #include "xfs_dir_sf.h" | ||
| 32 | #include "xfs_dir2_sf.h" | 30 | #include "xfs_dir2_sf.h" |
| 33 | #include "xfs_attr_sf.h" | 31 | #include "xfs_attr_sf.h" |
| 34 | #include "xfs_dinode.h" | 32 | #include "xfs_dinode.h" |
| 35 | #include "xfs_inode.h" | 33 | #include "xfs_inode.h" |
| 36 | #include "xfs_dir_leaf.h" | ||
| 37 | #include "xfs_dir2_data.h" | 34 | #include "xfs_dir2_data.h" |
| 38 | #include "xfs_dir2_leaf.h" | 35 | #include "xfs_dir2_leaf.h" |
| 39 | #include "xfs_dir2_block.h" | 36 | #include "xfs_dir2_block.h" |
| @@ -133,7 +130,7 @@ xfs_dir2_data_check( | |||
| 133 | */ | 130 | */ |
| 134 | dep = (xfs_dir2_data_entry_t *)p; | 131 | dep = (xfs_dir2_data_entry_t *)p; |
| 135 | ASSERT(dep->namelen != 0); | 132 | ASSERT(dep->namelen != 0); |
| 136 | ASSERT(xfs_dir_ino_validate(mp, INT_GET(dep->inumber, ARCH_CONVERT)) == 0); | 133 | ASSERT(xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)) == 0); |
| 137 | ASSERT(be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)) == | 134 | ASSERT(be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)) == |
| 138 | (char *)dep - (char *)d); | 135 | (char *)dep - (char *)d); |
| 139 | count++; | 136 | count++; |
diff --git a/fs/xfs/xfs_dir2_data.h b/fs/xfs/xfs_dir2_data.h index 0847cbb53e17..a6ae2d21c40a 100644 --- a/fs/xfs/xfs_dir2_data.h +++ b/fs/xfs/xfs_dir2_data.h | |||
| @@ -85,11 +85,11 @@ typedef struct xfs_dir2_data_hdr { | |||
| 85 | * Tag appears as the last 2 bytes. | 85 | * Tag appears as the last 2 bytes. |
| 86 | */ | 86 | */ |
| 87 | typedef struct xfs_dir2_data_entry { | 87 | typedef struct xfs_dir2_data_entry { |
| 88 | xfs_ino_t inumber; /* inode number */ | 88 | __be64 inumber; /* inode number */ |
| 89 | __uint8_t namelen; /* name length */ | 89 | __u8 namelen; /* name length */ |
| 90 | __uint8_t name[1]; /* name bytes, no null */ | 90 | __u8 name[1]; /* name bytes, no null */ |
| 91 | /* variable offset */ | 91 | /* variable offset */ |
| 92 | xfs_dir2_data_off_t tag; /* starting offset of us */ | 92 | __be16 tag; /* starting offset of us */ |
| 93 | } xfs_dir2_data_entry_t; | 93 | } xfs_dir2_data_entry_t; |
| 94 | 94 | ||
| 95 | /* | 95 | /* |
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 0f5e2f2ce6ec..b1cf1fbf423d 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_da_btree.h" | 30 | #include "xfs_da_btree.h" |
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_attr_sf.h" | 32 | #include "xfs_attr_sf.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_dinode.h" | 34 | #include "xfs_dinode.h" |
| 37 | #include "xfs_inode.h" | 35 | #include "xfs_inode.h" |
| @@ -407,7 +405,7 @@ xfs_dir2_leaf_addname( | |||
| 407 | * Initialize our new entry (at last). | 405 | * Initialize our new entry (at last). |
| 408 | */ | 406 | */ |
| 409 | dep = (xfs_dir2_data_entry_t *)dup; | 407 | dep = (xfs_dir2_data_entry_t *)dup; |
| 410 | INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); | 408 | dep->inumber = cpu_to_be64(args->inumber); |
| 411 | dep->namelen = args->namelen; | 409 | dep->namelen = args->namelen; |
| 412 | memcpy(dep->name, args->name, dep->namelen); | 410 | memcpy(dep->name, args->name, dep->namelen); |
| 413 | tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); | 411 | tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); |
| @@ -884,7 +882,7 @@ xfs_dir2_leaf_getdents( | |||
| 884 | XFS_DIR2_BYTE_TO_DA(mp, | 882 | XFS_DIR2_BYTE_TO_DA(mp, |
| 885 | XFS_DIR2_LEAF_OFFSET) - map_off, | 883 | XFS_DIR2_LEAF_OFFSET) - map_off, |
| 886 | XFS_BMAPI_METADATA, NULL, 0, | 884 | XFS_BMAPI_METADATA, NULL, 0, |
| 887 | &map[map_valid], &nmap, NULL); | 885 | &map[map_valid], &nmap, NULL, NULL); |
| 888 | /* | 886 | /* |
| 889 | * Don't know if we should ignore this or | 887 | * Don't know if we should ignore this or |
| 890 | * try to return an error. | 888 | * try to return an error. |
| @@ -1098,7 +1096,7 @@ xfs_dir2_leaf_getdents( | |||
| 1098 | 1096 | ||
| 1099 | p->cook = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff + length); | 1097 | p->cook = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff + length); |
| 1100 | 1098 | ||
| 1101 | p->ino = INT_GET(dep->inumber, ARCH_CONVERT); | 1099 | p->ino = be64_to_cpu(dep->inumber); |
| 1102 | #if XFS_BIG_INUMS | 1100 | #if XFS_BIG_INUMS |
| 1103 | p->ino += mp->m_inoadd; | 1101 | p->ino += mp->m_inoadd; |
| 1104 | #endif | 1102 | #endif |
| @@ -1319,7 +1317,7 @@ xfs_dir2_leaf_lookup( | |||
| 1319 | /* | 1317 | /* |
| 1320 | * Return the found inode number. | 1318 | * Return the found inode number. |
| 1321 | */ | 1319 | */ |
| 1322 | args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); | 1320 | args->inumber = be64_to_cpu(dep->inumber); |
| 1323 | xfs_da_brelse(tp, dbp); | 1321 | xfs_da_brelse(tp, dbp); |
| 1324 | xfs_da_brelse(tp, lbp); | 1322 | xfs_da_brelse(tp, lbp); |
| 1325 | return XFS_ERROR(EEXIST); | 1323 | return XFS_ERROR(EEXIST); |
| @@ -1606,11 +1604,11 @@ xfs_dir2_leaf_replace( | |||
| 1606 | dep = (xfs_dir2_data_entry_t *) | 1604 | dep = (xfs_dir2_data_entry_t *) |
| 1607 | ((char *)dbp->data + | 1605 | ((char *)dbp->data + |
| 1608 | XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, be32_to_cpu(lep->address))); | 1606 | XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, be32_to_cpu(lep->address))); |
| 1609 | ASSERT(args->inumber != INT_GET(dep->inumber, ARCH_CONVERT)); | 1607 | ASSERT(args->inumber != be64_to_cpu(dep->inumber)); |
| 1610 | /* | 1608 | /* |
| 1611 | * Put the new inode number in, log it. | 1609 | * Put the new inode number in, log it. |
| 1612 | */ | 1610 | */ |
| 1613 | INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); | 1611 | dep->inumber = cpu_to_be64(args->inumber); |
| 1614 | tp = args->trans; | 1612 | tp = args->trans; |
| 1615 | xfs_dir2_data_log_entry(tp, dbp, dep); | 1613 | xfs_dir2_data_log_entry(tp, dbp, dep); |
| 1616 | xfs_da_buf_done(dbp); | 1614 | xfs_da_buf_done(dbp); |
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index ac511ab9c52d..9ca71719b683 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c | |||
| @@ -22,13 +22,11 @@ | |||
| 22 | #include "xfs_inum.h" | 22 | #include "xfs_inum.h" |
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_dir.h" | ||
| 26 | #include "xfs_dir2.h" | 25 | #include "xfs_dir2.h" |
| 27 | #include "xfs_dmapi.h" | 26 | #include "xfs_dmapi.h" |
| 28 | #include "xfs_mount.h" | 27 | #include "xfs_mount.h" |
| 29 | #include "xfs_da_btree.h" | 28 | #include "xfs_da_btree.h" |
| 30 | #include "xfs_bmap_btree.h" | 29 | #include "xfs_bmap_btree.h" |
| 31 | #include "xfs_dir_sf.h" | ||
| 32 | #include "xfs_dir2_sf.h" | 30 | #include "xfs_dir2_sf.h" |
| 33 | #include "xfs_attr_sf.h" | 31 | #include "xfs_attr_sf.h" |
| 34 | #include "xfs_dinode.h" | 32 | #include "xfs_dinode.h" |
| @@ -505,7 +503,6 @@ xfs_dir2_leafn_lookup_int( | |||
| 505 | XFS_DATA_FORK))) { | 503 | XFS_DATA_FORK))) { |
| 506 | return error; | 504 | return error; |
| 507 | } | 505 | } |
| 508 | curfdb = newfdb; | ||
| 509 | free = curbp->data; | 506 | free = curbp->data; |
| 510 | ASSERT(be32_to_cpu(free->hdr.magic) == | 507 | ASSERT(be32_to_cpu(free->hdr.magic) == |
| 511 | XFS_DIR2_FREE_MAGIC); | 508 | XFS_DIR2_FREE_MAGIC); |
| @@ -527,8 +524,11 @@ xfs_dir2_leafn_lookup_int( | |||
| 527 | if (unlikely(be16_to_cpu(free->bests[fi]) == NULLDATAOFF)) { | 524 | if (unlikely(be16_to_cpu(free->bests[fi]) == NULLDATAOFF)) { |
| 528 | XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", | 525 | XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", |
| 529 | XFS_ERRLEVEL_LOW, mp); | 526 | XFS_ERRLEVEL_LOW, mp); |
| 527 | if (curfdb != newfdb) | ||
| 528 | xfs_da_brelse(tp, curbp); | ||
| 530 | return XFS_ERROR(EFSCORRUPTED); | 529 | return XFS_ERROR(EFSCORRUPTED); |
| 531 | } | 530 | } |
| 531 | curfdb = newfdb; | ||
| 532 | if (be16_to_cpu(free->bests[fi]) >= length) { | 532 | if (be16_to_cpu(free->bests[fi]) >= length) { |
| 533 | *indexp = index; | 533 | *indexp = index; |
| 534 | state->extravalid = 1; | 534 | state->extravalid = 1; |
| @@ -580,7 +580,7 @@ xfs_dir2_leafn_lookup_int( | |||
| 580 | if (dep->namelen == args->namelen && | 580 | if (dep->namelen == args->namelen && |
| 581 | dep->name[0] == args->name[0] && | 581 | dep->name[0] == args->name[0] && |
| 582 | memcmp(dep->name, args->name, args->namelen) == 0) { | 582 | memcmp(dep->name, args->name, args->namelen) == 0) { |
| 583 | args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); | 583 | args->inumber = be64_to_cpu(dep->inumber); |
| 584 | *indexp = index; | 584 | *indexp = index; |
| 585 | state->extravalid = 1; | 585 | state->extravalid = 1; |
| 586 | state->extrablk.bp = curbp; | 586 | state->extrablk.bp = curbp; |
| @@ -970,7 +970,7 @@ xfs_dir2_leafn_remove( | |||
| 970 | /* | 970 | /* |
| 971 | * One less used entry in the free table. | 971 | * One less used entry in the free table. |
| 972 | */ | 972 | */ |
| 973 | free->hdr.nused = cpu_to_be32(-1); | 973 | be32_add(&free->hdr.nused, -1); |
| 974 | xfs_dir2_free_log_header(tp, fbp); | 974 | xfs_dir2_free_log_header(tp, fbp); |
| 975 | /* | 975 | /* |
| 976 | * If this was the last entry in the table, we can | 976 | * If this was the last entry in the table, we can |
| @@ -1695,7 +1695,7 @@ xfs_dir2_node_addname_int( | |||
| 1695 | * Fill in the new entry and log it. | 1695 | * Fill in the new entry and log it. |
| 1696 | */ | 1696 | */ |
| 1697 | dep = (xfs_dir2_data_entry_t *)dup; | 1697 | dep = (xfs_dir2_data_entry_t *)dup; |
| 1698 | INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); | 1698 | dep->inumber = cpu_to_be64(args->inumber); |
| 1699 | dep->namelen = args->namelen; | 1699 | dep->namelen = args->namelen; |
| 1700 | memcpy(dep->name, args->name, dep->namelen); | 1700 | memcpy(dep->name, args->name, dep->namelen); |
| 1701 | tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); | 1701 | tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); |
| @@ -1905,11 +1905,11 @@ xfs_dir2_node_replace( | |||
| 1905 | dep = (xfs_dir2_data_entry_t *) | 1905 | dep = (xfs_dir2_data_entry_t *) |
| 1906 | ((char *)data + | 1906 | ((char *)data + |
| 1907 | XFS_DIR2_DATAPTR_TO_OFF(state->mp, be32_to_cpu(lep->address))); | 1907 | XFS_DIR2_DATAPTR_TO_OFF(state->mp, be32_to_cpu(lep->address))); |
| 1908 | ASSERT(inum != INT_GET(dep->inumber, ARCH_CONVERT)); | 1908 | ASSERT(inum != be64_to_cpu(dep->inumber)); |
| 1909 | /* | 1909 | /* |
| 1910 | * Fill in the new inode number and log the entry. | 1910 | * Fill in the new inode number and log the entry. |
| 1911 | */ | 1911 | */ |
| 1912 | INT_SET(dep->inumber, ARCH_CONVERT, inum); | 1912 | dep->inumber = cpu_to_be64(inum); |
| 1913 | xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep); | 1913 | xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep); |
| 1914 | rval = 0; | 1914 | rval = 0; |
| 1915 | } | 1915 | } |
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c index d98a41d1fe63..0cd77b17bf92 100644 --- a/fs/xfs/xfs_dir2_sf.c +++ b/fs/xfs/xfs_dir2_sf.c | |||
| @@ -22,19 +22,16 @@ | |||
| 22 | #include "xfs_inum.h" | 22 | #include "xfs_inum.h" |
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_dir.h" | ||
| 26 | #include "xfs_dir2.h" | 25 | #include "xfs_dir2.h" |
| 27 | #include "xfs_dmapi.h" | 26 | #include "xfs_dmapi.h" |
| 28 | #include "xfs_mount.h" | 27 | #include "xfs_mount.h" |
| 29 | #include "xfs_da_btree.h" | 28 | #include "xfs_da_btree.h" |
| 30 | #include "xfs_bmap_btree.h" | 29 | #include "xfs_bmap_btree.h" |
| 31 | #include "xfs_dir_sf.h" | ||
| 32 | #include "xfs_dir2_sf.h" | 30 | #include "xfs_dir2_sf.h" |
| 33 | #include "xfs_attr_sf.h" | 31 | #include "xfs_attr_sf.h" |
| 34 | #include "xfs_dinode.h" | 32 | #include "xfs_dinode.h" |
| 35 | #include "xfs_inode.h" | 33 | #include "xfs_inode.h" |
| 36 | #include "xfs_inode_item.h" | 34 | #include "xfs_inode_item.h" |
| 37 | #include "xfs_dir_leaf.h" | ||
| 38 | #include "xfs_error.h" | 35 | #include "xfs_error.h" |
| 39 | #include "xfs_dir2_data.h" | 36 | #include "xfs_dir2_data.h" |
| 40 | #include "xfs_dir2_leaf.h" | 37 | #include "xfs_dir2_leaf.h" |
| @@ -117,13 +114,13 @@ xfs_dir2_block_sfsize( | |||
| 117 | dep->name[0] == '.' && dep->name[1] == '.'; | 114 | dep->name[0] == '.' && dep->name[1] == '.'; |
| 118 | #if XFS_BIG_INUMS | 115 | #if XFS_BIG_INUMS |
| 119 | if (!isdot) | 116 | if (!isdot) |
| 120 | i8count += INT_GET(dep->inumber, ARCH_CONVERT) > XFS_DIR2_MAX_SHORT_INUM; | 117 | i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM; |
| 121 | #endif | 118 | #endif |
| 122 | if (!isdot && !isdotdot) { | 119 | if (!isdot && !isdotdot) { |
| 123 | count++; | 120 | count++; |
| 124 | namelen += dep->namelen; | 121 | namelen += dep->namelen; |
| 125 | } else if (isdotdot) | 122 | } else if (isdotdot) |
| 126 | parent = INT_GET(dep->inumber, ARCH_CONVERT); | 123 | parent = be64_to_cpu(dep->inumber); |
| 127 | /* | 124 | /* |
| 128 | * Calculate the new size, see if we should give up yet. | 125 | * Calculate the new size, see if we should give up yet. |
| 129 | */ | 126 | */ |
| @@ -229,13 +226,13 @@ xfs_dir2_block_to_sf( | |||
| 229 | * Skip . | 226 | * Skip . |
| 230 | */ | 227 | */ |
| 231 | if (dep->namelen == 1 && dep->name[0] == '.') | 228 | if (dep->namelen == 1 && dep->name[0] == '.') |
| 232 | ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == dp->i_ino); | 229 | ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino); |
| 233 | /* | 230 | /* |
| 234 | * Skip .., but make sure the inode number is right. | 231 | * Skip .., but make sure the inode number is right. |
| 235 | */ | 232 | */ |
| 236 | else if (dep->namelen == 2 && | 233 | else if (dep->namelen == 2 && |
| 237 | dep->name[0] == '.' && dep->name[1] == '.') | 234 | dep->name[0] == '.' && dep->name[1] == '.') |
| 238 | ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == | 235 | ASSERT(be64_to_cpu(dep->inumber) == |
| 239 | XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent)); | 236 | XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent)); |
| 240 | /* | 237 | /* |
| 241 | * Normal entry, copy it into shortform. | 238 | * Normal entry, copy it into shortform. |
| @@ -246,7 +243,7 @@ xfs_dir2_block_to_sf( | |||
| 246 | (xfs_dir2_data_aoff_t) | 243 | (xfs_dir2_data_aoff_t) |
| 247 | ((char *)dep - (char *)block)); | 244 | ((char *)dep - (char *)block)); |
| 248 | memcpy(sfep->name, dep->name, dep->namelen); | 245 | memcpy(sfep->name, dep->name, dep->namelen); |
| 249 | temp=INT_GET(dep->inumber, ARCH_CONVERT); | 246 | temp = be64_to_cpu(dep->inumber); |
| 250 | XFS_DIR2_SF_PUT_INUMBER(sfp, &temp, | 247 | XFS_DIR2_SF_PUT_INUMBER(sfp, &temp, |
| 251 | XFS_DIR2_SF_INUMBERP(sfep)); | 248 | XFS_DIR2_SF_INUMBERP(sfep)); |
| 252 | sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); | 249 | sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); |
diff --git a/fs/xfs/xfs_dir2_trace.c b/fs/xfs/xfs_dir2_trace.c index c626943b4112..f3fb2ffd6f5c 100644 --- a/fs/xfs/xfs_dir2_trace.c +++ b/fs/xfs/xfs_dir2_trace.c | |||
| @@ -19,11 +19,9 @@ | |||
| 19 | #include "xfs_fs.h" | 19 | #include "xfs_fs.h" |
| 20 | #include "xfs_types.h" | 20 | #include "xfs_types.h" |
| 21 | #include "xfs_inum.h" | 21 | #include "xfs_inum.h" |
| 22 | #include "xfs_dir.h" | ||
| 23 | #include "xfs_dir2.h" | 22 | #include "xfs_dir2.h" |
| 24 | #include "xfs_da_btree.h" | 23 | #include "xfs_da_btree.h" |
| 25 | #include "xfs_bmap_btree.h" | 24 | #include "xfs_bmap_btree.h" |
| 26 | #include "xfs_dir_sf.h" | ||
| 27 | #include "xfs_dir2_sf.h" | 25 | #include "xfs_dir2_sf.h" |
| 28 | #include "xfs_attr_sf.h" | 26 | #include "xfs_attr_sf.h" |
| 29 | #include "xfs_dinode.h" | 27 | #include "xfs_dinode.h" |
diff --git a/fs/xfs/xfs_dir_leaf.c b/fs/xfs/xfs_dir_leaf.c deleted file mode 100644 index 6d711869262f..000000000000 --- a/fs/xfs/xfs_dir_leaf.c +++ /dev/null | |||
| @@ -1,2213 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it would be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write the Free Software Foundation, | ||
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | #include "xfs.h" | ||
| 19 | #include "xfs_fs.h" | ||
| 20 | #include "xfs_types.h" | ||
| 21 | #include "xfs_log.h" | ||
| 22 | #include "xfs_inum.h" | ||
| 23 | #include "xfs_trans.h" | ||
| 24 | #include "xfs_sb.h" | ||
| 25 | #include "xfs_dir.h" | ||
| 26 | #include "xfs_dir2.h" | ||
| 27 | #include "xfs_dmapi.h" | ||
| 28 | #include "xfs_mount.h" | ||
| 29 | #include "xfs_da_btree.h" | ||
| 30 | #include "xfs_bmap_btree.h" | ||
| 31 | #include "xfs_alloc_btree.h" | ||
| 32 | #include "xfs_ialloc_btree.h" | ||
| 33 | #include "xfs_dir_sf.h" | ||
| 34 | #include "xfs_dir2_sf.h" | ||
| 35 | #include "xfs_attr_sf.h" | ||
| 36 | #include "xfs_dinode.h" | ||
| 37 | #include "xfs_inode.h" | ||
| 38 | #include "xfs_inode_item.h" | ||
| 39 | #include "xfs_alloc.h" | ||
| 40 | #include "xfs_btree.h" | ||
| 41 | #include "xfs_bmap.h" | ||
| 42 | #include "xfs_dir_leaf.h" | ||
| 43 | #include "xfs_error.h" | ||
| 44 | |||
| 45 | /* | ||
| 46 | * xfs_dir_leaf.c | ||
| 47 | * | ||
| 48 | * Routines to implement leaf blocks of directories as Btrees of hashed names. | ||
| 49 | */ | ||
| 50 | |||
| 51 | /*======================================================================== | ||
| 52 | * Function prototypes for the kernel. | ||
| 53 | *========================================================================*/ | ||
| 54 | |||
| 55 | /* | ||
| 56 | * Routines used for growing the Btree. | ||
| 57 | */ | ||
| 58 | STATIC void xfs_dir_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args, | ||
| 59 | int insertion_index, | ||
| 60 | int freemap_index); | ||
| 61 | STATIC int xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer, | ||
| 62 | int musthave, int justcheck); | ||
| 63 | STATIC void xfs_dir_leaf_rebalance(xfs_da_state_t *state, | ||
| 64 | xfs_da_state_blk_t *blk1, | ||
| 65 | xfs_da_state_blk_t *blk2); | ||
| 66 | STATIC int xfs_dir_leaf_figure_balance(xfs_da_state_t *state, | ||
| 67 | xfs_da_state_blk_t *leaf_blk_1, | ||
| 68 | xfs_da_state_blk_t *leaf_blk_2, | ||
| 69 | int *number_entries_in_blk1, | ||
| 70 | int *number_namebytes_in_blk1); | ||
| 71 | |||
| 72 | STATIC int xfs_dir_leaf_create(struct xfs_da_args *args, | ||
| 73 | xfs_dablk_t which_block, | ||
| 74 | struct xfs_dabuf **bpp); | ||
| 75 | |||
| 76 | /* | ||
| 77 | * Utility routines. | ||
| 78 | */ | ||
| 79 | STATIC void xfs_dir_leaf_moveents(xfs_dir_leafblock_t *src_leaf, | ||
| 80 | int src_start, | ||
| 81 | xfs_dir_leafblock_t *dst_leaf, | ||
| 82 | int dst_start, int move_count, | ||
| 83 | xfs_mount_t *mp); | ||
| 84 | |||
| 85 | |||
| 86 | /*======================================================================== | ||
| 87 | * External routines when dirsize < XFS_IFORK_DSIZE(dp). | ||
| 88 | *========================================================================*/ | ||
| 89 | |||
| 90 | |||
| 91 | /* | ||
| 92 | * Validate a given inode number. | ||
| 93 | */ | ||
| 94 | int | ||
| 95 | xfs_dir_ino_validate(xfs_mount_t *mp, xfs_ino_t ino) | ||
| 96 | { | ||
| 97 | xfs_agblock_t agblkno; | ||
| 98 | xfs_agino_t agino; | ||
| 99 | xfs_agnumber_t agno; | ||
| 100 | int ino_ok; | ||
| 101 | int ioff; | ||
| 102 | |||
| 103 | agno = XFS_INO_TO_AGNO(mp, ino); | ||
| 104 | agblkno = XFS_INO_TO_AGBNO(mp, ino); | ||
| 105 | ioff = XFS_INO_TO_OFFSET(mp, ino); | ||
| 106 | agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff); | ||
| 107 | ino_ok = | ||
| 108 | agno < mp->m_sb.sb_agcount && | ||
| 109 | agblkno < mp->m_sb.sb_agblocks && | ||
| 110 | agblkno != 0 && | ||
| 111 | ioff < (1 << mp->m_sb.sb_inopblog) && | ||
| 112 | XFS_AGINO_TO_INO(mp, agno, agino) == ino; | ||
| 113 | if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE, | ||
| 114 | XFS_RANDOM_DIR_INO_VALIDATE))) { | ||
| 115 | xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx", | ||
| 116 | (unsigned long long) ino); | ||
| 117 | XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp); | ||
| 118 | return XFS_ERROR(EFSCORRUPTED); | ||
| 119 | } | ||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | /* | ||
| 124 | * Create the initial contents of a shortform directory. | ||
| 125 | */ | ||
| 126 | int | ||
| 127 | xfs_dir_shortform_create(xfs_da_args_t *args, xfs_ino_t parent) | ||
| 128 | { | ||
| 129 | xfs_dir_sf_hdr_t *hdr; | ||
| 130 | xfs_inode_t *dp; | ||
| 131 | |||
| 132 | dp = args->dp; | ||
| 133 | ASSERT(dp != NULL); | ||
| 134 | ASSERT(dp->i_d.di_size == 0); | ||
| 135 | if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { | ||
| 136 | dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ | ||
| 137 | dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; | ||
| 138 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); | ||
| 139 | dp->i_df.if_flags |= XFS_IFINLINE; | ||
| 140 | } | ||
| 141 | ASSERT(dp->i_df.if_flags & XFS_IFINLINE); | ||
| 142 | ASSERT(dp->i_df.if_bytes == 0); | ||
| 143 | xfs_idata_realloc(dp, sizeof(*hdr), XFS_DATA_FORK); | ||
| 144 | hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data; | ||
| 145 | XFS_DIR_SF_PUT_DIRINO(&parent, &hdr->parent); | ||
| 146 | |||
| 147 | hdr->count = 0; | ||
| 148 | dp->i_d.di_size = sizeof(*hdr); | ||
| 149 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); | ||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | /* | ||
| 154 | * Add a name to the shortform directory structure. | ||
| 155 | * Overflow from the inode has already been checked for. | ||
| 156 | */ | ||
| 157 | int | ||
| 158 | xfs_dir_shortform_addname(xfs_da_args_t *args) | ||
| 159 | { | ||
| 160 | xfs_dir_shortform_t *sf; | ||
| 161 | xfs_dir_sf_entry_t *sfe; | ||
| 162 | int i, offset, size; | ||
| 163 | xfs_inode_t *dp; | ||
| 164 | |||
| 165 | dp = args->dp; | ||
| 166 | ASSERT(dp->i_df.if_flags & XFS_IFINLINE); | ||
| 167 | /* | ||
| 168 | * Catch the case where the conversion from shortform to leaf | ||
| 169 | * failed part way through. | ||
| 170 | */ | ||
| 171 | if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { | ||
| 172 | ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); | ||
| 173 | return XFS_ERROR(EIO); | ||
| 174 | } | ||
| 175 | ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); | ||
| 176 | ASSERT(dp->i_df.if_u1.if_data != NULL); | ||
| 177 | sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; | ||
| 178 | sfe = &sf->list[0]; | ||
| 179 | for (i = sf->hdr.count-1; i >= 0; i--) { | ||
| 180 | if (sfe->namelen == args->namelen && | ||
| 181 | args->name[0] == sfe->name[0] && | ||
| 182 | memcmp(args->name, sfe->name, args->namelen) == 0) | ||
| 183 | return XFS_ERROR(EEXIST); | ||
| 184 | sfe = XFS_DIR_SF_NEXTENTRY(sfe); | ||
| 185 | } | ||
| 186 | |||
| 187 | offset = (int)((char *)sfe - (char *)sf); | ||
| 188 | size = XFS_DIR_SF_ENTSIZE_BYNAME(args->namelen); | ||
| 189 | xfs_idata_realloc(dp, size, XFS_DATA_FORK); | ||
| 190 | sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; | ||
| 191 | sfe = (xfs_dir_sf_entry_t *)((char *)sf + offset); | ||
| 192 | |||
| 193 | XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sfe->inumber); | ||
| 194 | sfe->namelen = args->namelen; | ||
| 195 | memcpy(sfe->name, args->name, sfe->namelen); | ||
| 196 | sf->hdr.count++; | ||
| 197 | |||
| 198 | dp->i_d.di_size += size; | ||
| 199 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); | ||
| 200 | |||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | /* | ||
| 205 | * Remove a name from the shortform directory structure. | ||
| 206 | */ | ||
| 207 | int | ||
| 208 | xfs_dir_shortform_removename(xfs_da_args_t *args) | ||
| 209 | { | ||
| 210 | xfs_dir_shortform_t *sf; | ||
| 211 | xfs_dir_sf_entry_t *sfe; | ||
| 212 | int base, size = 0, i; | ||
| 213 | xfs_inode_t *dp; | ||
| 214 | |||
| 215 | dp = args->dp; | ||
| 216 | ASSERT(dp->i_df.if_flags & XFS_IFINLINE); | ||
| 217 | /* | ||
| 218 | * Catch the case where the conversion from shortform to leaf | ||
| 219 | * failed part way through. | ||
| 220 | */ | ||
| 221 | if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { | ||
| 222 | ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); | ||
| 223 | return XFS_ERROR(EIO); | ||
| 224 | } | ||
| 225 | ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); | ||
| 226 | ASSERT(dp->i_df.if_u1.if_data != NULL); | ||
| 227 | base = sizeof(xfs_dir_sf_hdr_t); | ||
| 228 | sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; | ||
| 229 | sfe = &sf->list[0]; | ||
| 230 | for (i = sf->hdr.count-1; i >= 0; i--) { | ||
| 231 | size = XFS_DIR_SF_ENTSIZE_BYENTRY(sfe); | ||
| 232 | if (sfe->namelen == args->namelen && | ||
| 233 | sfe->name[0] == args->name[0] && | ||
| 234 | memcmp(sfe->name, args->name, args->namelen) == 0) | ||
| 235 | break; | ||
| 236 | base += size; | ||
| 237 | sfe = XFS_DIR_SF_NEXTENTRY(sfe); | ||
| 238 | } | ||
| 239 | if (i < 0) { | ||
| 240 | ASSERT(args->oknoent); | ||
| 241 | return XFS_ERROR(ENOENT); | ||
| 242 | } | ||
| 243 | |||
| 244 | if ((base + size) != dp->i_d.di_size) { | ||
| 245 | memmove(&((char *)sf)[base], &((char *)sf)[base+size], | ||
| 246 | dp->i_d.di_size - (base+size)); | ||
| 247 | } | ||
| 248 | sf->hdr.count--; | ||
| 249 | |||
| 250 | xfs_idata_realloc(dp, -size, XFS_DATA_FORK); | ||
| 251 | dp->i_d.di_size -= size; | ||
| 252 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); | ||
| 253 | |||
| 254 | return 0; | ||
| 255 | } | ||
| 256 | |||
| 257 | /* | ||
| 258 | * Look up a name in a shortform directory structure. | ||
| 259 | */ | ||
| 260 | int | ||
| 261 | xfs_dir_shortform_lookup(xfs_da_args_t *args) | ||
| 262 | { | ||
| 263 | xfs_dir_shortform_t *sf; | ||
| 264 | xfs_dir_sf_entry_t *sfe; | ||
| 265 | int i; | ||
| 266 | xfs_inode_t *dp; | ||
| 267 | |||
| 268 | dp = args->dp; | ||
| 269 | ASSERT(dp->i_df.if_flags & XFS_IFINLINE); | ||
| 270 | /* | ||
| 271 | * Catch the case where the conversion from shortform to leaf | ||
| 272 | * failed part way through. | ||
| 273 | */ | ||
| 274 | if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { | ||
| 275 | ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); | ||
| 276 | return XFS_ERROR(EIO); | ||
| 277 | } | ||
| 278 | ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); | ||
| 279 | ASSERT(dp->i_df.if_u1.if_data != NULL); | ||
| 280 | sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; | ||
| 281 | if (args->namelen == 2 && | ||
| 282 | args->name[0] == '.' && args->name[1] == '.') { | ||
| 283 | XFS_DIR_SF_GET_DIRINO(&sf->hdr.parent, &args->inumber); | ||
| 284 | return(XFS_ERROR(EEXIST)); | ||
| 285 | } | ||
| 286 | if (args->namelen == 1 && args->name[0] == '.') { | ||
| 287 | args->inumber = dp->i_ino; | ||
| 288 | return(XFS_ERROR(EEXIST)); | ||
| 289 | } | ||
| 290 | sfe = &sf->list[0]; | ||
| 291 | for (i = sf->hdr.count-1; i >= 0; i--) { | ||
| 292 | if (sfe->namelen == args->namelen && | ||
| 293 | sfe->name[0] == args->name[0] && | ||
| 294 | memcmp(args->name, sfe->name, args->namelen) == 0) { | ||
| 295 | XFS_DIR_SF_GET_DIRINO(&sfe->inumber, &args->inumber); | ||
| 296 | return(XFS_ERROR(EEXIST)); | ||
| 297 | } | ||
| 298 | sfe = XFS_DIR_SF_NEXTENTRY(sfe); | ||
| 299 | } | ||
| 300 | ASSERT(args->oknoent); | ||
| 301 | return(XFS_ERROR(ENOENT)); | ||
| 302 | } | ||
| 303 | |||
| 304 | /* | ||
| 305 | * Convert from using the shortform to the leaf. | ||
| 306 | */ | ||
| 307 | int | ||
| 308 | xfs_dir_shortform_to_leaf(xfs_da_args_t *iargs) | ||
| 309 | { | ||
| 310 | xfs_inode_t *dp; | ||
| 311 | xfs_dir_shortform_t *sf; | ||
| 312 | xfs_dir_sf_entry_t *sfe; | ||
| 313 | xfs_da_args_t args; | ||
| 314 | xfs_ino_t inumber; | ||
| 315 | char *tmpbuffer; | ||
| 316 | int retval, i, size; | ||
| 317 | xfs_dablk_t blkno; | ||
| 318 | xfs_dabuf_t *bp; | ||
| 319 | |||
| 320 | dp = iargs->dp; | ||
| 321 | /* | ||
| 322 | * Catch the case where the conversion from shortform to leaf | ||
| 323 | * failed part way through. | ||
| 324 | */ | ||
| 325 | if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { | ||
| 326 | ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); | ||
| 327 | return XFS_ERROR(EIO); | ||
| 328 | } | ||
| 329 | ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); | ||
| 330 | ASSERT(dp->i_df.if_u1.if_data != NULL); | ||
| 331 | size = dp->i_df.if_bytes; | ||
| 332 | tmpbuffer = kmem_alloc(size, KM_SLEEP); | ||
| 333 | ASSERT(tmpbuffer != NULL); | ||
| 334 | |||
| 335 | memcpy(tmpbuffer, dp->i_df.if_u1.if_data, size); | ||
| 336 | |||
| 337 | sf = (xfs_dir_shortform_t *)tmpbuffer; | ||
| 338 | XFS_DIR_SF_GET_DIRINO(&sf->hdr.parent, &inumber); | ||
| 339 | |||
| 340 | xfs_idata_realloc(dp, -size, XFS_DATA_FORK); | ||
| 341 | dp->i_d.di_size = 0; | ||
| 342 | xfs_trans_log_inode(iargs->trans, dp, XFS_ILOG_CORE); | ||
| 343 | retval = xfs_da_grow_inode(iargs, &blkno); | ||
| 344 | if (retval) | ||
| 345 | goto out; | ||
| 346 | |||
| 347 | ASSERT(blkno == 0); | ||
| 348 | retval = xfs_dir_leaf_create(iargs, blkno, &bp); | ||
| 349 | if (retval) | ||
| 350 | goto out; | ||
| 351 | xfs_da_buf_done(bp); | ||
| 352 | |||
| 353 | args.name = "."; | ||
| 354 | args.namelen = 1; | ||
| 355 | args.hashval = xfs_dir_hash_dot; | ||
| 356 | args.inumber = dp->i_ino; | ||
| 357 | args.dp = dp; | ||
| 358 | args.firstblock = iargs->firstblock; | ||
| 359 | args.flist = iargs->flist; | ||
| 360 | args.total = iargs->total; | ||
| 361 | args.whichfork = XFS_DATA_FORK; | ||
| 362 | args.trans = iargs->trans; | ||
| 363 | args.justcheck = 0; | ||
| 364 | args.addname = args.oknoent = 1; | ||
| 365 | retval = xfs_dir_leaf_addname(&args); | ||
| 366 | if (retval) | ||
| 367 | goto out; | ||
| 368 | |||
| 369 | args.name = ".."; | ||
| 370 | args.namelen = 2; | ||
| 371 | args.hashval = xfs_dir_hash_dotdot; | ||
| 372 | args.inumber = inumber; | ||
| 373 | retval = xfs_dir_leaf_addname(&args); | ||
| 374 | if (retval) | ||
| 375 | goto out; | ||
| 376 | |||
| 377 | sfe = &sf->list[0]; | ||
| 378 | for (i = 0; i < sf->hdr.count; i++) { | ||
| 379 | args.name = (char *)(sfe->name); | ||
| 380 | args.namelen = sfe->namelen; | ||
| 381 | args.hashval = xfs_da_hashname((char *)(sfe->name), | ||
| 382 | sfe->namelen); | ||
| 383 | XFS_DIR_SF_GET_DIRINO(&sfe->inumber, &args.inumber); | ||
| 384 | retval = xfs_dir_leaf_addname(&args); | ||
| 385 | if (retval) | ||
| 386 | goto out; | ||
| 387 | sfe = XFS_DIR_SF_NEXTENTRY(sfe); | ||
| 388 | } | ||
| 389 | retval = 0; | ||
| 390 | |||
| 391 | out: | ||
| 392 | kmem_free(tmpbuffer, size); | ||
| 393 | return retval; | ||
| 394 | } | ||
| 395 | |||
| 396 | STATIC int | ||
| 397 | xfs_dir_shortform_compare(const void *a, const void *b) | ||
| 398 | { | ||
| 399 | xfs_dir_sf_sort_t *sa, *sb; | ||
| 400 | |||
| 401 | sa = (xfs_dir_sf_sort_t *)a; | ||
| 402 | sb = (xfs_dir_sf_sort_t *)b; | ||
| 403 | if (sa->hash < sb->hash) | ||
| 404 | return -1; | ||
| 405 | else if (sa->hash > sb->hash) | ||
| 406 | return 1; | ||
| 407 | else | ||
| 408 | return sa->entno - sb->entno; | ||
| 409 | } | ||
| 410 | |||
| 411 | /* | ||
| 412 | * Copy out directory entries for getdents(), for shortform directories. | ||
| 413 | */ | ||
| 414 | /*ARGSUSED*/ | ||
| 415 | int | ||
| 416 | xfs_dir_shortform_getdents(xfs_inode_t *dp, uio_t *uio, int *eofp, | ||
| 417 | xfs_dirent_t *dbp, xfs_dir_put_t put) | ||
| 418 | { | ||
| 419 | xfs_dir_shortform_t *sf; | ||
| 420 | xfs_dir_sf_entry_t *sfe; | ||
| 421 | int retval, i, sbsize, nsbuf, lastresid=0, want_entno; | ||
| 422 | xfs_mount_t *mp; | ||
| 423 | xfs_dahash_t cookhash, hash; | ||
| 424 | xfs_dir_put_args_t p; | ||
| 425 | xfs_dir_sf_sort_t *sbuf, *sbp; | ||
| 426 | |||
| 427 | mp = dp->i_mount; | ||
| 428 | sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; | ||
| 429 | cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset); | ||
| 430 | want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset); | ||
| 431 | nsbuf = sf->hdr.count + 2; | ||
| 432 | sbsize = (nsbuf + 1) * sizeof(*sbuf); | ||
| 433 | sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP); | ||
| 434 | |||
| 435 | xfs_dir_trace_g_du("sf: start", dp, uio); | ||
| 436 | |||
| 437 | /* | ||
| 438 | * Collect all the entries into the buffer. | ||
| 439 | * Entry 0 is . | ||
| 440 | */ | ||
| 441 | sbp->entno = 0; | ||
| 442 | sbp->seqno = 0; | ||
| 443 | sbp->hash = xfs_dir_hash_dot; | ||
| 444 | sbp->ino = dp->i_ino; | ||
| 445 | sbp->name = "."; | ||
| 446 | sbp->namelen = 1; | ||
| 447 | sbp++; | ||
| 448 | |||
| 449 | /* | ||
| 450 | * Entry 1 is .. | ||
| 451 | */ | ||
| 452 | sbp->entno = 1; | ||
| 453 | sbp->seqno = 0; | ||
| 454 | sbp->hash = xfs_dir_hash_dotdot; | ||
| 455 | sbp->ino = XFS_GET_DIR_INO8(sf->hdr.parent); | ||
| 456 | sbp->name = ".."; | ||
| 457 | sbp->namelen = 2; | ||
| 458 | sbp++; | ||
| 459 | |||
| 460 | /* | ||
| 461 | * Scan the directory data for the rest of the entries. | ||
| 462 | */ | ||
| 463 | for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { | ||
| 464 | |||
| 465 | if (unlikely( | ||
| 466 | ((char *)sfe < (char *)sf) || | ||
| 467 | ((char *)sfe >= ((char *)sf + dp->i_df.if_bytes)))) { | ||
| 468 | xfs_dir_trace_g_du("sf: corrupted", dp, uio); | ||
| 469 | XFS_CORRUPTION_ERROR("xfs_dir_shortform_getdents", | ||
| 470 | XFS_ERRLEVEL_LOW, mp, sfe); | ||
| 471 | kmem_free(sbuf, sbsize); | ||
| 472 | return XFS_ERROR(EFSCORRUPTED); | ||
| 473 | } | ||
| 474 | |||
| 475 | sbp->entno = i + 2; | ||
| 476 | sbp->seqno = 0; | ||
| 477 | sbp->hash = xfs_da_hashname((char *)sfe->name, sfe->namelen); | ||
| 478 | sbp->ino = XFS_GET_DIR_INO8(sfe->inumber); | ||
| 479 | sbp->name = (char *)sfe->name; | ||
| 480 | sbp->namelen = sfe->namelen; | ||
| 481 | sfe = XFS_DIR_SF_NEXTENTRY(sfe); | ||
| 482 | sbp++; | ||
| 483 | } | ||
| 484 | |||
| 485 | /* | ||
| 486 | * Sort the entries on hash then entno. | ||
| 487 | */ | ||
| 488 | xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_dir_shortform_compare); | ||
| 489 | /* | ||
| 490 | * Stuff in last entry. | ||
| 491 | */ | ||
| 492 | sbp->entno = nsbuf; | ||
| 493 | sbp->hash = XFS_DA_MAXHASH; | ||
| 494 | sbp->seqno = 0; | ||
| 495 | /* | ||
| 496 | * Figure out the sequence numbers in case there's a hash duplicate. | ||
| 497 | */ | ||
| 498 | for (hash = sbuf->hash, sbp = sbuf + 1; | ||
| 499 | sbp < &sbuf[nsbuf + 1]; sbp++) { | ||
| 500 | if (sbp->hash == hash) | ||
| 501 | sbp->seqno = sbp[-1].seqno + 1; | ||
| 502 | else | ||
| 503 | hash = sbp->hash; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* | ||
| 507 | * Set up put routine. | ||
| 508 | */ | ||
| 509 | p.dbp = dbp; | ||
| 510 | p.put = put; | ||
| 511 | p.uio = uio; | ||
| 512 | |||
| 513 | /* | ||
| 514 | * Find our place. | ||
| 515 | */ | ||
| 516 | for (sbp = sbuf; sbp < &sbuf[nsbuf + 1]; sbp++) { | ||
| 517 | if (sbp->hash > cookhash || | ||
| 518 | (sbp->hash == cookhash && sbp->seqno >= want_entno)) | ||
| 519 | break; | ||
| 520 | } | ||
| 521 | |||
| 522 | /* | ||
| 523 | * Did we fail to find anything? We stop at the last entry, | ||
| 524 | * the one we put maxhash into. | ||
| 525 | */ | ||
| 526 | if (sbp == &sbuf[nsbuf]) { | ||
| 527 | kmem_free(sbuf, sbsize); | ||
| 528 | xfs_dir_trace_g_du("sf: hash beyond end", dp, uio); | ||
| 529 | uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH); | ||
| 530 | *eofp = 1; | ||
| 531 | return 0; | ||
| 532 | } | ||
| 533 | |||
| 534 | /* | ||
| 535 | * Loop putting entries into the user buffer. | ||
| 536 | */ | ||
| 537 | while (sbp < &sbuf[nsbuf]) { | ||
| 538 | /* | ||
| 539 | * Save the first resid in a run of equal-hashval entries | ||
| 540 | * so that we can back them out if they don't all fit. | ||
| 541 | */ | ||
| 542 | if (sbp->seqno == 0 || sbp == sbuf) | ||
| 543 | lastresid = uio->uio_resid; | ||
| 544 | XFS_PUT_COOKIE(p.cook, mp, 0, sbp[1].seqno, sbp[1].hash); | ||
| 545 | p.ino = sbp->ino; | ||
| 546 | #if XFS_BIG_INUMS | ||
| 547 | p.ino += mp->m_inoadd; | ||
| 548 | #endif | ||
| 549 | p.name = sbp->name; | ||
| 550 | p.namelen = sbp->namelen; | ||
| 551 | retval = p.put(&p); | ||
| 552 | if (!p.done) { | ||
| 553 | uio->uio_offset = | ||
| 554 | XFS_DA_MAKE_COOKIE(mp, 0, 0, sbp->hash); | ||
| 555 | kmem_free(sbuf, sbsize); | ||
| 556 | uio->uio_resid = lastresid; | ||
| 557 | xfs_dir_trace_g_du("sf: E-O-B", dp, uio); | ||
| 558 | return retval; | ||
| 559 | } | ||
| 560 | sbp++; | ||
| 561 | } | ||
| 562 | kmem_free(sbuf, sbsize); | ||
| 563 | uio->uio_offset = p.cook.o; | ||
| 564 | *eofp = 1; | ||
| 565 | xfs_dir_trace_g_du("sf: E-O-F", dp, uio); | ||
| 566 | return 0; | ||
| 567 | } | ||
| 568 | |||
| 569 | /* | ||
| 570 | * Look up a name in a shortform directory structure, replace the inode number. | ||
| 571 | */ | ||
| 572 | int | ||
| 573 | xfs_dir_shortform_replace(xfs_da_args_t *args) | ||
| 574 | { | ||
| 575 | xfs_dir_shortform_t *sf; | ||
| 576 | xfs_dir_sf_entry_t *sfe; | ||
| 577 | xfs_inode_t *dp; | ||
| 578 | int i; | ||
| 579 | |||
| 580 | dp = args->dp; | ||
| 581 | ASSERT(dp->i_df.if_flags & XFS_IFINLINE); | ||
| 582 | /* | ||
| 583 | * Catch the case where the conversion from shortform to leaf | ||
| 584 | * failed part way through. | ||
| 585 | */ | ||
| 586 | if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { | ||
| 587 | ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); | ||
| 588 | return XFS_ERROR(EIO); | ||
| 589 | } | ||
| 590 | ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); | ||
| 591 | ASSERT(dp->i_df.if_u1.if_data != NULL); | ||
| 592 | sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; | ||
| 593 | if (args->namelen == 2 && | ||
| 594 | args->name[0] == '.' && args->name[1] == '.') { | ||
| 595 | /* XXX - replace assert? */ | ||
| 596 | XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sf->hdr.parent); | ||
| 597 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); | ||
| 598 | return 0; | ||
| 599 | } | ||
| 600 | ASSERT(args->namelen != 1 || args->name[0] != '.'); | ||
| 601 | sfe = &sf->list[0]; | ||
| 602 | for (i = sf->hdr.count-1; i >= 0; i--) { | ||
| 603 | if (sfe->namelen == args->namelen && | ||
| 604 | sfe->name[0] == args->name[0] && | ||
| 605 | memcmp(args->name, sfe->name, args->namelen) == 0) { | ||
| 606 | ASSERT(memcmp((char *)&args->inumber, | ||
| 607 | (char *)&sfe->inumber, sizeof(xfs_ino_t))); | ||
| 608 | XFS_DIR_SF_PUT_DIRINO(&args->inumber, &sfe->inumber); | ||
| 609 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); | ||
| 610 | return 0; | ||
| 611 | } | ||
| 612 | sfe = XFS_DIR_SF_NEXTENTRY(sfe); | ||
| 613 | } | ||
| 614 | ASSERT(args->oknoent); | ||
| 615 | return XFS_ERROR(ENOENT); | ||
| 616 | } | ||
| 617 | |||
| 618 | /* | ||
| 619 | * Convert a leaf directory to shortform structure | ||
| 620 | */ | ||
| 621 | int | ||
| 622 | xfs_dir_leaf_to_shortform(xfs_da_args_t *iargs) | ||
| 623 | { | ||
| 624 | xfs_dir_leafblock_t *leaf; | ||
| 625 | xfs_dir_leaf_hdr_t *hdr; | ||
| 626 | xfs_dir_leaf_entry_t *entry; | ||
| 627 | xfs_dir_leaf_name_t *namest; | ||
| 628 | xfs_da_args_t args; | ||
| 629 | xfs_inode_t *dp; | ||
| 630 | xfs_ino_t parent = 0; | ||
| 631 | char *tmpbuffer; | ||
| 632 | int retval, i; | ||
| 633 | xfs_dabuf_t *bp; | ||
| 634 | |||
| 635 | dp = iargs->dp; | ||
| 636 | tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP); | ||
| 637 | ASSERT(tmpbuffer != NULL); | ||
| 638 | |||
| 639 | retval = xfs_da_read_buf(iargs->trans, iargs->dp, 0, -1, &bp, | ||
| 640 | XFS_DATA_FORK); | ||
| 641 | if (retval) | ||
| 642 | goto out; | ||
| 643 | ASSERT(bp != NULL); | ||
| 644 | memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount)); | ||
| 645 | leaf = (xfs_dir_leafblock_t *)tmpbuffer; | ||
| 646 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 647 | memset(bp->data, 0, XFS_LBSIZE(dp->i_mount)); | ||
| 648 | |||
| 649 | /* | ||
| 650 | * Find and special case the parent inode number | ||
| 651 | */ | ||
| 652 | hdr = &leaf->hdr; | ||
| 653 | entry = &leaf->entries[0]; | ||
| 654 | for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) { | ||
| 655 | namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); | ||
| 656 | if ((entry->namelen == 2) && | ||
| 657 | (namest->name[0] == '.') && | ||
| 658 | (namest->name[1] == '.')) { | ||
| 659 | XFS_DIR_SF_GET_DIRINO(&namest->inumber, &parent); | ||
| 660 | entry->nameidx = 0; | ||
| 661 | } else if ((entry->namelen == 1) && (namest->name[0] == '.')) { | ||
| 662 | entry->nameidx = 0; | ||
| 663 | } | ||
| 664 | } | ||
| 665 | retval = xfs_da_shrink_inode(iargs, 0, bp); | ||
| 666 | if (retval) | ||
| 667 | goto out; | ||
| 668 | retval = xfs_dir_shortform_create(iargs, parent); | ||
| 669 | if (retval) | ||
| 670 | goto out; | ||
| 671 | |||
| 672 | /* | ||
| 673 | * Copy the rest of the filenames | ||
| 674 | */ | ||
| 675 | entry = &leaf->entries[0]; | ||
| 676 | args.dp = dp; | ||
| 677 | args.firstblock = iargs->firstblock; | ||
| 678 | args.flist = iargs->flist; | ||
| 679 | args.total = iargs->total; | ||
| 680 | args.whichfork = XFS_DATA_FORK; | ||
| 681 | args.trans = iargs->trans; | ||
| 682 | args.justcheck = 0; | ||
| 683 | args.addname = args.oknoent = 1; | ||
| 684 | for (i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) { | ||
| 685 | if (!entry->nameidx) | ||
| 686 | continue; | ||
| 687 | namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); | ||
| 688 | args.name = (char *)(namest->name); | ||
| 689 | args.namelen = entry->namelen; | ||
| 690 | args.hashval = INT_GET(entry->hashval, ARCH_CONVERT); | ||
| 691 | XFS_DIR_SF_GET_DIRINO(&namest->inumber, &args.inumber); | ||
| 692 | xfs_dir_shortform_addname(&args); | ||
| 693 | } | ||
| 694 | |||
| 695 | out: | ||
| 696 | kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount)); | ||
| 697 | return retval; | ||
| 698 | } | ||
| 699 | |||
| 700 | /* | ||
| 701 | * Convert from using a single leaf to a root node and a leaf. | ||
| 702 | */ | ||
| 703 | int | ||
| 704 | xfs_dir_leaf_to_node(xfs_da_args_t *args) | ||
| 705 | { | ||
| 706 | xfs_dir_leafblock_t *leaf; | ||
| 707 | xfs_da_intnode_t *node; | ||
| 708 | xfs_inode_t *dp; | ||
| 709 | xfs_dabuf_t *bp1, *bp2; | ||
| 710 | xfs_dablk_t blkno; | ||
| 711 | int retval; | ||
| 712 | |||
| 713 | dp = args->dp; | ||
| 714 | retval = xfs_da_grow_inode(args, &blkno); | ||
| 715 | ASSERT(blkno == 1); | ||
| 716 | if (retval) | ||
| 717 | return retval; | ||
| 718 | retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1, | ||
| 719 | XFS_DATA_FORK); | ||
| 720 | if (retval) | ||
| 721 | return retval; | ||
| 722 | ASSERT(bp1 != NULL); | ||
| 723 | retval = xfs_da_get_buf(args->trans, args->dp, 1, -1, &bp2, | ||
| 724 | XFS_DATA_FORK); | ||
| 725 | if (retval) { | ||
| 726 | xfs_da_buf_done(bp1); | ||
| 727 | return retval; | ||
| 728 | } | ||
| 729 | ASSERT(bp2 != NULL); | ||
| 730 | memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount)); | ||
| 731 | xfs_da_buf_done(bp1); | ||
| 732 | xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1); | ||
| 733 | |||
| 734 | /* | ||
| 735 | * Set up the new root node. | ||
| 736 | */ | ||
| 737 | retval = xfs_da_node_create(args, 0, 1, &bp1, XFS_DATA_FORK); | ||
| 738 | if (retval) { | ||
| 739 | xfs_da_buf_done(bp2); | ||
| 740 | return retval; | ||
| 741 | } | ||
| 742 | node = bp1->data; | ||
| 743 | leaf = bp2->data; | ||
| 744 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 745 | node->btree[0].hashval = cpu_to_be32( | ||
| 746 | INT_GET(leaf->entries[ | ||
| 747 | INT_GET(leaf->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT)); | ||
| 748 | xfs_da_buf_done(bp2); | ||
| 749 | node->btree[0].before = cpu_to_be32(blkno); | ||
| 750 | node->hdr.count = cpu_to_be16(1); | ||
| 751 | xfs_da_log_buf(args->trans, bp1, | ||
| 752 | XFS_DA_LOGRANGE(node, &node->btree[0], sizeof(node->btree[0]))); | ||
| 753 | xfs_da_buf_done(bp1); | ||
| 754 | |||
| 755 | return retval; | ||
| 756 | } | ||
| 757 | |||
| 758 | |||
| 759 | /*======================================================================== | ||
| 760 | * Routines used for growing the Btree. | ||
| 761 | *========================================================================*/ | ||
| 762 | |||
| 763 | /* | ||
| 764 | * Create the initial contents of a leaf directory | ||
| 765 | * or a leaf in a node directory. | ||
| 766 | */ | ||
| 767 | STATIC int | ||
| 768 | xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) | ||
| 769 | { | ||
| 770 | xfs_dir_leafblock_t *leaf; | ||
| 771 | xfs_dir_leaf_hdr_t *hdr; | ||
| 772 | xfs_inode_t *dp; | ||
| 773 | xfs_dabuf_t *bp; | ||
| 774 | int retval; | ||
| 775 | |||
| 776 | dp = args->dp; | ||
| 777 | ASSERT(dp != NULL); | ||
| 778 | retval = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp, XFS_DATA_FORK); | ||
| 779 | if (retval) | ||
| 780 | return retval; | ||
| 781 | ASSERT(bp != NULL); | ||
| 782 | leaf = bp->data; | ||
| 783 | memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount)); | ||
| 784 | hdr = &leaf->hdr; | ||
| 785 | hdr->info.magic = cpu_to_be16(XFS_DIR_LEAF_MAGIC); | ||
| 786 | INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount)); | ||
| 787 | if (!hdr->firstused) | ||
| 788 | INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount) - 1); | ||
| 789 | INT_SET(hdr->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t)); | ||
| 790 | INT_SET(hdr->freemap[0].size, ARCH_CONVERT, INT_GET(hdr->firstused, ARCH_CONVERT) - INT_GET(hdr->freemap[0].base, ARCH_CONVERT)); | ||
| 791 | |||
| 792 | xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1); | ||
| 793 | |||
| 794 | *bpp = bp; | ||
| 795 | return 0; | ||
| 796 | } | ||
| 797 | |||
| 798 | /* | ||
| 799 | * Split the leaf node, rebalance, then add the new entry. | ||
| 800 | */ | ||
| 801 | int | ||
| 802 | xfs_dir_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, | ||
| 803 | xfs_da_state_blk_t *newblk) | ||
| 804 | { | ||
| 805 | xfs_dablk_t blkno; | ||
| 806 | xfs_da_args_t *args; | ||
| 807 | int error; | ||
| 808 | |||
| 809 | /* | ||
| 810 | * Allocate space for a new leaf node. | ||
| 811 | */ | ||
| 812 | args = state->args; | ||
| 813 | ASSERT(args != NULL); | ||
| 814 | ASSERT(oldblk->magic == XFS_DIR_LEAF_MAGIC); | ||
| 815 | error = xfs_da_grow_inode(args, &blkno); | ||
| 816 | if (error) | ||
| 817 | return error; | ||
| 818 | error = xfs_dir_leaf_create(args, blkno, &newblk->bp); | ||
| 819 | if (error) | ||
| 820 | return error; | ||
| 821 | newblk->blkno = blkno; | ||
| 822 | newblk->magic = XFS_DIR_LEAF_MAGIC; | ||
| 823 | |||
| 824 | /* | ||
| 825 | * Rebalance the entries across the two leaves. | ||
| 826 | */ | ||
| 827 | xfs_dir_leaf_rebalance(state, oldblk, newblk); | ||
| 828 | error = xfs_da_blk_link(state, oldblk, newblk); | ||
| 829 | if (error) | ||
| 830 | return error; | ||
| 831 | |||
| 832 | /* | ||
| 833 | * Insert the new entry in the correct block. | ||
| 834 | */ | ||
| 835 | if (state->inleaf) { | ||
| 836 | error = xfs_dir_leaf_add(oldblk->bp, args, oldblk->index); | ||
| 837 | } else { | ||
| 838 | error = xfs_dir_leaf_add(newblk->bp, args, newblk->index); | ||
| 839 | } | ||
| 840 | |||
| 841 | /* | ||
| 842 | * Update last hashval in each block since we added the name. | ||
| 843 | */ | ||
| 844 | oldblk->hashval = xfs_dir_leaf_lasthash(oldblk->bp, NULL); | ||
| 845 | newblk->hashval = xfs_dir_leaf_lasthash(newblk->bp, NULL); | ||
| 846 | return error; | ||
| 847 | } | ||
| 848 | |||
| 849 | /* | ||
| 850 | * Add a name to the leaf directory structure. | ||
| 851 | * | ||
| 852 | * Must take into account fragmented leaves and leaves where spacemap has | ||
| 853 | * lost some freespace information (ie: holes). | ||
| 854 | */ | ||
| 855 | int | ||
| 856 | xfs_dir_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args, int index) | ||
| 857 | { | ||
| 858 | xfs_dir_leafblock_t *leaf; | ||
| 859 | xfs_dir_leaf_hdr_t *hdr; | ||
| 860 | xfs_dir_leaf_map_t *map; | ||
| 861 | int tablesize, entsize, sum, i, tmp, error; | ||
| 862 | |||
| 863 | leaf = bp->data; | ||
| 864 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 865 | ASSERT((index >= 0) && (index <= INT_GET(leaf->hdr.count, ARCH_CONVERT))); | ||
| 866 | hdr = &leaf->hdr; | ||
| 867 | entsize = XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen); | ||
| 868 | |||
| 869 | /* | ||
| 870 | * Search through freemap for first-fit on new name length. | ||
| 871 | * (may need to figure in size of entry struct too) | ||
| 872 | */ | ||
| 873 | tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) * (uint)sizeof(xfs_dir_leaf_entry_t) | ||
| 874 | + (uint)sizeof(xfs_dir_leaf_hdr_t); | ||
| 875 | map = &hdr->freemap[XFS_DIR_LEAF_MAPSIZE-1]; | ||
| 876 | for (sum = 0, i = XFS_DIR_LEAF_MAPSIZE-1; i >= 0; map--, i--) { | ||
| 877 | if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) { | ||
| 878 | sum += INT_GET(map->size, ARCH_CONVERT); | ||
| 879 | continue; | ||
| 880 | } | ||
| 881 | if (!map->size) | ||
| 882 | continue; /* no space in this map */ | ||
| 883 | tmp = entsize; | ||
| 884 | if (INT_GET(map->base, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) | ||
| 885 | tmp += (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 886 | if (INT_GET(map->size, ARCH_CONVERT) >= tmp) { | ||
| 887 | if (!args->justcheck) | ||
| 888 | xfs_dir_leaf_add_work(bp, args, index, i); | ||
| 889 | return 0; | ||
| 890 | } | ||
| 891 | sum += INT_GET(map->size, ARCH_CONVERT); | ||
| 892 | } | ||
| 893 | |||
| 894 | /* | ||
| 895 | * If there are no holes in the address space of the block, | ||
| 896 | * and we don't have enough freespace, then compaction will do us | ||
| 897 | * no good and we should just give up. | ||
| 898 | */ | ||
| 899 | if (!hdr->holes && (sum < entsize)) | ||
| 900 | return XFS_ERROR(ENOSPC); | ||
| 901 | |||
| 902 | /* | ||
| 903 | * Compact the entries to coalesce free space. | ||
| 904 | * Pass the justcheck flag so the checking pass can return | ||
| 905 | * an error, without changing anything, if it won't fit. | ||
| 906 | */ | ||
| 907 | error = xfs_dir_leaf_compact(args->trans, bp, | ||
| 908 | args->total == 0 ? | ||
| 909 | entsize + | ||
| 910 | (uint)sizeof(xfs_dir_leaf_entry_t) : 0, | ||
| 911 | args->justcheck); | ||
| 912 | if (error) | ||
| 913 | return error; | ||
| 914 | /* | ||
| 915 | * After compaction, the block is guaranteed to have only one | ||
| 916 | * free region, in freemap[0]. If it is not big enough, give up. | ||
| 917 | */ | ||
| 918 | if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) < | ||
| 919 | (entsize + (uint)sizeof(xfs_dir_leaf_entry_t))) | ||
| 920 | return XFS_ERROR(ENOSPC); | ||
| 921 | |||
| 922 | if (!args->justcheck) | ||
| 923 | xfs_dir_leaf_add_work(bp, args, index, 0); | ||
| 924 | return 0; | ||
| 925 | } | ||
| 926 | |||
| 927 | /* | ||
| 928 | * Add a name to a leaf directory structure. | ||
| 929 | */ | ||
| 930 | STATIC void | ||
| 931 | xfs_dir_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int index, | ||
| 932 | int mapindex) | ||
| 933 | { | ||
| 934 | xfs_dir_leafblock_t *leaf; | ||
| 935 | xfs_dir_leaf_hdr_t *hdr; | ||
| 936 | xfs_dir_leaf_entry_t *entry; | ||
| 937 | xfs_dir_leaf_name_t *namest; | ||
| 938 | xfs_dir_leaf_map_t *map; | ||
| 939 | /* REFERENCED */ | ||
| 940 | xfs_mount_t *mp; | ||
| 941 | int tmp, i; | ||
| 942 | |||
| 943 | leaf = bp->data; | ||
| 944 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 945 | hdr = &leaf->hdr; | ||
| 946 | ASSERT((mapindex >= 0) && (mapindex < XFS_DIR_LEAF_MAPSIZE)); | ||
| 947 | ASSERT((index >= 0) && (index <= INT_GET(hdr->count, ARCH_CONVERT))); | ||
| 948 | |||
| 949 | /* | ||
| 950 | * Force open some space in the entry array and fill it in. | ||
| 951 | */ | ||
| 952 | entry = &leaf->entries[index]; | ||
| 953 | if (index < INT_GET(hdr->count, ARCH_CONVERT)) { | ||
| 954 | tmp = INT_GET(hdr->count, ARCH_CONVERT) - index; | ||
| 955 | tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 956 | memmove(entry + 1, entry, tmp); | ||
| 957 | xfs_da_log_buf(args->trans, bp, | ||
| 958 | XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry))); | ||
| 959 | } | ||
| 960 | INT_MOD(hdr->count, ARCH_CONVERT, +1); | ||
| 961 | |||
| 962 | /* | ||
| 963 | * Allocate space for the new string (at the end of the run). | ||
| 964 | */ | ||
| 965 | map = &hdr->freemap[mapindex]; | ||
| 966 | mp = args->trans->t_mountp; | ||
| 967 | ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); | ||
| 968 | ASSERT(INT_GET(map->size, ARCH_CONVERT) >= XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen)); | ||
| 969 | ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); | ||
| 970 | INT_MOD(map->size, ARCH_CONVERT, -(XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen))); | ||
| 971 | INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)); | ||
| 972 | INT_SET(entry->hashval, ARCH_CONVERT, args->hashval); | ||
| 973 | entry->namelen = args->namelen; | ||
| 974 | xfs_da_log_buf(args->trans, bp, | ||
| 975 | XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); | ||
| 976 | |||
| 977 | /* | ||
| 978 | * Copy the string and inode number into the new space. | ||
| 979 | */ | ||
| 980 | namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); | ||
| 981 | XFS_DIR_SF_PUT_DIRINO(&args->inumber, &namest->inumber); | ||
| 982 | memcpy(namest->name, args->name, args->namelen); | ||
| 983 | xfs_da_log_buf(args->trans, bp, | ||
| 984 | XFS_DA_LOGRANGE(leaf, namest, XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry))); | ||
| 985 | |||
| 986 | /* | ||
| 987 | * Update the control info for this leaf node | ||
| 988 | */ | ||
| 989 | if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) | ||
| 990 | INT_COPY(hdr->firstused, entry->nameidx, ARCH_CONVERT); | ||
| 991 | ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr))); | ||
| 992 | tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) * (uint)sizeof(xfs_dir_leaf_entry_t) | ||
| 993 | + (uint)sizeof(xfs_dir_leaf_hdr_t); | ||
| 994 | map = &hdr->freemap[0]; | ||
| 995 | for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) { | ||
| 996 | if (INT_GET(map->base, ARCH_CONVERT) == tmp) { | ||
| 997 | INT_MOD(map->base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t)); | ||
| 998 | INT_MOD(map->size, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t))); | ||
| 999 | } | ||
| 1000 | } | ||
| 1001 | INT_MOD(hdr->namebytes, ARCH_CONVERT, args->namelen); | ||
| 1002 | xfs_da_log_buf(args->trans, bp, | ||
| 1003 | XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | /* | ||
| 1007 | * Garbage collect a leaf directory block by copying it to a new buffer. | ||
| 1008 | */ | ||
| 1009 | STATIC int | ||
| 1010 | xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp, int musthave, | ||
| 1011 | int justcheck) | ||
| 1012 | { | ||
| 1013 | xfs_dir_leafblock_t *leaf_s, *leaf_d; | ||
| 1014 | xfs_dir_leaf_hdr_t *hdr_s, *hdr_d; | ||
| 1015 | xfs_mount_t *mp; | ||
| 1016 | char *tmpbuffer; | ||
| 1017 | char *tmpbuffer2=NULL; | ||
| 1018 | int rval; | ||
| 1019 | int lbsize; | ||
| 1020 | |||
| 1021 | mp = trans->t_mountp; | ||
| 1022 | lbsize = XFS_LBSIZE(mp); | ||
| 1023 | tmpbuffer = kmem_alloc(lbsize, KM_SLEEP); | ||
| 1024 | ASSERT(tmpbuffer != NULL); | ||
| 1025 | memcpy(tmpbuffer, bp->data, lbsize); | ||
| 1026 | |||
| 1027 | /* | ||
| 1028 | * Make a second copy in case xfs_dir_leaf_moveents() | ||
| 1029 | * below destroys the original. | ||
| 1030 | */ | ||
| 1031 | if (musthave || justcheck) { | ||
| 1032 | tmpbuffer2 = kmem_alloc(lbsize, KM_SLEEP); | ||
| 1033 | memcpy(tmpbuffer2, bp->data, lbsize); | ||
| 1034 | } | ||
| 1035 | memset(bp->data, 0, lbsize); | ||
| 1036 | |||
| 1037 | /* | ||
| 1038 | * Copy basic information | ||
| 1039 | */ | ||
| 1040 | leaf_s = (xfs_dir_leafblock_t *)tmpbuffer; | ||
| 1041 | leaf_d = bp->data; | ||
| 1042 | hdr_s = &leaf_s->hdr; | ||
| 1043 | hdr_d = &leaf_d->hdr; | ||
| 1044 | hdr_d->info = hdr_s->info; /* struct copy */ | ||
| 1045 | INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize); | ||
| 1046 | if (!hdr_d->firstused) | ||
| 1047 | INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize - 1); | ||
| 1048 | hdr_d->namebytes = 0; | ||
| 1049 | hdr_d->count = 0; | ||
| 1050 | hdr_d->holes = 0; | ||
| 1051 | INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t)); | ||
| 1052 | INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); | ||
| 1053 | |||
| 1054 | /* | ||
| 1055 | * Copy all entry's in the same (sorted) order, | ||
| 1056 | * but allocate filenames packed and in sequence. | ||
| 1057 | * This changes the source (leaf_s) as well. | ||
| 1058 | */ | ||
| 1059 | xfs_dir_leaf_moveents(leaf_s, 0, leaf_d, 0, (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp); | ||
| 1060 | |||
| 1061 | if (musthave && INT_GET(hdr_d->freemap[0].size, ARCH_CONVERT) < musthave) | ||
| 1062 | rval = XFS_ERROR(ENOSPC); | ||
| 1063 | else | ||
| 1064 | rval = 0; | ||
| 1065 | |||
| 1066 | if (justcheck || rval == ENOSPC) { | ||
| 1067 | ASSERT(tmpbuffer2); | ||
| 1068 | memcpy(bp->data, tmpbuffer2, lbsize); | ||
| 1069 | } else { | ||
| 1070 | xfs_da_log_buf(trans, bp, 0, lbsize - 1); | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | kmem_free(tmpbuffer, lbsize); | ||
| 1074 | if (musthave || justcheck) | ||
| 1075 | kmem_free(tmpbuffer2, lbsize); | ||
| 1076 | return rval; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | /* | ||
| 1080 | * Redistribute the directory entries between two leaf nodes, | ||
| 1081 | * taking into account the size of the new entry. | ||
| 1082 | * | ||
| 1083 | * NOTE: if new block is empty, then it will get the upper half of old block. | ||
| 1084 | */ | ||
| 1085 | STATIC void | ||
| 1086 | xfs_dir_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, | ||
| 1087 | xfs_da_state_blk_t *blk2) | ||
| 1088 | { | ||
| 1089 | xfs_da_state_blk_t *tmp_blk; | ||
| 1090 | xfs_dir_leafblock_t *leaf1, *leaf2; | ||
| 1091 | xfs_dir_leaf_hdr_t *hdr1, *hdr2; | ||
| 1092 | int count, totallen, max, space, swap; | ||
| 1093 | |||
| 1094 | /* | ||
| 1095 | * Set up environment. | ||
| 1096 | */ | ||
| 1097 | ASSERT(blk1->magic == XFS_DIR_LEAF_MAGIC); | ||
| 1098 | ASSERT(blk2->magic == XFS_DIR_LEAF_MAGIC); | ||
| 1099 | leaf1 = blk1->bp->data; | ||
| 1100 | leaf2 = blk2->bp->data; | ||
| 1101 | ASSERT(be16_to_cpu(leaf1->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1102 | ASSERT(be16_to_cpu(leaf2->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1103 | |||
| 1104 | /* | ||
| 1105 | * Check ordering of blocks, reverse if it makes things simpler. | ||
| 1106 | */ | ||
| 1107 | swap = 0; | ||
| 1108 | if (xfs_dir_leaf_order(blk1->bp, blk2->bp)) { | ||
| 1109 | tmp_blk = blk1; | ||
| 1110 | blk1 = blk2; | ||
| 1111 | blk2 = tmp_blk; | ||
| 1112 | leaf1 = blk1->bp->data; | ||
| 1113 | leaf2 = blk2->bp->data; | ||
| 1114 | swap = 1; | ||
| 1115 | } | ||
| 1116 | hdr1 = &leaf1->hdr; | ||
| 1117 | hdr2 = &leaf2->hdr; | ||
| 1118 | |||
| 1119 | /* | ||
| 1120 | * Examine entries until we reduce the absolute difference in | ||
| 1121 | * byte usage between the two blocks to a minimum. Then get | ||
| 1122 | * the direction to copy and the number of elements to move. | ||
| 1123 | */ | ||
| 1124 | state->inleaf = xfs_dir_leaf_figure_balance(state, blk1, blk2, | ||
| 1125 | &count, &totallen); | ||
| 1126 | if (swap) | ||
| 1127 | state->inleaf = !state->inleaf; | ||
| 1128 | |||
| 1129 | /* | ||
| 1130 | * Move any entries required from leaf to leaf: | ||
| 1131 | */ | ||
| 1132 | if (count < INT_GET(hdr1->count, ARCH_CONVERT)) { | ||
| 1133 | /* | ||
| 1134 | * Figure the total bytes to be added to the destination leaf. | ||
| 1135 | */ | ||
| 1136 | count = INT_GET(hdr1->count, ARCH_CONVERT) - count; /* number entries being moved */ | ||
| 1137 | space = INT_GET(hdr1->namebytes, ARCH_CONVERT) - totallen; | ||
| 1138 | space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1); | ||
| 1139 | space += count * (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1140 | |||
| 1141 | /* | ||
| 1142 | * leaf2 is the destination, compact it if it looks tight. | ||
| 1143 | */ | ||
| 1144 | max = INT_GET(hdr2->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t); | ||
| 1145 | max -= INT_GET(hdr2->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1146 | if (space > max) { | ||
| 1147 | xfs_dir_leaf_compact(state->args->trans, blk2->bp, | ||
| 1148 | 0, 0); | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | /* | ||
| 1152 | * Move high entries from leaf1 to low end of leaf2. | ||
| 1153 | */ | ||
| 1154 | xfs_dir_leaf_moveents(leaf1, INT_GET(hdr1->count, ARCH_CONVERT) - count, | ||
| 1155 | leaf2, 0, count, state->mp); | ||
| 1156 | |||
| 1157 | xfs_da_log_buf(state->args->trans, blk1->bp, 0, | ||
| 1158 | state->blocksize-1); | ||
| 1159 | xfs_da_log_buf(state->args->trans, blk2->bp, 0, | ||
| 1160 | state->blocksize-1); | ||
| 1161 | |||
| 1162 | } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) { | ||
| 1163 | /* | ||
| 1164 | * Figure the total bytes to be added to the destination leaf. | ||
| 1165 | */ | ||
| 1166 | count -= INT_GET(hdr1->count, ARCH_CONVERT); /* number entries being moved */ | ||
| 1167 | space = totallen - INT_GET(hdr1->namebytes, ARCH_CONVERT); | ||
| 1168 | space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1); | ||
| 1169 | space += count * (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1170 | |||
| 1171 | /* | ||
| 1172 | * leaf1 is the destination, compact it if it looks tight. | ||
| 1173 | */ | ||
| 1174 | max = INT_GET(hdr1->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t); | ||
| 1175 | max -= INT_GET(hdr1->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1176 | if (space > max) { | ||
| 1177 | xfs_dir_leaf_compact(state->args->trans, blk1->bp, | ||
| 1178 | 0, 0); | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | /* | ||
| 1182 | * Move low entries from leaf2 to high end of leaf1. | ||
| 1183 | */ | ||
| 1184 | xfs_dir_leaf_moveents(leaf2, 0, leaf1, (int)INT_GET(hdr1->count, ARCH_CONVERT), | ||
| 1185 | count, state->mp); | ||
| 1186 | |||
| 1187 | xfs_da_log_buf(state->args->trans, blk1->bp, 0, | ||
| 1188 | state->blocksize-1); | ||
| 1189 | xfs_da_log_buf(state->args->trans, blk2->bp, 0, | ||
| 1190 | state->blocksize-1); | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | /* | ||
| 1194 | * Copy out last hashval in each block for B-tree code. | ||
| 1195 | */ | ||
| 1196 | blk1->hashval = INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); | ||
| 1197 | blk2->hashval = INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); | ||
| 1198 | |||
| 1199 | /* | ||
| 1200 | * Adjust the expected index for insertion. | ||
| 1201 | * GROT: this doesn't work unless blk2 was originally empty. | ||
| 1202 | */ | ||
| 1203 | if (!state->inleaf) { | ||
| 1204 | blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT); | ||
| 1205 | } | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | /* | ||
| 1209 | * Examine entries until we reduce the absolute difference in | ||
| 1210 | * byte usage between the two blocks to a minimum. | ||
| 1211 | * GROT: Is this really necessary? With other than a 512 byte blocksize, | ||
| 1212 | * GROT: there will always be enough room in either block for a new entry. | ||
| 1213 | * GROT: Do a double-split for this case? | ||
| 1214 | */ | ||
| 1215 | STATIC int | ||
| 1216 | xfs_dir_leaf_figure_balance(xfs_da_state_t *state, | ||
| 1217 | xfs_da_state_blk_t *blk1, | ||
| 1218 | xfs_da_state_blk_t *blk2, | ||
| 1219 | int *countarg, int *namebytesarg) | ||
| 1220 | { | ||
| 1221 | xfs_dir_leafblock_t *leaf1, *leaf2; | ||
| 1222 | xfs_dir_leaf_hdr_t *hdr1, *hdr2; | ||
| 1223 | xfs_dir_leaf_entry_t *entry; | ||
| 1224 | int count, max, totallen, half; | ||
| 1225 | int lastdelta, foundit, tmp; | ||
| 1226 | |||
| 1227 | /* | ||
| 1228 | * Set up environment. | ||
| 1229 | */ | ||
| 1230 | leaf1 = blk1->bp->data; | ||
| 1231 | leaf2 = blk2->bp->data; | ||
| 1232 | hdr1 = &leaf1->hdr; | ||
| 1233 | hdr2 = &leaf2->hdr; | ||
| 1234 | foundit = 0; | ||
| 1235 | totallen = 0; | ||
| 1236 | |||
| 1237 | /* | ||
| 1238 | * Examine entries until we reduce the absolute difference in | ||
| 1239 | * byte usage between the two blocks to a minimum. | ||
| 1240 | */ | ||
| 1241 | max = INT_GET(hdr1->count, ARCH_CONVERT) + INT_GET(hdr2->count, ARCH_CONVERT); | ||
| 1242 | half = (max+1) * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1); | ||
| 1243 | half += INT_GET(hdr1->namebytes, ARCH_CONVERT) + INT_GET(hdr2->namebytes, ARCH_CONVERT) + state->args->namelen; | ||
| 1244 | half /= 2; | ||
| 1245 | lastdelta = state->blocksize; | ||
| 1246 | entry = &leaf1->entries[0]; | ||
| 1247 | for (count = 0; count < max; entry++, count++) { | ||
| 1248 | |||
| 1249 | #define XFS_DIR_ABS(A) (((A) < 0) ? -(A) : (A)) | ||
| 1250 | /* | ||
| 1251 | * The new entry is in the first block, account for it. | ||
| 1252 | */ | ||
| 1253 | if (count == blk1->index) { | ||
| 1254 | tmp = totallen + (uint)sizeof(*entry) | ||
| 1255 | + XFS_DIR_LEAF_ENTSIZE_BYNAME(state->args->namelen); | ||
| 1256 | if (XFS_DIR_ABS(half - tmp) > lastdelta) | ||
| 1257 | break; | ||
| 1258 | lastdelta = XFS_DIR_ABS(half - tmp); | ||
| 1259 | totallen = tmp; | ||
| 1260 | foundit = 1; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | /* | ||
| 1264 | * Wrap around into the second block if necessary. | ||
| 1265 | */ | ||
| 1266 | if (count == INT_GET(hdr1->count, ARCH_CONVERT)) { | ||
| 1267 | leaf1 = leaf2; | ||
| 1268 | entry = &leaf1->entries[0]; | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | /* | ||
| 1272 | * Figure out if next leaf entry would be too much. | ||
| 1273 | */ | ||
| 1274 | tmp = totallen + (uint)sizeof(*entry) | ||
| 1275 | + XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry); | ||
| 1276 | if (XFS_DIR_ABS(half - tmp) > lastdelta) | ||
| 1277 | break; | ||
| 1278 | lastdelta = XFS_DIR_ABS(half - tmp); | ||
| 1279 | totallen = tmp; | ||
| 1280 | #undef XFS_DIR_ABS | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | /* | ||
| 1284 | * Calculate the number of namebytes that will end up in lower block. | ||
| 1285 | * If new entry not in lower block, fix up the count. | ||
| 1286 | */ | ||
| 1287 | totallen -= | ||
| 1288 | count * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1); | ||
| 1289 | if (foundit) { | ||
| 1290 | totallen -= (sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1) + | ||
| 1291 | state->args->namelen; | ||
| 1292 | } | ||
| 1293 | |||
| 1294 | *countarg = count; | ||
| 1295 | *namebytesarg = totallen; | ||
| 1296 | return foundit; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | /*======================================================================== | ||
| 1300 | * Routines used for shrinking the Btree. | ||
| 1301 | *========================================================================*/ | ||
| 1302 | |||
| 1303 | /* | ||
| 1304 | * Check a leaf block and its neighbors to see if the block should be | ||
| 1305 | * collapsed into one or the other neighbor. Always keep the block | ||
| 1306 | * with the smaller block number. | ||
| 1307 | * If the current block is over 50% full, don't try to join it, return 0. | ||
| 1308 | * If the block is empty, fill in the state structure and return 2. | ||
| 1309 | * If it can be collapsed, fill in the state structure and return 1. | ||
| 1310 | * If nothing can be done, return 0. | ||
| 1311 | */ | ||
| 1312 | int | ||
| 1313 | xfs_dir_leaf_toosmall(xfs_da_state_t *state, int *action) | ||
| 1314 | { | ||
| 1315 | xfs_dir_leafblock_t *leaf; | ||
| 1316 | xfs_da_state_blk_t *blk; | ||
| 1317 | xfs_da_blkinfo_t *info; | ||
| 1318 | int count, bytes, forward, error, retval, i; | ||
| 1319 | xfs_dablk_t blkno; | ||
| 1320 | xfs_dabuf_t *bp; | ||
| 1321 | |||
| 1322 | /* | ||
| 1323 | * Check for the degenerate case of the block being over 50% full. | ||
| 1324 | * If so, it's not worth even looking to see if we might be able | ||
| 1325 | * to coalesce with a sibling. | ||
| 1326 | */ | ||
| 1327 | blk = &state->path.blk[ state->path.active-1 ]; | ||
| 1328 | info = blk->bp->data; | ||
| 1329 | ASSERT(be16_to_cpu(info->magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1330 | leaf = (xfs_dir_leafblock_t *)info; | ||
| 1331 | count = INT_GET(leaf->hdr.count, ARCH_CONVERT); | ||
| 1332 | bytes = (uint)sizeof(xfs_dir_leaf_hdr_t) + | ||
| 1333 | count * (uint)sizeof(xfs_dir_leaf_entry_t) + | ||
| 1334 | count * ((uint)sizeof(xfs_dir_leaf_name_t)-1) + | ||
| 1335 | INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); | ||
| 1336 | if (bytes > (state->blocksize >> 1)) { | ||
| 1337 | *action = 0; /* blk over 50%, don't try to join */ | ||
| 1338 | return 0; | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | /* | ||
| 1342 | * Check for the degenerate case of the block being empty. | ||
| 1343 | * If the block is empty, we'll simply delete it, no need to | ||
| 1344 | * coalesce it with a sibling block. We choose (arbitrarily) | ||
| 1345 | * to merge with the forward block unless it is NULL. | ||
| 1346 | */ | ||
| 1347 | if (count == 0) { | ||
| 1348 | /* | ||
| 1349 | * Make altpath point to the block we want to keep and | ||
| 1350 | * path point to the block we want to drop (this one). | ||
| 1351 | */ | ||
| 1352 | forward = (info->forw != 0); | ||
| 1353 | memcpy(&state->altpath, &state->path, sizeof(state->path)); | ||
| 1354 | error = xfs_da_path_shift(state, &state->altpath, forward, | ||
| 1355 | 0, &retval); | ||
| 1356 | if (error) | ||
| 1357 | return error; | ||
| 1358 | if (retval) { | ||
| 1359 | *action = 0; | ||
| 1360 | } else { | ||
| 1361 | *action = 2; | ||
| 1362 | } | ||
| 1363 | return 0; | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | /* | ||
| 1367 | * Examine each sibling block to see if we can coalesce with | ||
| 1368 | * at least 25% free space to spare. We need to figure out | ||
| 1369 | * whether to merge with the forward or the backward block. | ||
| 1370 | * We prefer coalescing with the lower numbered sibling so as | ||
| 1371 | * to shrink a directory over time. | ||
| 1372 | */ | ||
| 1373 | forward = (be32_to_cpu(info->forw) < be32_to_cpu(info->back)); /* start with smaller blk num */ | ||
| 1374 | for (i = 0; i < 2; forward = !forward, i++) { | ||
| 1375 | if (forward) | ||
| 1376 | blkno = be32_to_cpu(info->forw); | ||
| 1377 | else | ||
| 1378 | blkno = be32_to_cpu(info->back); | ||
| 1379 | if (blkno == 0) | ||
| 1380 | continue; | ||
| 1381 | error = xfs_da_read_buf(state->args->trans, state->args->dp, | ||
| 1382 | blkno, -1, &bp, | ||
| 1383 | XFS_DATA_FORK); | ||
| 1384 | if (error) | ||
| 1385 | return error; | ||
| 1386 | ASSERT(bp != NULL); | ||
| 1387 | |||
| 1388 | leaf = (xfs_dir_leafblock_t *)info; | ||
| 1389 | count = INT_GET(leaf->hdr.count, ARCH_CONVERT); | ||
| 1390 | bytes = state->blocksize - (state->blocksize>>2); | ||
| 1391 | bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); | ||
| 1392 | leaf = bp->data; | ||
| 1393 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1394 | count += INT_GET(leaf->hdr.count, ARCH_CONVERT); | ||
| 1395 | bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); | ||
| 1396 | bytes -= count * ((uint)sizeof(xfs_dir_leaf_name_t) - 1); | ||
| 1397 | bytes -= count * (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1398 | bytes -= (uint)sizeof(xfs_dir_leaf_hdr_t); | ||
| 1399 | if (bytes >= 0) | ||
| 1400 | break; /* fits with at least 25% to spare */ | ||
| 1401 | |||
| 1402 | xfs_da_brelse(state->args->trans, bp); | ||
| 1403 | } | ||
| 1404 | if (i >= 2) { | ||
| 1405 | *action = 0; | ||
| 1406 | return 0; | ||
| 1407 | } | ||
| 1408 | xfs_da_buf_done(bp); | ||
| 1409 | |||
| 1410 | /* | ||
| 1411 | * Make altpath point to the block we want to keep (the lower | ||
| 1412 | * numbered block) and path point to the block we want to drop. | ||
| 1413 | */ | ||
| 1414 | memcpy(&state->altpath, &state->path, sizeof(state->path)); | ||
| 1415 | if (blkno < blk->blkno) { | ||
| 1416 | error = xfs_da_path_shift(state, &state->altpath, forward, | ||
| 1417 | 0, &retval); | ||
| 1418 | } else { | ||
| 1419 | error = xfs_da_path_shift(state, &state->path, forward, | ||
| 1420 | 0, &retval); | ||
| 1421 | } | ||
| 1422 | if (error) | ||
| 1423 | return error; | ||
| 1424 | if (retval) { | ||
| 1425 | *action = 0; | ||
| 1426 | } else { | ||
| 1427 | *action = 1; | ||
| 1428 | } | ||
| 1429 | return 0; | ||
| 1430 | } | ||
| 1431 | |||
| 1432 | /* | ||
| 1433 | * Remove a name from the leaf directory structure. | ||
| 1434 | * | ||
| 1435 | * Return 1 if leaf is less than 37% full, 0 if >= 37% full. | ||
| 1436 | * If two leaves are 37% full, when combined they will leave 25% free. | ||
| 1437 | */ | ||
| 1438 | int | ||
| 1439 | xfs_dir_leaf_remove(xfs_trans_t *trans, xfs_dabuf_t *bp, int index) | ||
| 1440 | { | ||
| 1441 | xfs_dir_leafblock_t *leaf; | ||
| 1442 | xfs_dir_leaf_hdr_t *hdr; | ||
| 1443 | xfs_dir_leaf_map_t *map; | ||
| 1444 | xfs_dir_leaf_entry_t *entry; | ||
| 1445 | xfs_dir_leaf_name_t *namest; | ||
| 1446 | int before, after, smallest, entsize; | ||
| 1447 | int tablesize, tmp, i; | ||
| 1448 | xfs_mount_t *mp; | ||
| 1449 | |||
| 1450 | leaf = bp->data; | ||
| 1451 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1452 | hdr = &leaf->hdr; | ||
| 1453 | mp = trans->t_mountp; | ||
| 1454 | ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0) && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); | ||
| 1455 | ASSERT((index >= 0) && (index < INT_GET(hdr->count, ARCH_CONVERT))); | ||
| 1456 | ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr))); | ||
| 1457 | entry = &leaf->entries[index]; | ||
| 1458 | ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT)); | ||
| 1459 | ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); | ||
| 1460 | |||
| 1461 | /* | ||
| 1462 | * Scan through free region table: | ||
| 1463 | * check for adjacency of free'd entry with an existing one, | ||
| 1464 | * find smallest free region in case we need to replace it, | ||
| 1465 | * adjust any map that borders the entry table, | ||
| 1466 | */ | ||
| 1467 | tablesize = INT_GET(hdr->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t) | ||
| 1468 | + (uint)sizeof(xfs_dir_leaf_hdr_t); | ||
| 1469 | map = &hdr->freemap[0]; | ||
| 1470 | tmp = INT_GET(map->size, ARCH_CONVERT); | ||
| 1471 | before = after = -1; | ||
| 1472 | smallest = XFS_DIR_LEAF_MAPSIZE - 1; | ||
| 1473 | entsize = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry); | ||
| 1474 | for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) { | ||
| 1475 | ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); | ||
| 1476 | ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); | ||
| 1477 | if (INT_GET(map->base, ARCH_CONVERT) == tablesize) { | ||
| 1478 | INT_MOD(map->base, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t))); | ||
| 1479 | INT_MOD(map->size, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t)); | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == INT_GET(entry->nameidx, ARCH_CONVERT)) { | ||
| 1483 | before = i; | ||
| 1484 | } else if (INT_GET(map->base, ARCH_CONVERT) == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) { | ||
| 1485 | after = i; | ||
| 1486 | } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) { | ||
| 1487 | tmp = INT_GET(map->size, ARCH_CONVERT); | ||
| 1488 | smallest = i; | ||
| 1489 | } | ||
| 1490 | } | ||
| 1491 | |||
| 1492 | /* | ||
| 1493 | * Coalesce adjacent freemap regions, | ||
| 1494 | * or replace the smallest region. | ||
| 1495 | */ | ||
| 1496 | if ((before >= 0) || (after >= 0)) { | ||
| 1497 | if ((before >= 0) && (after >= 0)) { | ||
| 1498 | map = &hdr->freemap[before]; | ||
| 1499 | INT_MOD(map->size, ARCH_CONVERT, entsize); | ||
| 1500 | INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT)); | ||
| 1501 | hdr->freemap[after].base = 0; | ||
| 1502 | hdr->freemap[after].size = 0; | ||
| 1503 | } else if (before >= 0) { | ||
| 1504 | map = &hdr->freemap[before]; | ||
| 1505 | INT_MOD(map->size, ARCH_CONVERT, entsize); | ||
| 1506 | } else { | ||
| 1507 | map = &hdr->freemap[after]; | ||
| 1508 | INT_COPY(map->base, entry->nameidx, ARCH_CONVERT); | ||
| 1509 | INT_MOD(map->size, ARCH_CONVERT, entsize); | ||
| 1510 | } | ||
| 1511 | } else { | ||
| 1512 | /* | ||
| 1513 | * Replace smallest region (if it is smaller than free'd entry) | ||
| 1514 | */ | ||
| 1515 | map = &hdr->freemap[smallest]; | ||
| 1516 | if (INT_GET(map->size, ARCH_CONVERT) < entsize) { | ||
| 1517 | INT_COPY(map->base, entry->nameidx, ARCH_CONVERT); | ||
| 1518 | INT_SET(map->size, ARCH_CONVERT, entsize); | ||
| 1519 | } | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | /* | ||
| 1523 | * Did we remove the first entry? | ||
| 1524 | */ | ||
| 1525 | if (INT_GET(entry->nameidx, ARCH_CONVERT) == INT_GET(hdr->firstused, ARCH_CONVERT)) | ||
| 1526 | smallest = 1; | ||
| 1527 | else | ||
| 1528 | smallest = 0; | ||
| 1529 | |||
| 1530 | /* | ||
| 1531 | * Compress the remaining entries and zero out the removed stuff. | ||
| 1532 | */ | ||
| 1533 | namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); | ||
| 1534 | memset((char *)namest, 0, entsize); | ||
| 1535 | xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, namest, entsize)); | ||
| 1536 | |||
| 1537 | INT_MOD(hdr->namebytes, ARCH_CONVERT, -(entry->namelen)); | ||
| 1538 | tmp = (INT_GET(hdr->count, ARCH_CONVERT) - index) * (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1539 | memmove(entry, entry + 1, tmp); | ||
| 1540 | INT_MOD(hdr->count, ARCH_CONVERT, -1); | ||
| 1541 | xfs_da_log_buf(trans, bp, | ||
| 1542 | XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry))); | ||
| 1543 | entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)]; | ||
| 1544 | memset((char *)entry, 0, sizeof(xfs_dir_leaf_entry_t)); | ||
| 1545 | |||
| 1546 | /* | ||
| 1547 | * If we removed the first entry, re-find the first used byte | ||
| 1548 | * in the name area. Note that if the entry was the "firstused", | ||
| 1549 | * then we don't have a "hole" in our block resulting from | ||
| 1550 | * removing the name. | ||
| 1551 | */ | ||
| 1552 | if (smallest) { | ||
| 1553 | tmp = XFS_LBSIZE(mp); | ||
| 1554 | entry = &leaf->entries[0]; | ||
| 1555 | for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) { | ||
| 1556 | ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT)); | ||
| 1557 | ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); | ||
| 1558 | if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp) | ||
| 1559 | tmp = INT_GET(entry->nameidx, ARCH_CONVERT); | ||
| 1560 | } | ||
| 1561 | INT_SET(hdr->firstused, ARCH_CONVERT, tmp); | ||
| 1562 | if (!hdr->firstused) | ||
| 1563 | INT_SET(hdr->firstused, ARCH_CONVERT, tmp - 1); | ||
| 1564 | } else { | ||
| 1565 | hdr->holes = 1; /* mark as needing compaction */ | ||
| 1566 | } | ||
| 1567 | |||
| 1568 | xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); | ||
| 1569 | |||
| 1570 | /* | ||
| 1571 | * Check if leaf is less than 50% full, caller may want to | ||
| 1572 | * "join" the leaf with a sibling if so. | ||
| 1573 | */ | ||
| 1574 | tmp = (uint)sizeof(xfs_dir_leaf_hdr_t); | ||
| 1575 | tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1576 | tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * ((uint)sizeof(xfs_dir_leaf_name_t) - 1); | ||
| 1577 | tmp += INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); | ||
| 1578 | if (tmp < mp->m_dir_magicpct) | ||
| 1579 | return 1; /* leaf is < 37% full */ | ||
| 1580 | return 0; | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | /* | ||
| 1584 | * Move all the directory entries from drop_leaf into save_leaf. | ||
| 1585 | */ | ||
| 1586 | void | ||
| 1587 | xfs_dir_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, | ||
| 1588 | xfs_da_state_blk_t *save_blk) | ||
| 1589 | { | ||
| 1590 | xfs_dir_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf; | ||
| 1591 | xfs_dir_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr; | ||
| 1592 | xfs_mount_t *mp; | ||
| 1593 | char *tmpbuffer; | ||
| 1594 | |||
| 1595 | /* | ||
| 1596 | * Set up environment. | ||
| 1597 | */ | ||
| 1598 | mp = state->mp; | ||
| 1599 | ASSERT(drop_blk->magic == XFS_DIR_LEAF_MAGIC); | ||
| 1600 | ASSERT(save_blk->magic == XFS_DIR_LEAF_MAGIC); | ||
| 1601 | drop_leaf = drop_blk->bp->data; | ||
| 1602 | save_leaf = save_blk->bp->data; | ||
| 1603 | ASSERT(be16_to_cpu(drop_leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1604 | ASSERT(be16_to_cpu(save_leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1605 | drop_hdr = &drop_leaf->hdr; | ||
| 1606 | save_hdr = &save_leaf->hdr; | ||
| 1607 | |||
| 1608 | /* | ||
| 1609 | * Save last hashval from dying block for later Btree fixup. | ||
| 1610 | */ | ||
| 1611 | drop_blk->hashval = INT_GET(drop_leaf->entries[ drop_leaf->hdr.count-1 ].hashval, ARCH_CONVERT); | ||
| 1612 | |||
| 1613 | /* | ||
| 1614 | * Check if we need a temp buffer, or can we do it in place. | ||
| 1615 | * Note that we don't check "leaf" for holes because we will | ||
| 1616 | * always be dropping it, toosmall() decided that for us already. | ||
| 1617 | */ | ||
| 1618 | if (save_hdr->holes == 0) { | ||
| 1619 | /* | ||
| 1620 | * dest leaf has no holes, so we add there. May need | ||
| 1621 | * to make some room in the entry array. | ||
| 1622 | */ | ||
| 1623 | if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) { | ||
| 1624 | xfs_dir_leaf_moveents(drop_leaf, 0, save_leaf, 0, | ||
| 1625 | (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); | ||
| 1626 | } else { | ||
| 1627 | xfs_dir_leaf_moveents(drop_leaf, 0, | ||
| 1628 | save_leaf, INT_GET(save_hdr->count, ARCH_CONVERT), | ||
| 1629 | (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); | ||
| 1630 | } | ||
| 1631 | } else { | ||
| 1632 | /* | ||
| 1633 | * Destination has holes, so we make a temporary copy | ||
| 1634 | * of the leaf and add them both to that. | ||
| 1635 | */ | ||
| 1636 | tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP); | ||
| 1637 | ASSERT(tmpbuffer != NULL); | ||
| 1638 | memset(tmpbuffer, 0, state->blocksize); | ||
| 1639 | tmp_leaf = (xfs_dir_leafblock_t *)tmpbuffer; | ||
| 1640 | tmp_hdr = &tmp_leaf->hdr; | ||
| 1641 | tmp_hdr->info = save_hdr->info; /* struct copy */ | ||
| 1642 | tmp_hdr->count = 0; | ||
| 1643 | INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize); | ||
| 1644 | if (!tmp_hdr->firstused) | ||
| 1645 | INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize - 1); | ||
| 1646 | tmp_hdr->namebytes = 0; | ||
| 1647 | if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) { | ||
| 1648 | xfs_dir_leaf_moveents(drop_leaf, 0, tmp_leaf, 0, | ||
| 1649 | (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); | ||
| 1650 | xfs_dir_leaf_moveents(save_leaf, 0, | ||
| 1651 | tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), | ||
| 1652 | (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp); | ||
| 1653 | } else { | ||
| 1654 | xfs_dir_leaf_moveents(save_leaf, 0, tmp_leaf, 0, | ||
| 1655 | (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp); | ||
| 1656 | xfs_dir_leaf_moveents(drop_leaf, 0, | ||
| 1657 | tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), | ||
| 1658 | (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); | ||
| 1659 | } | ||
| 1660 | memcpy(save_leaf, tmp_leaf, state->blocksize); | ||
| 1661 | kmem_free(tmpbuffer, state->blocksize); | ||
| 1662 | } | ||
| 1663 | |||
| 1664 | xfs_da_log_buf(state->args->trans, save_blk->bp, 0, | ||
| 1665 | state->blocksize - 1); | ||
| 1666 | |||
| 1667 | /* | ||
| 1668 | * Copy out last hashval in each block for B-tree code. | ||
| 1669 | */ | ||
| 1670 | save_blk->hashval = INT_GET(save_leaf->entries[ INT_GET(save_leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); | ||
| 1671 | } | ||
| 1672 | |||
| 1673 | /*======================================================================== | ||
| 1674 | * Routines used for finding things in the Btree. | ||
| 1675 | *========================================================================*/ | ||
| 1676 | |||
| 1677 | /* | ||
| 1678 | * Look up a name in a leaf directory structure. | ||
| 1679 | * This is the internal routine, it uses the caller's buffer. | ||
| 1680 | * | ||
| 1681 | * Note that duplicate keys are allowed, but only check within the | ||
| 1682 | * current leaf node. The Btree code must check in adjacent leaf nodes. | ||
| 1683 | * | ||
| 1684 | * Return in *index the index into the entry[] array of either the found | ||
| 1685 | * entry, or where the entry should have been (insert before that entry). | ||
| 1686 | * | ||
| 1687 | * Don't change the args->inumber unless we find the filename. | ||
| 1688 | */ | ||
| 1689 | int | ||
| 1690 | xfs_dir_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args, int *index) | ||
| 1691 | { | ||
| 1692 | xfs_dir_leafblock_t *leaf; | ||
| 1693 | xfs_dir_leaf_entry_t *entry; | ||
| 1694 | xfs_dir_leaf_name_t *namest; | ||
| 1695 | int probe, span; | ||
| 1696 | xfs_dahash_t hashval; | ||
| 1697 | |||
| 1698 | leaf = bp->data; | ||
| 1699 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1700 | ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) < (XFS_LBSIZE(args->dp->i_mount)/8)); | ||
| 1701 | |||
| 1702 | /* | ||
| 1703 | * Binary search. (note: small blocks will skip this loop) | ||
| 1704 | */ | ||
| 1705 | hashval = args->hashval; | ||
| 1706 | probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2; | ||
| 1707 | for (entry = &leaf->entries[probe]; span > 4; | ||
| 1708 | entry = &leaf->entries[probe]) { | ||
| 1709 | span /= 2; | ||
| 1710 | if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval) | ||
| 1711 | probe += span; | ||
| 1712 | else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval) | ||
| 1713 | probe -= span; | ||
| 1714 | else | ||
| 1715 | break; | ||
| 1716 | } | ||
| 1717 | ASSERT((probe >= 0) && \ | ||
| 1718 | ((!leaf->hdr.count) || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)))); | ||
| 1719 | ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)); | ||
| 1720 | |||
| 1721 | /* | ||
| 1722 | * Since we may have duplicate hashval's, find the first matching | ||
| 1723 | * hashval in the leaf. | ||
| 1724 | */ | ||
| 1725 | while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT) >= hashval)) { | ||
| 1726 | entry--; | ||
| 1727 | probe--; | ||
| 1728 | } | ||
| 1729 | while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) { | ||
| 1730 | entry++; | ||
| 1731 | probe++; | ||
| 1732 | } | ||
| 1733 | if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT)) || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) { | ||
| 1734 | *index = probe; | ||
| 1735 | ASSERT(args->oknoent); | ||
| 1736 | return XFS_ERROR(ENOENT); | ||
| 1737 | } | ||
| 1738 | |||
| 1739 | /* | ||
| 1740 | * Duplicate keys may be present, so search all of them for a match. | ||
| 1741 | */ | ||
| 1742 | while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)) { | ||
| 1743 | namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); | ||
| 1744 | if (entry->namelen == args->namelen && | ||
| 1745 | namest->name[0] == args->name[0] && | ||
| 1746 | memcmp(args->name, namest->name, args->namelen) == 0) { | ||
| 1747 | XFS_DIR_SF_GET_DIRINO(&namest->inumber, &args->inumber); | ||
| 1748 | *index = probe; | ||
| 1749 | return XFS_ERROR(EEXIST); | ||
| 1750 | } | ||
| 1751 | entry++; | ||
| 1752 | probe++; | ||
| 1753 | } | ||
| 1754 | *index = probe; | ||
| 1755 | ASSERT(probe == INT_GET(leaf->hdr.count, ARCH_CONVERT) || args->oknoent); | ||
| 1756 | return XFS_ERROR(ENOENT); | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | /*======================================================================== | ||
| 1760 | * Utility routines. | ||
| 1761 | *========================================================================*/ | ||
| 1762 | |||
| 1763 | /* | ||
| 1764 | * Move the indicated entries from one leaf to another. | ||
| 1765 | * NOTE: this routine modifies both source and destination leaves. | ||
| 1766 | */ | ||
| 1767 | /* ARGSUSED */ | ||
| 1768 | STATIC void | ||
| 1769 | xfs_dir_leaf_moveents(xfs_dir_leafblock_t *leaf_s, int start_s, | ||
| 1770 | xfs_dir_leafblock_t *leaf_d, int start_d, | ||
| 1771 | int count, xfs_mount_t *mp) | ||
| 1772 | { | ||
| 1773 | xfs_dir_leaf_hdr_t *hdr_s, *hdr_d; | ||
| 1774 | xfs_dir_leaf_entry_t *entry_s, *entry_d; | ||
| 1775 | int tmp, i; | ||
| 1776 | |||
| 1777 | /* | ||
| 1778 | * Check for nothing to do. | ||
| 1779 | */ | ||
| 1780 | if (count == 0) | ||
| 1781 | return; | ||
| 1782 | |||
| 1783 | /* | ||
| 1784 | * Set up environment. | ||
| 1785 | */ | ||
| 1786 | ASSERT(be16_to_cpu(leaf_s->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1787 | ASSERT(be16_to_cpu(leaf_d->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1788 | hdr_s = &leaf_s->hdr; | ||
| 1789 | hdr_d = &leaf_d->hdr; | ||
| 1790 | ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0) && (INT_GET(hdr_s->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); | ||
| 1791 | ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >= | ||
| 1792 | ((INT_GET(hdr_s->count, ARCH_CONVERT)*sizeof(*entry_s))+sizeof(*hdr_s))); | ||
| 1793 | ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)); | ||
| 1794 | ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= | ||
| 1795 | ((INT_GET(hdr_d->count, ARCH_CONVERT)*sizeof(*entry_d))+sizeof(*hdr_d))); | ||
| 1796 | |||
| 1797 | ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT)); | ||
| 1798 | ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT)); | ||
| 1799 | ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT)); | ||
| 1800 | |||
| 1801 | /* | ||
| 1802 | * Move the entries in the destination leaf up to make a hole? | ||
| 1803 | */ | ||
| 1804 | if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) { | ||
| 1805 | tmp = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d; | ||
| 1806 | tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1807 | entry_s = &leaf_d->entries[start_d]; | ||
| 1808 | entry_d = &leaf_d->entries[start_d + count]; | ||
| 1809 | memcpy(entry_d, entry_s, tmp); | ||
| 1810 | } | ||
| 1811 | |||
| 1812 | /* | ||
| 1813 | * Copy all entry's in the same (sorted) order, | ||
| 1814 | * but allocate filenames packed and in sequence. | ||
| 1815 | */ | ||
| 1816 | entry_s = &leaf_s->entries[start_s]; | ||
| 1817 | entry_d = &leaf_d->entries[start_d]; | ||
| 1818 | for (i = 0; i < count; entry_s++, entry_d++, i++) { | ||
| 1819 | ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) >= INT_GET(hdr_s->firstused, ARCH_CONVERT)); | ||
| 1820 | tmp = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry_s); | ||
| 1821 | INT_MOD(hdr_d->firstused, ARCH_CONVERT, -(tmp)); | ||
| 1822 | entry_d->hashval = entry_s->hashval; /* INT_: direct copy */ | ||
| 1823 | INT_COPY(entry_d->nameidx, hdr_d->firstused, ARCH_CONVERT); | ||
| 1824 | entry_d->namelen = entry_s->namelen; | ||
| 1825 | ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp)); | ||
| 1826 | memcpy(XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)), | ||
| 1827 | XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), tmp); | ||
| 1828 | ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp)); | ||
| 1829 | memset((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), | ||
| 1830 | 0, tmp); | ||
| 1831 | INT_MOD(hdr_s->namebytes, ARCH_CONVERT, -(entry_d->namelen)); | ||
| 1832 | INT_MOD(hdr_d->namebytes, ARCH_CONVERT, entry_d->namelen); | ||
| 1833 | INT_MOD(hdr_s->count, ARCH_CONVERT, -1); | ||
| 1834 | INT_MOD(hdr_d->count, ARCH_CONVERT, +1); | ||
| 1835 | tmp = INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t) | ||
| 1836 | + (uint)sizeof(xfs_dir_leaf_hdr_t); | ||
| 1837 | ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp); | ||
| 1838 | |||
| 1839 | } | ||
| 1840 | |||
| 1841 | /* | ||
| 1842 | * Zero out the entries we just copied. | ||
| 1843 | */ | ||
| 1844 | if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) { | ||
| 1845 | tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1846 | entry_s = &leaf_s->entries[start_s]; | ||
| 1847 | ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp)); | ||
| 1848 | memset((char *)entry_s, 0, tmp); | ||
| 1849 | } else { | ||
| 1850 | /* | ||
| 1851 | * Move the remaining entries down to fill the hole, | ||
| 1852 | * then zero the entries at the top. | ||
| 1853 | */ | ||
| 1854 | tmp = INT_GET(hdr_s->count, ARCH_CONVERT) - count; | ||
| 1855 | tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1856 | entry_s = &leaf_s->entries[start_s + count]; | ||
| 1857 | entry_d = &leaf_s->entries[start_s]; | ||
| 1858 | memcpy(entry_d, entry_s, tmp); | ||
| 1859 | |||
| 1860 | tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t); | ||
| 1861 | entry_s = &leaf_s->entries[INT_GET(hdr_s->count, ARCH_CONVERT)]; | ||
| 1862 | ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp)); | ||
| 1863 | memset((char *)entry_s, 0, tmp); | ||
| 1864 | } | ||
| 1865 | |||
| 1866 | /* | ||
| 1867 | * Fill in the freemap information | ||
| 1868 | */ | ||
| 1869 | INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_hdr_t)); | ||
| 1870 | INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t)); | ||
| 1871 | INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); | ||
| 1872 | INT_SET(hdr_d->freemap[1].base, ARCH_CONVERT, (hdr_d->freemap[2].base = 0)); | ||
| 1873 | INT_SET(hdr_d->freemap[1].size, ARCH_CONVERT, (hdr_d->freemap[2].size = 0)); | ||
| 1874 | hdr_s->holes = 1; /* leaf may not be compact */ | ||
| 1875 | } | ||
| 1876 | |||
| 1877 | /* | ||
| 1878 | * Compare two leaf blocks "order". | ||
| 1879 | */ | ||
| 1880 | int | ||
| 1881 | xfs_dir_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp) | ||
| 1882 | { | ||
| 1883 | xfs_dir_leafblock_t *leaf1, *leaf2; | ||
| 1884 | |||
| 1885 | leaf1 = leaf1_bp->data; | ||
| 1886 | leaf2 = leaf2_bp->data; | ||
| 1887 | ASSERT((be16_to_cpu(leaf1->hdr.info.magic) == XFS_DIR_LEAF_MAGIC) && | ||
| 1888 | (be16_to_cpu(leaf2->hdr.info.magic) == XFS_DIR_LEAF_MAGIC)); | ||
| 1889 | if ((INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0) && | ||
| 1890 | ((INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) < | ||
| 1891 | INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) || | ||
| 1892 | (INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < | ||
| 1893 | INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) { | ||
| 1894 | return 1; | ||
| 1895 | } | ||
| 1896 | return 0; | ||
| 1897 | } | ||
| 1898 | |||
| 1899 | /* | ||
| 1900 | * Pick up the last hashvalue from a leaf block. | ||
| 1901 | */ | ||
| 1902 | xfs_dahash_t | ||
| 1903 | xfs_dir_leaf_lasthash(xfs_dabuf_t *bp, int *count) | ||
| 1904 | { | ||
| 1905 | xfs_dir_leafblock_t *leaf; | ||
| 1906 | |||
| 1907 | leaf = bp->data; | ||
| 1908 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR_LEAF_MAGIC); | ||
| 1909 | if (count) | ||
| 1910 | *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); | ||
| 1911 | if (!leaf->hdr.count) | ||
| 1912 | return(0); | ||
| 1913 | return(INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)); | ||
| 1914 | } | ||
| 1915 | |||
| 1916 | /* | ||
| 1917 | * Copy out directory entries for getdents(), for leaf directories. | ||
| 1918 | */ | ||
| 1919 | int | ||
| 1920 | xfs_dir_leaf_getdents_int( | ||
| 1921 | xfs_dabuf_t *bp, | ||
| 1922 | xfs_inode_t *dp, | ||
| 1923 | xfs_dablk_t bno, | ||
| 1924 | uio_t *uio, | ||
| 1925 | int *eobp, | ||
| 1926 | xfs_dirent_t *dbp, | ||
| 1927 | xfs_dir_put_t put, | ||
| 1928 | xfs_daddr_t nextda) | ||
| 1929 | { | ||
| 1930 | xfs_dir_leafblock_t *leaf; | ||
| 1931 | xfs_dir_leaf_entry_t *entry; | ||
| 1932 | xfs_dir_leaf_name_t *namest; | ||
| 1933 | int entno, want_entno, i, nextentno; | ||
| 1934 | xfs_mount_t *mp; | ||
| 1935 | xfs_dahash_t cookhash; | ||
| 1936 | xfs_dahash_t nexthash = 0; | ||
| 1937 | #if (BITS_PER_LONG == 32) | ||
| 1938 | xfs_dahash_t lasthash = XFS_DA_MAXHASH; | ||
| 1939 | #endif | ||
| 1940 | xfs_dir_put_args_t p; | ||
| 1941 | |||
| 1942 | mp = dp->i_mount; | ||
| 1943 | leaf = bp->data; | ||
| 1944 | if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR_LEAF_MAGIC) { | ||
| 1945 | *eobp = 1; | ||
| 1946 | return XFS_ERROR(ENOENT); /* XXX wrong code */ | ||
| 1947 | } | ||
| 1948 | |||
| 1949 | want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset); | ||
| 1950 | |||
| 1951 | cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset); | ||
| 1952 | |||
| 1953 | xfs_dir_trace_g_dul("leaf: start", dp, uio, leaf); | ||
| 1954 | |||
| 1955 | /* | ||
| 1956 | * Re-find our place. | ||
| 1957 | */ | ||
| 1958 | for (i = entno = 0, entry = &leaf->entries[0]; | ||
| 1959 | i < INT_GET(leaf->hdr.count, ARCH_CONVERT); | ||
| 1960 | entry++, i++) { | ||
| 1961 | |||
| 1962 | namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, | ||
| 1963 | INT_GET(entry->nameidx, ARCH_CONVERT)); | ||
| 1964 | |||
| 1965 | if (unlikely( | ||
| 1966 | ((char *)namest < (char *)leaf) || | ||
| 1967 | ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)))) { | ||
| 1968 | XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(1)", | ||
| 1969 | XFS_ERRLEVEL_LOW, mp, leaf); | ||
| 1970 | xfs_dir_trace_g_du("leaf: corrupted", dp, uio); | ||
| 1971 | return XFS_ERROR(EFSCORRUPTED); | ||
| 1972 | } | ||
| 1973 | if (INT_GET(entry->hashval, ARCH_CONVERT) >= cookhash) { | ||
| 1974 | if ( entno < want_entno | ||
| 1975 | && INT_GET(entry->hashval, ARCH_CONVERT) | ||
| 1976 | == cookhash) { | ||
| 1977 | /* | ||
| 1978 | * Trying to get to a particular offset in a | ||
| 1979 | * run of equal-hashval entries. | ||
| 1980 | */ | ||
| 1981 | entno++; | ||
| 1982 | } else if ( want_entno > 0 | ||
| 1983 | && entno == want_entno | ||
| 1984 | && INT_GET(entry->hashval, ARCH_CONVERT) | ||
| 1985 | == cookhash) { | ||
| 1986 | break; | ||
| 1987 | } else { | ||
| 1988 | entno = 0; | ||
| 1989 | break; | ||
| 1990 | } | ||
| 1991 | } | ||
| 1992 | } | ||
| 1993 | |||
| 1994 | if (i == INT_GET(leaf->hdr.count, ARCH_CONVERT)) { | ||
| 1995 | xfs_dir_trace_g_du("leaf: hash not found", dp, uio); | ||
| 1996 | if (!leaf->hdr.info.forw) | ||
| 1997 | uio->uio_offset = | ||
| 1998 | XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH); | ||
| 1999 | /* | ||
| 2000 | * Don't set uio_offset if there's another block: | ||
| 2001 | * the node code will be setting uio_offset anyway. | ||
| 2002 | */ | ||
| 2003 | *eobp = 0; | ||
| 2004 | return 0; | ||
| 2005 | } | ||
| 2006 | xfs_dir_trace_g_due("leaf: hash found", dp, uio, entry); | ||
| 2007 | |||
| 2008 | p.dbp = dbp; | ||
| 2009 | p.put = put; | ||
| 2010 | p.uio = uio; | ||
| 2011 | |||
| 2012 | /* | ||
| 2013 | * We're synchronized, start copying entries out to the user. | ||
| 2014 | */ | ||
| 2015 | for (; entno >= 0 && i < INT_GET(leaf->hdr.count, ARCH_CONVERT); | ||
| 2016 | entry++, i++, (entno = nextentno)) { | ||
| 2017 | int lastresid=0, retval; | ||
| 2018 | xfs_dircook_t lastoffset; | ||
| 2019 | xfs_dahash_t thishash; | ||
| 2020 | |||
| 2021 | /* | ||
| 2022 | * Check for a damaged directory leaf block and pick up | ||
| 2023 | * the inode number from this entry. | ||
| 2024 | */ | ||
| 2025 | namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, | ||
| 2026 | INT_GET(entry->nameidx, ARCH_CONVERT)); | ||
| 2027 | |||
| 2028 | if (unlikely( | ||
| 2029 | ((char *)namest < (char *)leaf) || | ||
| 2030 | ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)))) { | ||
| 2031 | XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(2)", | ||
| 2032 | XFS_ERRLEVEL_LOW, mp, leaf); | ||
| 2033 | xfs_dir_trace_g_du("leaf: corrupted", dp, uio); | ||
| 2034 | return XFS_ERROR(EFSCORRUPTED); | ||
| 2035 | } | ||
| 2036 | |||
| 2037 | xfs_dir_trace_g_duc("leaf: middle cookie ", | ||
| 2038 | dp, uio, p.cook.o); | ||
| 2039 | |||
| 2040 | if (i < (INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1)) { | ||
| 2041 | nexthash = INT_GET(entry[1].hashval, ARCH_CONVERT); | ||
| 2042 | |||
| 2043 | if (nexthash == INT_GET(entry->hashval, ARCH_CONVERT)) | ||
| 2044 | nextentno = entno + 1; | ||
| 2045 | else | ||
| 2046 | nextentno = 0; | ||
| 2047 | XFS_PUT_COOKIE(p.cook, mp, bno, nextentno, nexthash); | ||
| 2048 | xfs_dir_trace_g_duc("leaf: middle cookie ", | ||
| 2049 | dp, uio, p.cook.o); | ||
| 2050 | |||
| 2051 | } else if ((thishash = be32_to_cpu(leaf->hdr.info.forw))) { | ||
| 2052 | xfs_dabuf_t *bp2; | ||
| 2053 | xfs_dir_leafblock_t *leaf2; | ||
| 2054 | |||
| 2055 | ASSERT(nextda != -1); | ||
| 2056 | |||
| 2057 | retval = xfs_da_read_buf(dp->i_transp, dp, thishash, | ||
| 2058 | nextda, &bp2, XFS_DATA_FORK); | ||
| 2059 | if (retval) | ||
| 2060 | return retval; | ||
| 2061 | |||
| 2062 | ASSERT(bp2 != NULL); | ||
| 2063 | |||
| 2064 | leaf2 = bp2->data; | ||
| 2065 | |||
| 2066 | if (unlikely( | ||
| 2067 | (be16_to_cpu(leaf2->hdr.info.magic) | ||
| 2068 | != XFS_DIR_LEAF_MAGIC) | ||
| 2069 | || (be32_to_cpu(leaf2->hdr.info.back) | ||
| 2070 | != bno))) { /* GROT */ | ||
| 2071 | XFS_CORRUPTION_ERROR("xfs_dir_leaf_getdents_int(3)", | ||
| 2072 | XFS_ERRLEVEL_LOW, mp, | ||
| 2073 | leaf2); | ||
| 2074 | xfs_da_brelse(dp->i_transp, bp2); | ||
| 2075 | |||
| 2076 | return XFS_ERROR(EFSCORRUPTED); | ||
| 2077 | } | ||
| 2078 | |||
| 2079 | nexthash = INT_GET(leaf2->entries[0].hashval, | ||
| 2080 | ARCH_CONVERT); | ||
| 2081 | nextentno = -1; | ||
| 2082 | XFS_PUT_COOKIE(p.cook, mp, thishash, 0, nexthash); | ||
| 2083 | xfs_da_brelse(dp->i_transp, bp2); | ||
| 2084 | xfs_dir_trace_g_duc("leaf: next blk cookie", | ||
| 2085 | dp, uio, p.cook.o); | ||
| 2086 | } else { | ||
| 2087 | nextentno = -1; | ||
| 2088 | XFS_PUT_COOKIE(p.cook, mp, 0, 0, XFS_DA_MAXHASH); | ||
| 2089 | } | ||
| 2090 | |||
| 2091 | /* | ||
| 2092 | * Save off the cookie so we can fall back should the | ||
| 2093 | * 'put' into the outgoing buffer fails. To handle a run | ||
| 2094 | * of equal-hashvals, the off_t structure on 64bit | ||
| 2095 | * builds has entno built into the cookie to ID the | ||
| 2096 | * entry. On 32bit builds, we only have space for the | ||
| 2097 | * hashval so we can't ID specific entries within a group | ||
| 2098 | * of same hashval entries. For this, lastoffset is set | ||
| 2099 | * to the first in the run of equal hashvals so we don't | ||
| 2100 | * include any entries unless we can include all entries | ||
| 2101 | * that share the same hashval. Hopefully the buffer | ||
| 2102 | * provided is big enough to handle it (see pv763517). | ||
| 2103 | */ | ||
| 2104 | #if (BITS_PER_LONG == 32) | ||
| 2105 | if ((thishash = INT_GET(entry->hashval, ARCH_CONVERT)) | ||
| 2106 | != lasthash) { | ||
| 2107 | XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash); | ||
| 2108 | lastresid = uio->uio_resid; | ||
| 2109 | lasthash = thishash; | ||
| 2110 | } else { | ||
| 2111 | xfs_dir_trace_g_duc("leaf: DUP COOKIES, skipped", | ||
| 2112 | dp, uio, p.cook.o); | ||
| 2113 | } | ||
| 2114 | #else | ||
| 2115 | thishash = INT_GET(entry->hashval, ARCH_CONVERT); | ||
| 2116 | XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash); | ||
| 2117 | lastresid = uio->uio_resid; | ||
| 2118 | #endif /* BITS_PER_LONG == 32 */ | ||
| 2119 | |||
| 2120 | /* | ||
| 2121 | * Put the current entry into the outgoing buffer. If we fail | ||
| 2122 | * then restore the UIO to the first entry in the current | ||
| 2123 | * run of equal-hashval entries (probably one 1 entry long). | ||
| 2124 | */ | ||
| 2125 | p.ino = XFS_GET_DIR_INO8(namest->inumber); | ||
| 2126 | #if XFS_BIG_INUMS | ||
| 2127 | p.ino += mp->m_inoadd; | ||
| 2128 | #endif | ||
| 2129 | p.name = (char *)namest->name; | ||
| 2130 | p.namelen = entry->namelen; | ||
| 2131 | |||
| 2132 | retval = p.put(&p); | ||
| 2133 | |||
| 2134 | if (!p.done) { | ||
| 2135 | uio->uio_offset = lastoffset.o; | ||
| 2136 | uio->uio_resid = lastresid; | ||
| 2137 | |||
| 2138 | *eobp = 1; | ||
| 2139 | |||
| 2140 | xfs_dir_trace_g_du("leaf: E-O-B", dp, uio); | ||
| 2141 | |||
| 2142 | return retval; | ||
| 2143 | } | ||
| 2144 | } | ||
| 2145 | |||
| 2146 | uio->uio_offset = p.cook.o; | ||
| 2147 | |||
| 2148 | *eobp = 0; | ||
| 2149 | |||
| 2150 | xfs_dir_trace_g_du("leaf: E-O-F", dp, uio); | ||
| 2151 | |||
| 2152 | return 0; | ||
| 2153 | } | ||
| 2154 | |||
| 2155 | /* | ||
| 2156 | * Format a dirent64 structure and copy it out the the user's buffer. | ||
| 2157 | */ | ||
| 2158 | int | ||
| 2159 | xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa) | ||
| 2160 | { | ||
| 2161 | iovec_t *iovp; | ||
| 2162 | int reclen, namelen; | ||
| 2163 | xfs_dirent_t *idbp; | ||
| 2164 | uio_t *uio; | ||
| 2165 | |||
| 2166 | namelen = pa->namelen; | ||
| 2167 | reclen = DIRENTSIZE(namelen); | ||
| 2168 | uio = pa->uio; | ||
| 2169 | if (reclen > uio->uio_resid) { | ||
| 2170 | pa->done = 0; | ||
| 2171 | return 0; | ||
| 2172 | } | ||
| 2173 | iovp = uio->uio_iov; | ||
| 2174 | idbp = (xfs_dirent_t *)iovp->iov_base; | ||
| 2175 | iovp->iov_base = (char *)idbp + reclen; | ||
| 2176 | iovp->iov_len -= reclen; | ||
| 2177 | uio->uio_resid -= reclen; | ||
| 2178 | idbp->d_reclen = reclen; | ||
| 2179 | idbp->d_ino = pa->ino; | ||
| 2180 | idbp->d_off = pa->cook.o; | ||
| 2181 | idbp->d_name[namelen] = '\0'; | ||
| 2182 | pa->done = 1; | ||
| 2183 | memcpy(idbp->d_name, pa->name, namelen); | ||
| 2184 | return 0; | ||
| 2185 | } | ||
| 2186 | |||
| 2187 | /* | ||
| 2188 | * Format a dirent64 structure and copy it out the the user's buffer. | ||
| 2189 | */ | ||
| 2190 | int | ||
| 2191 | xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa) | ||
| 2192 | { | ||
| 2193 | int retval, reclen, namelen; | ||
| 2194 | xfs_dirent_t *idbp; | ||
| 2195 | uio_t *uio; | ||
| 2196 | |||
| 2197 | namelen = pa->namelen; | ||
| 2198 | reclen = DIRENTSIZE(namelen); | ||
| 2199 | uio = pa->uio; | ||
| 2200 | if (reclen > uio->uio_resid) { | ||
| 2201 | pa->done = 0; | ||
| 2202 | return 0; | ||
| 2203 | } | ||
| 2204 | idbp = pa->dbp; | ||
| 2205 | idbp->d_reclen = reclen; | ||
| 2206 | idbp->d_ino = pa->ino; | ||
| 2207 | idbp->d_off = pa->cook.o; | ||
| 2208 | idbp->d_name[namelen] = '\0'; | ||
| 2209 | memcpy(idbp->d_name, pa->name, namelen); | ||
| 2210 | retval = uio_read((caddr_t)idbp, reclen, uio); | ||
| 2211 | pa->done = (retval == 0); | ||
| 2212 | return retval; | ||
| 2213 | } | ||
diff --git a/fs/xfs/xfs_dir_leaf.h b/fs/xfs/xfs_dir_leaf.h deleted file mode 100644 index eb8cd9a4667f..000000000000 --- a/fs/xfs/xfs_dir_leaf.h +++ /dev/null | |||
| @@ -1,231 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it would be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write the Free Software Foundation, | ||
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | #ifndef __XFS_DIR_LEAF_H__ | ||
| 19 | #define __XFS_DIR_LEAF_H__ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Directory layout, internal structure, access macros, etc. | ||
| 23 | * | ||
| 24 | * Large directories are structured around Btrees where all the data | ||
| 25 | * elements are in the leaf nodes. Filenames are hashed into an int, | ||
| 26 | * then that int is used as the index into the Btree. Since the hashval | ||
| 27 | * of a filename may not be unique, we may have duplicate keys. The | ||
| 28 | * internal links in the Btree are logical block offsets into the file. | ||
| 29 | */ | ||
| 30 | |||
| 31 | struct uio; | ||
| 32 | struct xfs_bmap_free; | ||
| 33 | struct xfs_dabuf; | ||
| 34 | struct xfs_da_args; | ||
| 35 | struct xfs_da_state; | ||
| 36 | struct xfs_da_state_blk; | ||
| 37 | struct xfs_dir_put_args; | ||
| 38 | struct xfs_inode; | ||
| 39 | struct xfs_mount; | ||
| 40 | struct xfs_trans; | ||
| 41 | |||
| 42 | /*======================================================================== | ||
| 43 | * Directory Structure when equal to XFS_LBSIZE(mp) bytes. | ||
| 44 | *========================================================================*/ | ||
| 45 | |||
| 46 | /* | ||
| 47 | * This is the structure of the leaf nodes in the Btree. | ||
| 48 | * | ||
| 49 | * Struct leaf_entry's are packed from the top. Names grow from the bottom | ||
| 50 | * but are not packed. The freemap contains run-length-encoded entries | ||
| 51 | * for the free bytes after the leaf_entry's, but only the N largest such, | ||
| 52 | * smaller runs are dropped. When the freemap doesn't show enough space | ||
| 53 | * for an allocation, we compact the namelist area and try again. If we | ||
| 54 | * still don't have enough space, then we have to split the block. | ||
| 55 | * | ||
| 56 | * Since we have duplicate hash keys, for each key that matches, compare | ||
| 57 | * the actual string. The root and intermediate node search always takes | ||
| 58 | * the first-in-the-block key match found, so we should only have to work | ||
| 59 | * "forw"ard. If none matches, continue with the "forw"ard leaf nodes | ||
| 60 | * until the hash key changes or the filename is found. | ||
| 61 | * | ||
| 62 | * The parent directory and the self-pointer are explicitly represented | ||
| 63 | * (ie: there are entries for "." and ".."). | ||
| 64 | * | ||
| 65 | * Note that the count being a __uint16_t limits us to something like a | ||
| 66 | * blocksize of 1.3MB in the face of worst case (short) filenames. | ||
| 67 | */ | ||
| 68 | #define XFS_DIR_LEAF_MAPSIZE 3 /* how many freespace slots */ | ||
| 69 | |||
| 70 | typedef struct xfs_dir_leaf_map { /* RLE map of free bytes */ | ||
| 71 | __uint16_t base; /* base of free region */ | ||
| 72 | __uint16_t size; /* run length of free region */ | ||
| 73 | } xfs_dir_leaf_map_t; | ||
| 74 | |||
| 75 | typedef struct xfs_dir_leaf_hdr { /* constant-structure header block */ | ||
| 76 | xfs_da_blkinfo_t info; /* block type, links, etc. */ | ||
| 77 | __uint16_t count; /* count of active leaf_entry's */ | ||
| 78 | __uint16_t namebytes; /* num bytes of name strings stored */ | ||
| 79 | __uint16_t firstused; /* first used byte in name area */ | ||
| 80 | __uint8_t holes; /* != 0 if blk needs compaction */ | ||
| 81 | __uint8_t pad1; | ||
| 82 | xfs_dir_leaf_map_t freemap[XFS_DIR_LEAF_MAPSIZE]; | ||
| 83 | } xfs_dir_leaf_hdr_t; | ||
| 84 | |||
| 85 | typedef struct xfs_dir_leaf_entry { /* sorted on key, not name */ | ||
| 86 | xfs_dahash_t hashval; /* hash value of name */ | ||
| 87 | __uint16_t nameidx; /* index into buffer of name */ | ||
| 88 | __uint8_t namelen; /* length of name string */ | ||
| 89 | __uint8_t pad2; | ||
| 90 | } xfs_dir_leaf_entry_t; | ||
| 91 | |||
| 92 | typedef struct xfs_dir_leaf_name { | ||
| 93 | xfs_dir_ino_t inumber; /* inode number for this key */ | ||
| 94 | __uint8_t name[1]; /* name string itself */ | ||
| 95 | } xfs_dir_leaf_name_t; | ||
| 96 | |||
| 97 | typedef struct xfs_dir_leafblock { | ||
| 98 | xfs_dir_leaf_hdr_t hdr; /* constant-structure header block */ | ||
| 99 | xfs_dir_leaf_entry_t entries[1]; /* var sized array */ | ||
| 100 | xfs_dir_leaf_name_t namelist[1]; /* grows from bottom of buf */ | ||
| 101 | } xfs_dir_leafblock_t; | ||
| 102 | |||
| 103 | /* | ||
| 104 | * Length of name for which a 512-byte block filesystem | ||
| 105 | * can get a double split. | ||
| 106 | */ | ||
| 107 | #define XFS_DIR_LEAF_CAN_DOUBLE_SPLIT_LEN \ | ||
| 108 | (512 - (uint)sizeof(xfs_dir_leaf_hdr_t) - \ | ||
| 109 | (uint)sizeof(xfs_dir_leaf_entry_t) * 2 - \ | ||
| 110 | (uint)sizeof(xfs_dir_leaf_name_t) * 2 - (MAXNAMELEN - 2) + 1 + 1) | ||
| 111 | |||
| 112 | typedef int (*xfs_dir_put_t)(struct xfs_dir_put_args *pa); | ||
| 113 | |||
| 114 | typedef union { | ||
| 115 | xfs_off_t o; /* offset (cookie) */ | ||
| 116 | /* | ||
| 117 | * Watch the order here (endian-ness dependent). | ||
| 118 | */ | ||
| 119 | struct { | ||
| 120 | #ifndef XFS_NATIVE_HOST | ||
| 121 | xfs_dahash_t h; /* hash value */ | ||
| 122 | __uint32_t be; /* block and entry */ | ||
| 123 | #else | ||
| 124 | __uint32_t be; /* block and entry */ | ||
| 125 | xfs_dahash_t h; /* hash value */ | ||
| 126 | #endif /* XFS_NATIVE_HOST */ | ||
| 127 | } s; | ||
| 128 | } xfs_dircook_t; | ||
| 129 | |||
| 130 | #define XFS_PUT_COOKIE(c,mp,bno,entry,hash) \ | ||
| 131 | ((c).s.be = XFS_DA_MAKE_BNOENTRY(mp, bno, entry), (c).s.h = (hash)) | ||
| 132 | |||
| 133 | typedef struct xfs_dir_put_args { | ||
| 134 | xfs_dircook_t cook; /* cookie of (next) entry */ | ||
| 135 | xfs_intino_t ino; /* inode number */ | ||
| 136 | struct xfs_dirent *dbp; /* buffer pointer */ | ||
| 137 | char *name; /* directory entry name */ | ||
| 138 | int namelen; /* length of name */ | ||
| 139 | int done; /* output: set if value was stored */ | ||
| 140 | xfs_dir_put_t put; /* put function ptr (i/o) */ | ||
| 141 | struct uio *uio; /* uio control structure */ | ||
| 142 | } xfs_dir_put_args_t; | ||
| 143 | |||
| 144 | #define XFS_DIR_LEAF_ENTSIZE_BYNAME(len) \ | ||
| 145 | xfs_dir_leaf_entsize_byname(len) | ||
| 146 | static inline int xfs_dir_leaf_entsize_byname(int len) | ||
| 147 | { | ||
| 148 | return (uint)sizeof(xfs_dir_leaf_name_t)-1 + len; | ||
| 149 | } | ||
| 150 | |||
| 151 | #define XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry) \ | ||
| 152 | xfs_dir_leaf_entsize_byentry(entry) | ||
| 153 | static inline int xfs_dir_leaf_entsize_byentry(xfs_dir_leaf_entry_t *entry) | ||
| 154 | { | ||
| 155 | return (uint)sizeof(xfs_dir_leaf_name_t)-1 + (entry)->namelen; | ||
| 156 | } | ||
| 157 | |||
| 158 | #define XFS_DIR_LEAF_NAMESTRUCT(leafp,offset) \ | ||
| 159 | xfs_dir_leaf_namestruct(leafp,offset) | ||
| 160 | static inline xfs_dir_leaf_name_t * | ||
| 161 | xfs_dir_leaf_namestruct(xfs_dir_leafblock_t *leafp, int offset) | ||
| 162 | { | ||
| 163 | return (xfs_dir_leaf_name_t *)&((char *)(leafp))[offset]; | ||
| 164 | } | ||
| 165 | |||
| 166 | /*======================================================================== | ||
| 167 | * Function prototypes for the kernel. | ||
| 168 | *========================================================================*/ | ||
| 169 | |||
| 170 | /* | ||
| 171 | * Internal routines when dirsize < XFS_LITINO(mp). | ||
| 172 | */ | ||
| 173 | int xfs_dir_shortform_create(struct xfs_da_args *args, xfs_ino_t parent); | ||
| 174 | int xfs_dir_shortform_addname(struct xfs_da_args *args); | ||
| 175 | int xfs_dir_shortform_lookup(struct xfs_da_args *args); | ||
| 176 | int xfs_dir_shortform_to_leaf(struct xfs_da_args *args); | ||
| 177 | int xfs_dir_shortform_removename(struct xfs_da_args *args); | ||
| 178 | int xfs_dir_shortform_getdents(struct xfs_inode *dp, struct uio *uio, int *eofp, | ||
| 179 | struct xfs_dirent *dbp, xfs_dir_put_t put); | ||
| 180 | int xfs_dir_shortform_replace(struct xfs_da_args *args); | ||
| 181 | |||
| 182 | /* | ||
| 183 | * Internal routines when dirsize == XFS_LBSIZE(mp). | ||
| 184 | */ | ||
| 185 | int xfs_dir_leaf_to_node(struct xfs_da_args *args); | ||
| 186 | int xfs_dir_leaf_to_shortform(struct xfs_da_args *args); | ||
| 187 | |||
| 188 | /* | ||
| 189 | * Routines used for growing the Btree. | ||
| 190 | */ | ||
| 191 | int xfs_dir_leaf_split(struct xfs_da_state *state, | ||
| 192 | struct xfs_da_state_blk *oldblk, | ||
| 193 | struct xfs_da_state_blk *newblk); | ||
| 194 | int xfs_dir_leaf_add(struct xfs_dabuf *leaf_buffer, | ||
| 195 | struct xfs_da_args *args, int insertion_index); | ||
| 196 | int xfs_dir_leaf_addname(struct xfs_da_args *args); | ||
| 197 | int xfs_dir_leaf_lookup_int(struct xfs_dabuf *leaf_buffer, | ||
| 198 | struct xfs_da_args *args, | ||
| 199 | int *index_found_at); | ||
| 200 | int xfs_dir_leaf_remove(struct xfs_trans *trans, | ||
| 201 | struct xfs_dabuf *leaf_buffer, | ||
| 202 | int index_to_remove); | ||
| 203 | int xfs_dir_leaf_getdents_int(struct xfs_dabuf *bp, struct xfs_inode *dp, | ||
| 204 | xfs_dablk_t bno, struct uio *uio, | ||
| 205 | int *eobp, struct xfs_dirent *dbp, | ||
| 206 | xfs_dir_put_t put, xfs_daddr_t nextda); | ||
| 207 | |||
| 208 | /* | ||
| 209 | * Routines used for shrinking the Btree. | ||
| 210 | */ | ||
| 211 | int xfs_dir_leaf_toosmall(struct xfs_da_state *state, int *retval); | ||
| 212 | void xfs_dir_leaf_unbalance(struct xfs_da_state *state, | ||
| 213 | struct xfs_da_state_blk *drop_blk, | ||
| 214 | struct xfs_da_state_blk *save_blk); | ||
| 215 | |||
| 216 | /* | ||
| 217 | * Utility routines. | ||
| 218 | */ | ||
| 219 | uint xfs_dir_leaf_lasthash(struct xfs_dabuf *bp, int *count); | ||
| 220 | int xfs_dir_leaf_order(struct xfs_dabuf *leaf1_bp, | ||
| 221 | struct xfs_dabuf *leaf2_bp); | ||
| 222 | int xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa); | ||
| 223 | int xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa); | ||
| 224 | int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); | ||
| 225 | |||
| 226 | /* | ||
| 227 | * Global data. | ||
| 228 | */ | ||
| 229 | extern xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; | ||
| 230 | |||
| 231 | #endif /* __XFS_DIR_LEAF_H__ */ | ||
diff --git a/fs/xfs/xfs_dir_sf.h b/fs/xfs/xfs_dir_sf.h deleted file mode 100644 index 5b20b4d3f57d..000000000000 --- a/fs/xfs/xfs_dir_sf.h +++ /dev/null | |||
| @@ -1,155 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000,2005 Silicon Graphics, Inc. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it would be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write the Free Software Foundation, | ||
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | #ifndef __XFS_DIR_SF_H__ | ||
| 19 | #define __XFS_DIR_SF_H__ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Directory layout when stored internal to an inode. | ||
| 23 | * | ||
| 24 | * Small directories are packed as tightly as possible so as to | ||
| 25 | * fit into the literal area of the inode. | ||
| 26 | */ | ||
| 27 | |||
| 28 | typedef struct { __uint8_t i[sizeof(xfs_ino_t)]; } xfs_dir_ino_t; | ||
| 29 | |||
| 30 | /* | ||
| 31 | * The parent directory has a dedicated field, and the self-pointer must | ||
| 32 | * be calculated on the fly. | ||
| 33 | * | ||
| 34 | * Entries are packed toward the top as tight as possible. The header | ||
| 35 | * and the elements much be memcpy'd out into a work area to get correct | ||
| 36 | * alignment for the inode number fields. | ||
| 37 | */ | ||
| 38 | typedef struct xfs_dir_sf_hdr { /* constant-structure header block */ | ||
| 39 | xfs_dir_ino_t parent; /* parent dir inode number */ | ||
| 40 | __uint8_t count; /* count of active entries */ | ||
| 41 | } xfs_dir_sf_hdr_t; | ||
| 42 | |||
| 43 | typedef struct xfs_dir_sf_entry { | ||
| 44 | xfs_dir_ino_t inumber; /* referenced inode number */ | ||
| 45 | __uint8_t namelen; /* actual length of name (no NULL) */ | ||
| 46 | __uint8_t name[1]; /* name */ | ||
| 47 | } xfs_dir_sf_entry_t; | ||
| 48 | |||
| 49 | typedef struct xfs_dir_shortform { | ||
| 50 | xfs_dir_sf_hdr_t hdr; | ||
| 51 | xfs_dir_sf_entry_t list[1]; /* variable sized array */ | ||
| 52 | } xfs_dir_shortform_t; | ||
| 53 | |||
| 54 | /* | ||
| 55 | * We generate this then sort it, so that readdirs are returned in | ||
| 56 | * hash-order. Else seekdir won't work. | ||
| 57 | */ | ||
| 58 | typedef struct xfs_dir_sf_sort { | ||
| 59 | __uint8_t entno; /* .=0, ..=1, else entry# + 2 */ | ||
| 60 | __uint8_t seqno; /* sequence # with same hash value */ | ||
| 61 | __uint8_t namelen; /* length of name value (no null) */ | ||
| 62 | xfs_dahash_t hash; /* this entry's hash value */ | ||
| 63 | xfs_intino_t ino; /* this entry's inode number */ | ||
| 64 | char *name; /* name value, pointer into buffer */ | ||
| 65 | } xfs_dir_sf_sort_t; | ||
| 66 | |||
| 67 | #define XFS_DIR_SF_GET_DIRINO(from,to) xfs_dir_sf_get_dirino(from, to) | ||
| 68 | static inline void xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to) | ||
| 69 | { | ||
| 70 | *(to) = XFS_GET_DIR_INO8(*from); | ||
| 71 | } | ||
| 72 | |||
| 73 | #define XFS_DIR_SF_PUT_DIRINO(from,to) xfs_dir_sf_put_dirino(from, to) | ||
| 74 | static inline void xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to) | ||
| 75 | { | ||
| 76 | XFS_PUT_DIR_INO8(*(from), *(to)); | ||
| 77 | } | ||
| 78 | |||
| 79 | #define XFS_DIR_SF_ENTSIZE_BYNAME(len) xfs_dir_sf_entsize_byname(len) | ||
| 80 | static inline int xfs_dir_sf_entsize_byname(int len) | ||
| 81 | { | ||
| 82 | return (uint)sizeof(xfs_dir_sf_entry_t)-1 + (len); | ||
| 83 | } | ||
| 84 | |||
| 85 | #define XFS_DIR_SF_ENTSIZE_BYENTRY(sfep) xfs_dir_sf_entsize_byentry(sfep) | ||
| 86 | static inline int xfs_dir_sf_entsize_byentry(xfs_dir_sf_entry_t *sfep) | ||
| 87 | { | ||
| 88 | return (uint)sizeof(xfs_dir_sf_entry_t)-1 + (sfep)->namelen; | ||
| 89 | } | ||
| 90 | |||
| 91 | #define XFS_DIR_SF_NEXTENTRY(sfep) xfs_dir_sf_nextentry(sfep) | ||
| 92 | static inline xfs_dir_sf_entry_t *xfs_dir_sf_nextentry(xfs_dir_sf_entry_t *sfep) | ||
| 93 | { | ||
| 94 | return (xfs_dir_sf_entry_t *) \ | ||
| 95 | ((char *)(sfep) + XFS_DIR_SF_ENTSIZE_BYENTRY(sfep)); | ||
| 96 | } | ||
| 97 | |||
| 98 | #define XFS_DIR_SF_ALLFIT(count,totallen) \ | ||
| 99 | xfs_dir_sf_allfit(count,totallen) | ||
| 100 | static inline int xfs_dir_sf_allfit(int count, int totallen) | ||
| 101 | { | ||
| 102 | return ((uint)sizeof(xfs_dir_sf_hdr_t) + \ | ||
| 103 | ((uint)sizeof(xfs_dir_sf_entry_t)-1)*(count) + (totallen)); | ||
| 104 | } | ||
| 105 | |||
| 106 | #if defined(XFS_DIR_TRACE) | ||
| 107 | |||
| 108 | /* | ||
| 109 | * Kernel tracing support for directories. | ||
| 110 | */ | ||
| 111 | struct uio; | ||
| 112 | struct xfs_inode; | ||
| 113 | struct xfs_da_intnode; | ||
| 114 | struct xfs_dinode; | ||
| 115 | struct xfs_dir_leafblock; | ||
| 116 | struct xfs_dir_leaf_entry; | ||
| 117 | |||
| 118 | #define XFS_DIR_TRACE_SIZE 4096 /* size of global trace buffer */ | ||
| 119 | extern ktrace_t *xfs_dir_trace_buf; | ||
| 120 | |||
| 121 | /* | ||
| 122 | * Trace record types. | ||
| 123 | */ | ||
| 124 | #define XFS_DIR_KTRACE_G_DU 1 /* dp, uio */ | ||
| 125 | #define XFS_DIR_KTRACE_G_DUB 2 /* dp, uio, bno */ | ||
| 126 | #define XFS_DIR_KTRACE_G_DUN 3 /* dp, uio, node */ | ||
| 127 | #define XFS_DIR_KTRACE_G_DUL 4 /* dp, uio, leaf */ | ||
| 128 | #define XFS_DIR_KTRACE_G_DUE 5 /* dp, uio, leaf entry */ | ||
| 129 | #define XFS_DIR_KTRACE_G_DUC 6 /* dp, uio, cookie */ | ||
| 130 | |||
| 131 | void xfs_dir_trace_g_du(char *where, struct xfs_inode *dp, struct uio *uio); | ||
| 132 | void xfs_dir_trace_g_dub(char *where, struct xfs_inode *dp, struct uio *uio, | ||
| 133 | xfs_dablk_t bno); | ||
| 134 | void xfs_dir_trace_g_dun(char *where, struct xfs_inode *dp, struct uio *uio, | ||
| 135 | struct xfs_da_intnode *node); | ||
| 136 | void xfs_dir_trace_g_dul(char *where, struct xfs_inode *dp, struct uio *uio, | ||
| 137 | struct xfs_dir_leafblock *leaf); | ||
| 138 | void xfs_dir_trace_g_due(char *where, struct xfs_inode *dp, struct uio *uio, | ||
| 139 | struct xfs_dir_leaf_entry *entry); | ||
| 140 | void xfs_dir_trace_g_duc(char *where, struct xfs_inode *dp, struct uio *uio, | ||
| 141 | xfs_off_t cookie); | ||
| 142 | void xfs_dir_trace_enter(int type, char *where, | ||
| 143 | void *a0, void *a1, void *a2, void *a3, | ||
| 144 | void *a4, void *a5, void *a6, void *a7, | ||
| 145 | void *a8, void *a9, void *a10, void *a11); | ||
| 146 | #else | ||
| 147 | #define xfs_dir_trace_g_du(w,d,u) | ||
| 148 | #define xfs_dir_trace_g_dub(w,d,u,b) | ||
| 149 | #define xfs_dir_trace_g_dun(w,d,u,n) | ||
| 150 | #define xfs_dir_trace_g_dul(w,d,u,l) | ||
| 151 | #define xfs_dir_trace_g_due(w,d,u,e) | ||
| 152 | #define xfs_dir_trace_g_duc(w,d,u,c) | ||
| 153 | #endif /* DEBUG */ | ||
| 154 | |||
| 155 | #endif /* __XFS_DIR_SF_H__ */ | ||
diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h index 00b1540f8108..4e7865ad6f0e 100644 --- a/fs/xfs/xfs_dmapi.h +++ b/fs/xfs/xfs_dmapi.h | |||
| @@ -189,6 +189,6 @@ typedef enum { | |||
| 189 | #define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0) | 189 | #define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0) |
| 190 | 190 | ||
| 191 | 191 | ||
| 192 | extern struct bhv_vfsops xfs_dmops; | 192 | extern struct bhv_module_vfsops xfs_dmops; |
| 193 | 193 | ||
| 194 | #endif /* __XFS_DMAPI_H__ */ | 194 | #endif /* __XFS_DMAPI_H__ */ |
diff --git a/fs/xfs/xfs_dmops.c b/fs/xfs/xfs_dmops.c index 629795b3b3d5..1e4a35ddf7f9 100644 --- a/fs/xfs/xfs_dmops.c +++ b/fs/xfs/xfs_dmops.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_dmapi.h" | 27 | #include "xfs_dmapi.h" |
| 29 | #include "xfs_mount.h" | 28 | #include "xfs_mount.h" |
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c index 2a21c5024017..b95681b03d81 100644 --- a/fs/xfs/xfs_error.c +++ b/fs/xfs/xfs_error.c | |||
| @@ -22,12 +22,10 @@ | |||
| 22 | #include "xfs_inum.h" | 22 | #include "xfs_inum.h" |
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_dir.h" | ||
| 26 | #include "xfs_dir2.h" | 25 | #include "xfs_dir2.h" |
| 27 | #include "xfs_dmapi.h" | 26 | #include "xfs_dmapi.h" |
| 28 | #include "xfs_mount.h" | 27 | #include "xfs_mount.h" |
| 29 | #include "xfs_bmap_btree.h" | 28 | #include "xfs_bmap_btree.h" |
| 30 | #include "xfs_dir_sf.h" | ||
| 31 | #include "xfs_dir2_sf.h" | 29 | #include "xfs_dir2_sf.h" |
| 32 | #include "xfs_attr_sf.h" | 30 | #include "xfs_attr_sf.h" |
| 33 | #include "xfs_dinode.h" | 31 | #include "xfs_dinode.h" |
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index f19282ec8549..6cf6d8769b97 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_buf_item.h" | 24 | #include "xfs_buf_item.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dmapi.h" | 26 | #include "xfs_dmapi.h" |
| 28 | #include "xfs_mount.h" | 27 | #include "xfs_mount.h" |
| 29 | #include "xfs_trans_priv.h" | 28 | #include "xfs_trans_priv.h" |
| @@ -294,6 +293,62 @@ xfs_efi_init(xfs_mount_t *mp, | |||
| 294 | } | 293 | } |
| 295 | 294 | ||
| 296 | /* | 295 | /* |
| 296 | * Copy an EFI format buffer from the given buf, and into the destination | ||
| 297 | * EFI format structure. | ||
| 298 | * The given buffer can be in 32 bit or 64 bit form (which has different padding), | ||
| 299 | * one of which will be the native format for this kernel. | ||
| 300 | * It will handle the conversion of formats if necessary. | ||
| 301 | */ | ||
| 302 | int | ||
| 303 | xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt) | ||
| 304 | { | ||
| 305 | xfs_efi_log_format_t *src_efi_fmt = (xfs_efi_log_format_t *)buf->i_addr; | ||
| 306 | uint i; | ||
| 307 | uint len = sizeof(xfs_efi_log_format_t) + | ||
| 308 | (src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_t); | ||
| 309 | uint len32 = sizeof(xfs_efi_log_format_32_t) + | ||
| 310 | (src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_32_t); | ||
| 311 | uint len64 = sizeof(xfs_efi_log_format_64_t) + | ||
| 312 | (src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_64_t); | ||
| 313 | |||
| 314 | if (buf->i_len == len) { | ||
| 315 | memcpy((char *)dst_efi_fmt, (char*)src_efi_fmt, len); | ||
| 316 | return 0; | ||
| 317 | } else if (buf->i_len == len32) { | ||
| 318 | xfs_efi_log_format_32_t *src_efi_fmt_32 = | ||
| 319 | (xfs_efi_log_format_32_t *)buf->i_addr; | ||
| 320 | |||
| 321 | dst_efi_fmt->efi_type = src_efi_fmt_32->efi_type; | ||
| 322 | dst_efi_fmt->efi_size = src_efi_fmt_32->efi_size; | ||
| 323 | dst_efi_fmt->efi_nextents = src_efi_fmt_32->efi_nextents; | ||
| 324 | dst_efi_fmt->efi_id = src_efi_fmt_32->efi_id; | ||
| 325 | for (i = 0; i < dst_efi_fmt->efi_nextents; i++) { | ||
| 326 | dst_efi_fmt->efi_extents[i].ext_start = | ||
| 327 | src_efi_fmt_32->efi_extents[i].ext_start; | ||
| 328 | dst_efi_fmt->efi_extents[i].ext_len = | ||
| 329 | src_efi_fmt_32->efi_extents[i].ext_len; | ||
| 330 | } | ||
| 331 | return 0; | ||
| 332 | } else if (buf->i_len == len64) { | ||
| 333 | xfs_efi_log_format_64_t *src_efi_fmt_64 = | ||
| 334 | (xfs_efi_log_format_64_t *)buf->i_addr; | ||
| 335 | |||
| 336 | dst_efi_fmt->efi_type = src_efi_fmt_64->efi_type; | ||
| 337 | dst_efi_fmt->efi_size = src_efi_fmt_64->efi_size; | ||
| 338 | dst_efi_fmt->efi_nextents = src_efi_fmt_64->efi_nextents; | ||
| 339 | dst_efi_fmt->efi_id = src_efi_fmt_64->efi_id; | ||
| 340 | for (i = 0; i < dst_efi_fmt->efi_nextents; i++) { | ||
| 341 | dst_efi_fmt->efi_extents[i].ext_start = | ||
| 342 | src_efi_fmt_64->efi_extents[i].ext_start; | ||
| 343 | dst_efi_fmt->efi_extents[i].ext_len = | ||
| 344 | src_efi_fmt_64->efi_extents[i].ext_len; | ||
| 345 | } | ||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | return EFSCORRUPTED; | ||
| 349 | } | ||
| 350 | |||
| 351 | /* | ||
| 297 | * This is called by the efd item code below to release references to | 352 | * This is called by the efd item code below to release references to |
| 298 | * the given efi item. Each efd calls this with the number of | 353 | * the given efi item. Each efd calls this with the number of |
| 299 | * extents that it has logged, and when the sum of these reaches | 354 | * extents that it has logged, and when the sum of these reaches |
diff --git a/fs/xfs/xfs_extfree_item.h b/fs/xfs/xfs_extfree_item.h index 5bf681708fec..0ea45edaab03 100644 --- a/fs/xfs/xfs_extfree_item.h +++ b/fs/xfs/xfs_extfree_item.h | |||
| @@ -27,6 +27,24 @@ typedef struct xfs_extent { | |||
| 27 | } xfs_extent_t; | 27 | } xfs_extent_t; |
| 28 | 28 | ||
| 29 | /* | 29 | /* |
| 30 | * Since an xfs_extent_t has types (start:64, len: 32) | ||
| 31 | * there are different alignments on 32 bit and 64 bit kernels. | ||
| 32 | * So we provide the different variants for use by a | ||
| 33 | * conversion routine. | ||
| 34 | */ | ||
| 35 | |||
| 36 | typedef struct xfs_extent_32 { | ||
| 37 | xfs_dfsbno_t ext_start; | ||
| 38 | xfs_extlen_t ext_len; | ||
| 39 | } __attribute__((packed)) xfs_extent_32_t; | ||
| 40 | |||
| 41 | typedef struct xfs_extent_64 { | ||
| 42 | xfs_dfsbno_t ext_start; | ||
| 43 | xfs_extlen_t ext_len; | ||
| 44 | __uint32_t ext_pad; | ||
| 45 | } xfs_extent_64_t; | ||
| 46 | |||
| 47 | /* | ||
| 30 | * This is the structure used to lay out an efi log item in the | 48 | * This is the structure used to lay out an efi log item in the |
| 31 | * log. The efi_extents field is a variable size array whose | 49 | * log. The efi_extents field is a variable size array whose |
| 32 | * size is given by efi_nextents. | 50 | * size is given by efi_nextents. |
| @@ -39,6 +57,22 @@ typedef struct xfs_efi_log_format { | |||
| 39 | xfs_extent_t efi_extents[1]; /* array of extents to free */ | 57 | xfs_extent_t efi_extents[1]; /* array of extents to free */ |
| 40 | } xfs_efi_log_format_t; | 58 | } xfs_efi_log_format_t; |
| 41 | 59 | ||
| 60 | typedef struct xfs_efi_log_format_32 { | ||
| 61 | unsigned short efi_type; /* efi log item type */ | ||
| 62 | unsigned short efi_size; /* size of this item */ | ||
| 63 | uint efi_nextents; /* # extents to free */ | ||
| 64 | __uint64_t efi_id; /* efi identifier */ | ||
| 65 | xfs_extent_32_t efi_extents[1]; /* array of extents to free */ | ||
| 66 | } __attribute__((packed)) xfs_efi_log_format_32_t; | ||
| 67 | |||
| 68 | typedef struct xfs_efi_log_format_64 { | ||
| 69 | unsigned short efi_type; /* efi log item type */ | ||
| 70 | unsigned short efi_size; /* size of this item */ | ||
| 71 | uint efi_nextents; /* # extents to free */ | ||
| 72 | __uint64_t efi_id; /* efi identifier */ | ||
| 73 | xfs_extent_64_t efi_extents[1]; /* array of extents to free */ | ||
| 74 | } xfs_efi_log_format_64_t; | ||
| 75 | |||
| 42 | /* | 76 | /* |
| 43 | * This is the structure used to lay out an efd log item in the | 77 | * This is the structure used to lay out an efd log item in the |
| 44 | * log. The efd_extents array is a variable size array whose | 78 | * log. The efd_extents array is a variable size array whose |
| @@ -52,6 +86,22 @@ typedef struct xfs_efd_log_format { | |||
| 52 | xfs_extent_t efd_extents[1]; /* array of extents freed */ | 86 | xfs_extent_t efd_extents[1]; /* array of extents freed */ |
| 53 | } xfs_efd_log_format_t; | 87 | } xfs_efd_log_format_t; |
| 54 | 88 | ||
| 89 | typedef struct xfs_efd_log_format_32 { | ||
| 90 | unsigned short efd_type; /* efd log item type */ | ||
| 91 | unsigned short efd_size; /* size of this item */ | ||
| 92 | uint efd_nextents; /* # of extents freed */ | ||
| 93 | __uint64_t efd_efi_id; /* id of corresponding efi */ | ||
| 94 | xfs_extent_32_t efd_extents[1]; /* array of extents freed */ | ||
| 95 | } __attribute__((packed)) xfs_efd_log_format_32_t; | ||
| 96 | |||
| 97 | typedef struct xfs_efd_log_format_64 { | ||
| 98 | unsigned short efd_type; /* efd log item type */ | ||
| 99 | unsigned short efd_size; /* size of this item */ | ||
| 100 | uint efd_nextents; /* # of extents freed */ | ||
| 101 | __uint64_t efd_efi_id; /* id of corresponding efi */ | ||
| 102 | xfs_extent_64_t efd_extents[1]; /* array of extents freed */ | ||
| 103 | } xfs_efd_log_format_64_t; | ||
| 104 | |||
| 55 | 105 | ||
| 56 | #ifdef __KERNEL__ | 106 | #ifdef __KERNEL__ |
| 57 | 107 | ||
| @@ -103,7 +153,8 @@ extern struct kmem_zone *xfs_efd_zone; | |||
| 103 | xfs_efi_log_item_t *xfs_efi_init(struct xfs_mount *, uint); | 153 | xfs_efi_log_item_t *xfs_efi_init(struct xfs_mount *, uint); |
| 104 | xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *, | 154 | xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *, |
| 105 | uint); | 155 | uint); |
| 106 | 156 | int xfs_efi_copy_format(xfs_log_iovec_t *buf, | |
| 157 | xfs_efi_log_format_t *dst_efi_fmt); | ||
| 107 | void xfs_efi_item_free(xfs_efi_log_item_t *); | 158 | void xfs_efi_item_free(xfs_efi_log_item_t *); |
| 108 | 159 | ||
| 109 | #endif /* __KERNEL__ */ | 160 | #endif /* __KERNEL__ */ |
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index 14010f1fa82f..0f0ad1535951 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h | |||
| @@ -67,14 +67,15 @@ struct fsxattr { | |||
| 67 | #define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ | 67 | #define XFS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ |
| 68 | #define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ | 68 | #define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ |
| 69 | #define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ | 69 | #define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ |
| 70 | #define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ | ||
| 70 | #define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ | 71 | #define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ |
| 71 | 72 | ||
| 72 | /* | 73 | /* |
| 73 | * Structure for XFS_IOC_GETBMAP. | 74 | * Structure for XFS_IOC_GETBMAP. |
| 74 | * On input, fill in bmv_offset and bmv_length of the first structure | 75 | * On input, fill in bmv_offset and bmv_length of the first structure |
| 75 | * to indicate the area of interest in the file, and bmv_entry with the | 76 | * to indicate the area of interest in the file, and bmv_entries with |
| 76 | * number of array elements given. The first structure is updated on | 77 | * the number of array elements given back. The first structure is |
| 77 | * return to give the offset and length for the next call. | 78 | * updated on return to give the offset and length for the next call. |
| 78 | */ | 79 | */ |
| 79 | #ifndef HAVE_GETBMAP | 80 | #ifndef HAVE_GETBMAP |
| 80 | struct getbmap { | 81 | struct getbmap { |
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index dfa3527b20a7..077629bab532 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -542,14 +540,13 @@ xfs_reserve_blocks( | |||
| 542 | } | 540 | } |
| 543 | 541 | ||
| 544 | void | 542 | void |
| 545 | xfs_fs_log_dummy(xfs_mount_t *mp) | 543 | xfs_fs_log_dummy( |
| 544 | xfs_mount_t *mp) | ||
| 546 | { | 545 | { |
| 547 | xfs_trans_t *tp; | 546 | xfs_trans_t *tp; |
| 548 | xfs_inode_t *ip; | 547 | xfs_inode_t *ip; |
| 549 | |||
| 550 | 548 | ||
| 551 | tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); | 549 | tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); |
| 552 | atomic_inc(&mp->m_active_trans); | ||
| 553 | if (xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0)) { | 550 | if (xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0)) { |
| 554 | xfs_trans_cancel(tp, 0); | 551 | xfs_trans_cancel(tp, 0); |
| 555 | return; | 552 | return; |
| @@ -574,21 +571,22 @@ xfs_fs_goingdown( | |||
| 574 | { | 571 | { |
| 575 | switch (inflags) { | 572 | switch (inflags) { |
| 576 | case XFS_FSOP_GOING_FLAGS_DEFAULT: { | 573 | case XFS_FSOP_GOING_FLAGS_DEFAULT: { |
| 577 | struct vfs *vfsp = XFS_MTOVFS(mp); | 574 | struct bhv_vfs *vfsp = XFS_MTOVFS(mp); |
| 578 | struct super_block *sb = freeze_bdev(vfsp->vfs_super->s_bdev); | 575 | struct super_block *sb = freeze_bdev(vfsp->vfs_super->s_bdev); |
| 579 | 576 | ||
| 580 | if (sb && !IS_ERR(sb)) { | 577 | if (sb && !IS_ERR(sb)) { |
| 581 | xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); | 578 | xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); |
| 582 | thaw_bdev(sb->s_bdev, sb); | 579 | thaw_bdev(sb->s_bdev, sb); |
| 583 | } | 580 | } |
| 584 | 581 | ||
| 585 | break; | 582 | break; |
| 586 | } | 583 | } |
| 587 | case XFS_FSOP_GOING_FLAGS_LOGFLUSH: | 584 | case XFS_FSOP_GOING_FLAGS_LOGFLUSH: |
| 588 | xfs_force_shutdown(mp, XFS_FORCE_UMOUNT); | 585 | xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); |
| 589 | break; | 586 | break; |
| 590 | case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH: | 587 | case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH: |
| 591 | xfs_force_shutdown(mp, XFS_FORCE_UMOUNT|XFS_LOG_IO_ERROR); | 588 | xfs_force_shutdown(mp, |
| 589 | SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR); | ||
| 592 | break; | 590 | break; |
| 593 | default: | 591 | default: |
| 594 | return XFS_ERROR(EINVAL); | 592 | return XFS_ERROR(EINVAL); |
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index deddbd03c166..33164a85aa9d 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -1174,6 +1172,9 @@ xfs_dilocate( | |||
| 1174 | if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || | 1172 | if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || |
| 1175 | ino != XFS_AGINO_TO_INO(mp, agno, agino)) { | 1173 | ino != XFS_AGINO_TO_INO(mp, agno, agino)) { |
| 1176 | #ifdef DEBUG | 1174 | #ifdef DEBUG |
| 1175 | /* no diagnostics for bulkstat, ino comes from userspace */ | ||
| 1176 | if (flags & XFS_IMAP_BULKSTAT) | ||
| 1177 | return XFS_ERROR(EINVAL); | ||
| 1177 | if (agno >= mp->m_sb.sb_agcount) { | 1178 | if (agno >= mp->m_sb.sb_agcount) { |
| 1178 | xfs_fs_cmn_err(CE_ALERT, mp, | 1179 | xfs_fs_cmn_err(CE_ALERT, mp, |
| 1179 | "xfs_dilocate: agno (%d) >= " | 1180 | "xfs_dilocate: agno (%d) >= " |
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c index 60c65683462d..616eeeb6953e 100644 --- a/fs/xfs/xfs_ialloc_btree.c +++ b/fs/xfs/xfs_ialloc_btree.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index b53854325266..0724df7fabb7 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -186,7 +184,7 @@ xfs_ihash_promote( | |||
| 186 | */ | 184 | */ |
| 187 | STATIC int | 185 | STATIC int |
| 188 | xfs_iget_core( | 186 | xfs_iget_core( |
| 189 | vnode_t *vp, | 187 | bhv_vnode_t *vp, |
| 190 | xfs_mount_t *mp, | 188 | xfs_mount_t *mp, |
| 191 | xfs_trans_t *tp, | 189 | xfs_trans_t *tp, |
| 192 | xfs_ino_t ino, | 190 | xfs_ino_t ino, |
| @@ -198,7 +196,7 @@ xfs_iget_core( | |||
| 198 | xfs_ihash_t *ih; | 196 | xfs_ihash_t *ih; |
| 199 | xfs_inode_t *ip; | 197 | xfs_inode_t *ip; |
| 200 | xfs_inode_t *iq; | 198 | xfs_inode_t *iq; |
| 201 | vnode_t *inode_vp; | 199 | bhv_vnode_t *inode_vp; |
| 202 | ulong version; | 200 | ulong version; |
| 203 | int error; | 201 | int error; |
| 204 | /* REFERENCED */ | 202 | /* REFERENCED */ |
| @@ -468,7 +466,7 @@ finish_inode: | |||
| 468 | * If we have a real type for an on-disk inode, we can set ops(&unlock) | 466 | * If we have a real type for an on-disk inode, we can set ops(&unlock) |
| 469 | * now. If it's a new inode being created, xfs_ialloc will handle it. | 467 | * now. If it's a new inode being created, xfs_ialloc will handle it. |
| 470 | */ | 468 | */ |
| 471 | VFS_INIT_VNODE(XFS_MTOVFS(mp), vp, XFS_ITOBHV(ip), 1); | 469 | bhv_vfs_init_vnode(XFS_MTOVFS(mp), vp, XFS_ITOBHV(ip), 1); |
| 472 | 470 | ||
| 473 | return 0; | 471 | return 0; |
| 474 | } | 472 | } |
| @@ -489,7 +487,7 @@ xfs_iget( | |||
| 489 | xfs_daddr_t bno) | 487 | xfs_daddr_t bno) |
| 490 | { | 488 | { |
| 491 | struct inode *inode; | 489 | struct inode *inode; |
| 492 | vnode_t *vp = NULL; | 490 | bhv_vnode_t *vp = NULL; |
| 493 | int error; | 491 | int error; |
| 494 | 492 | ||
| 495 | XFS_STATS_INC(xs_ig_attempts); | 493 | XFS_STATS_INC(xs_ig_attempts); |
| @@ -543,7 +541,7 @@ retry: | |||
| 543 | void | 541 | void |
| 544 | xfs_inode_lock_init( | 542 | xfs_inode_lock_init( |
| 545 | xfs_inode_t *ip, | 543 | xfs_inode_t *ip, |
| 546 | vnode_t *vp) | 544 | bhv_vnode_t *vp) |
| 547 | { | 545 | { |
| 548 | mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER, | 546 | mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER, |
| 549 | "xfsino", (long)vp->v_number); | 547 | "xfsino", (long)vp->v_number); |
| @@ -603,12 +601,10 @@ void | |||
| 603 | xfs_iput(xfs_inode_t *ip, | 601 | xfs_iput(xfs_inode_t *ip, |
| 604 | uint lock_flags) | 602 | uint lock_flags) |
| 605 | { | 603 | { |
| 606 | vnode_t *vp = XFS_ITOV(ip); | 604 | bhv_vnode_t *vp = XFS_ITOV(ip); |
| 607 | 605 | ||
| 608 | vn_trace_entry(vp, "xfs_iput", (inst_t *)__return_address); | 606 | vn_trace_entry(vp, "xfs_iput", (inst_t *)__return_address); |
| 609 | |||
| 610 | xfs_iunlock(ip, lock_flags); | 607 | xfs_iunlock(ip, lock_flags); |
| 611 | |||
| 612 | VN_RELE(vp); | 608 | VN_RELE(vp); |
| 613 | } | 609 | } |
| 614 | 610 | ||
| @@ -619,7 +615,7 @@ void | |||
| 619 | xfs_iput_new(xfs_inode_t *ip, | 615 | xfs_iput_new(xfs_inode_t *ip, |
| 620 | uint lock_flags) | 616 | uint lock_flags) |
| 621 | { | 617 | { |
| 622 | vnode_t *vp = XFS_ITOV(ip); | 618 | bhv_vnode_t *vp = XFS_ITOV(ip); |
| 623 | struct inode *inode = vn_to_inode(vp); | 619 | struct inode *inode = vn_to_inode(vp); |
| 624 | 620 | ||
| 625 | vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address); | 621 | vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address); |
| @@ -645,7 +641,7 @@ xfs_iput_new(xfs_inode_t *ip, | |||
| 645 | void | 641 | void |
| 646 | xfs_ireclaim(xfs_inode_t *ip) | 642 | xfs_ireclaim(xfs_inode_t *ip) |
| 647 | { | 643 | { |
| 648 | vnode_t *vp; | 644 | bhv_vnode_t *vp; |
| 649 | 645 | ||
| 650 | /* | 646 | /* |
| 651 | * Remove from old hash list and mount list. | 647 | * Remove from old hash list and mount list. |
| @@ -1033,6 +1029,6 @@ xfs_iflock_nowait(xfs_inode_t *ip) | |||
| 1033 | void | 1029 | void |
| 1034 | xfs_ifunlock(xfs_inode_t *ip) | 1030 | xfs_ifunlock(xfs_inode_t *ip) |
| 1035 | { | 1031 | { |
| 1036 | ASSERT(valusema(&(ip->i_flock)) <= 0); | 1032 | ASSERT(issemalocked(&(ip->i_flock))); |
| 1037 | vsema(&(ip->i_flock)); | 1033 | vsema(&(ip->i_flock)); |
| 1038 | } | 1034 | } |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 94b60dd03801..5fa0adb7e173 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -26,14 +26,12 @@ | |||
| 26 | #include "xfs_trans_priv.h" | 26 | #include "xfs_trans_priv.h" |
| 27 | #include "xfs_sb.h" | 27 | #include "xfs_sb.h" |
| 28 | #include "xfs_ag.h" | 28 | #include "xfs_ag.h" |
| 29 | #include "xfs_dir.h" | ||
| 30 | #include "xfs_dir2.h" | 29 | #include "xfs_dir2.h" |
| 31 | #include "xfs_dmapi.h" | 30 | #include "xfs_dmapi.h" |
| 32 | #include "xfs_mount.h" | 31 | #include "xfs_mount.h" |
| 33 | #include "xfs_bmap_btree.h" | 32 | #include "xfs_bmap_btree.h" |
| 34 | #include "xfs_alloc_btree.h" | 33 | #include "xfs_alloc_btree.h" |
| 35 | #include "xfs_ialloc_btree.h" | 34 | #include "xfs_ialloc_btree.h" |
| 36 | #include "xfs_dir_sf.h" | ||
| 37 | #include "xfs_dir2_sf.h" | 35 | #include "xfs_dir2_sf.h" |
| 38 | #include "xfs_attr_sf.h" | 36 | #include "xfs_attr_sf.h" |
| 39 | #include "xfs_dinode.h" | 37 | #include "xfs_dinode.h" |
| @@ -256,13 +254,11 @@ xfs_itobp( | |||
| 256 | xfs_daddr_t bno, | 254 | xfs_daddr_t bno, |
| 257 | uint imap_flags) | 255 | uint imap_flags) |
| 258 | { | 256 | { |
| 257 | xfs_imap_t imap; | ||
| 259 | xfs_buf_t *bp; | 258 | xfs_buf_t *bp; |
| 260 | int error; | 259 | int error; |
| 261 | xfs_imap_t imap; | ||
| 262 | #ifdef __KERNEL__ | ||
| 263 | int i; | 260 | int i; |
| 264 | int ni; | 261 | int ni; |
| 265 | #endif | ||
| 266 | 262 | ||
| 267 | if (ip->i_blkno == (xfs_daddr_t)0) { | 263 | if (ip->i_blkno == (xfs_daddr_t)0) { |
| 268 | /* | 264 | /* |
| @@ -319,7 +315,6 @@ xfs_itobp( | |||
| 319 | */ | 315 | */ |
| 320 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno, | 316 | error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno, |
| 321 | (int)imap.im_len, XFS_BUF_LOCK, &bp); | 317 | (int)imap.im_len, XFS_BUF_LOCK, &bp); |
| 322 | |||
| 323 | if (error) { | 318 | if (error) { |
| 324 | #ifdef DEBUG | 319 | #ifdef DEBUG |
| 325 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: " | 320 | xfs_fs_cmn_err(CE_ALERT, mp, "xfs_itobp: " |
| @@ -330,17 +325,21 @@ xfs_itobp( | |||
| 330 | #endif /* DEBUG */ | 325 | #endif /* DEBUG */ |
| 331 | return error; | 326 | return error; |
| 332 | } | 327 | } |
| 333 | #ifdef __KERNEL__ | 328 | |
| 334 | /* | 329 | /* |
| 335 | * Validate the magic number and version of every inode in the buffer | 330 | * Validate the magic number and version of every inode in the buffer |
| 336 | * (if DEBUG kernel) or the first inode in the buffer, otherwise. | 331 | * (if DEBUG kernel) or the first inode in the buffer, otherwise. |
| 332 | * No validation is done here in userspace (xfs_repair). | ||
| 337 | */ | 333 | */ |
| 338 | #ifdef DEBUG | 334 | #if !defined(__KERNEL__) |
| 335 | ni = 0; | ||
| 336 | #elif defined(DEBUG) | ||
| 339 | ni = (imap_flags & XFS_IMAP_BULKSTAT) ? 0 : | 337 | ni = (imap_flags & XFS_IMAP_BULKSTAT) ? 0 : |
| 340 | (BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog); | 338 | (BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog); |
| 341 | #else | 339 | #else /* usual case */ |
| 342 | ni = (imap_flags & XFS_IMAP_BULKSTAT) ? 0 : 1; | 340 | ni = (imap_flags & XFS_IMAP_BULKSTAT) ? 0 : 1; |
| 343 | #endif | 341 | #endif |
| 342 | |||
| 344 | for (i = 0; i < ni; i++) { | 343 | for (i = 0; i < ni; i++) { |
| 345 | int di_ok; | 344 | int di_ok; |
| 346 | xfs_dinode_t *dip; | 345 | xfs_dinode_t *dip; |
| @@ -352,8 +351,11 @@ xfs_itobp( | |||
| 352 | if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, | 351 | if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, |
| 353 | XFS_RANDOM_ITOBP_INOTOBP))) { | 352 | XFS_RANDOM_ITOBP_INOTOBP))) { |
| 354 | #ifdef DEBUG | 353 | #ifdef DEBUG |
| 355 | prdev("bad inode magic/vsn daddr %lld #%d (magic=%x)", | 354 | if (!(imap_flags & XFS_IMAP_BULKSTAT)) |
| 356 | mp->m_ddev_targp, | 355 | cmn_err(CE_ALERT, |
| 356 | "Device %s - bad inode magic/vsn " | ||
| 357 | "daddr %lld #%d (magic=%x)", | ||
| 358 | XFS_BUFTARG_NAME(mp->m_ddev_targp), | ||
| 357 | (unsigned long long)imap.im_blkno, i, | 359 | (unsigned long long)imap.im_blkno, i, |
| 358 | INT_GET(dip->di_core.di_magic, ARCH_CONVERT)); | 360 | INT_GET(dip->di_core.di_magic, ARCH_CONVERT)); |
| 359 | #endif | 361 | #endif |
| @@ -363,7 +365,6 @@ xfs_itobp( | |||
| 363 | return XFS_ERROR(EFSCORRUPTED); | 365 | return XFS_ERROR(EFSCORRUPTED); |
| 364 | } | 366 | } |
| 365 | } | 367 | } |
| 366 | #endif /* __KERNEL__ */ | ||
| 367 | 368 | ||
| 368 | xfs_inobp_check(mp, bp); | 369 | xfs_inobp_check(mp, bp); |
| 369 | 370 | ||
| @@ -782,7 +783,6 @@ xfs_xlate_dinode_core( | |||
| 782 | 783 | ||
| 783 | STATIC uint | 784 | STATIC uint |
| 784 | _xfs_dic2xflags( | 785 | _xfs_dic2xflags( |
| 785 | xfs_dinode_core_t *dic, | ||
| 786 | __uint16_t di_flags) | 786 | __uint16_t di_flags) |
| 787 | { | 787 | { |
| 788 | uint flags = 0; | 788 | uint flags = 0; |
| @@ -812,6 +812,8 @@ _xfs_dic2xflags( | |||
| 812 | flags |= XFS_XFLAG_EXTSIZE; | 812 | flags |= XFS_XFLAG_EXTSIZE; |
| 813 | if (di_flags & XFS_DIFLAG_EXTSZINHERIT) | 813 | if (di_flags & XFS_DIFLAG_EXTSZINHERIT) |
| 814 | flags |= XFS_XFLAG_EXTSZINHERIT; | 814 | flags |= XFS_XFLAG_EXTSZINHERIT; |
| 815 | if (di_flags & XFS_DIFLAG_NODEFRAG) | ||
| 816 | flags |= XFS_XFLAG_NODEFRAG; | ||
| 815 | } | 817 | } |
| 816 | 818 | ||
| 817 | return flags; | 819 | return flags; |
| @@ -823,16 +825,16 @@ xfs_ip2xflags( | |||
| 823 | { | 825 | { |
| 824 | xfs_dinode_core_t *dic = &ip->i_d; | 826 | xfs_dinode_core_t *dic = &ip->i_d; |
| 825 | 827 | ||
| 826 | return _xfs_dic2xflags(dic, dic->di_flags) | | 828 | return _xfs_dic2xflags(dic->di_flags) | |
| 827 | (XFS_CFORK_Q(dic) ? XFS_XFLAG_HASATTR : 0); | 829 | (XFS_CFORK_Q(dic) ? XFS_XFLAG_HASATTR : 0); |
| 828 | } | 830 | } |
| 829 | 831 | ||
| 830 | uint | 832 | uint |
| 831 | xfs_dic2xflags( | 833 | xfs_dic2xflags( |
| 832 | xfs_dinode_core_t *dic) | 834 | xfs_dinode_core_t *dic) |
| 833 | { | 835 | { |
| 834 | return _xfs_dic2xflags(dic, INT_GET(dic->di_flags, ARCH_CONVERT)) | | 836 | return _xfs_dic2xflags(INT_GET(dic->di_flags, ARCH_CONVERT)) | |
| 835 | (XFS_CFORK_Q_DISK(dic) ? XFS_XFLAG_HASATTR : 0); | 837 | (XFS_CFORK_Q_DISK(dic) ? XFS_XFLAG_HASATTR : 0); |
| 836 | } | 838 | } |
| 837 | 839 | ||
| 838 | /* | 840 | /* |
| @@ -1083,7 +1085,7 @@ xfs_ialloc( | |||
| 1083 | { | 1085 | { |
| 1084 | xfs_ino_t ino; | 1086 | xfs_ino_t ino; |
| 1085 | xfs_inode_t *ip; | 1087 | xfs_inode_t *ip; |
| 1086 | vnode_t *vp; | 1088 | bhv_vnode_t *vp; |
| 1087 | uint flags; | 1089 | uint flags; |
| 1088 | int error; | 1090 | int error; |
| 1089 | 1091 | ||
| @@ -1221,6 +1223,9 @@ xfs_ialloc( | |||
| 1221 | di_flags |= XFS_DIFLAG_NOSYMLINKS; | 1223 | di_flags |= XFS_DIFLAG_NOSYMLINKS; |
| 1222 | if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) | 1224 | if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) |
| 1223 | di_flags |= XFS_DIFLAG_PROJINHERIT; | 1225 | di_flags |= XFS_DIFLAG_PROJINHERIT; |
| 1226 | if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) && | ||
| 1227 | xfs_inherit_nodefrag) | ||
| 1228 | di_flags |= XFS_DIFLAG_NODEFRAG; | ||
| 1224 | ip->i_d.di_flags |= di_flags; | 1229 | ip->i_d.di_flags |= di_flags; |
| 1225 | } | 1230 | } |
| 1226 | /* FALLTHROUGH */ | 1231 | /* FALLTHROUGH */ |
| @@ -1244,8 +1249,8 @@ xfs_ialloc( | |||
| 1244 | */ | 1249 | */ |
| 1245 | xfs_trans_log_inode(tp, ip, flags); | 1250 | xfs_trans_log_inode(tp, ip, flags); |
| 1246 | 1251 | ||
| 1247 | /* now that we have an i_mode we can set Linux inode ops (& unlock) */ | 1252 | /* now that we have an i_mode we can setup inode ops and unlock */ |
| 1248 | VFS_INIT_VNODE(XFS_MTOVFS(tp->t_mountp), vp, XFS_ITOBHV(ip), 1); | 1253 | bhv_vfs_init_vnode(XFS_MTOVFS(tp->t_mountp), vp, XFS_ITOBHV(ip), 1); |
| 1249 | 1254 | ||
| 1250 | *ipp = ip; | 1255 | *ipp = ip; |
| 1251 | return 0; | 1256 | return 0; |
| @@ -1285,7 +1290,7 @@ xfs_isize_check( | |||
| 1285 | (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) - | 1290 | (xfs_ufsize_t)XFS_MAXIOFFSET(mp)) - |
| 1286 | map_first), | 1291 | map_first), |
| 1287 | XFS_BMAPI_ENTIRE, NULL, 0, imaps, &nimaps, | 1292 | XFS_BMAPI_ENTIRE, NULL, 0, imaps, &nimaps, |
| 1288 | NULL)) | 1293 | NULL, NULL)) |
| 1289 | return; | 1294 | return; |
| 1290 | ASSERT(nimaps == 1); | 1295 | ASSERT(nimaps == 1); |
| 1291 | ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK); | 1296 | ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK); |
| @@ -1421,7 +1426,7 @@ xfs_itruncate_start( | |||
| 1421 | xfs_fsize_t last_byte; | 1426 | xfs_fsize_t last_byte; |
| 1422 | xfs_off_t toss_start; | 1427 | xfs_off_t toss_start; |
| 1423 | xfs_mount_t *mp; | 1428 | xfs_mount_t *mp; |
| 1424 | vnode_t *vp; | 1429 | bhv_vnode_t *vp; |
| 1425 | 1430 | ||
| 1426 | ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0); | 1431 | ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0); |
| 1427 | ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size)); | 1432 | ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size)); |
| @@ -1434,9 +1439,9 @@ xfs_itruncate_start( | |||
| 1434 | vn_iowait(vp); /* wait for the completion of any pending DIOs */ | 1439 | vn_iowait(vp); /* wait for the completion of any pending DIOs */ |
| 1435 | 1440 | ||
| 1436 | /* | 1441 | /* |
| 1437 | * Call VOP_TOSS_PAGES() or VOP_FLUSHINVAL_PAGES() to get rid of pages and buffers | 1442 | * Call toss_pages or flushinval_pages to get rid of pages |
| 1438 | * overlapping the region being removed. We have to use | 1443 | * overlapping the region being removed. We have to use |
| 1439 | * the less efficient VOP_FLUSHINVAL_PAGES() in the case that the | 1444 | * the less efficient flushinval_pages in the case that the |
| 1440 | * caller may not be able to finish the truncate without | 1445 | * caller may not be able to finish the truncate without |
| 1441 | * dropping the inode's I/O lock. Make sure | 1446 | * dropping the inode's I/O lock. Make sure |
| 1442 | * to catch any pages brought in by buffers overlapping | 1447 | * to catch any pages brought in by buffers overlapping |
| @@ -1445,10 +1450,10 @@ xfs_itruncate_start( | |||
| 1445 | * so that we don't toss things on the same block as | 1450 | * so that we don't toss things on the same block as |
| 1446 | * new_size but before it. | 1451 | * new_size but before it. |
| 1447 | * | 1452 | * |
| 1448 | * Before calling VOP_TOSS_PAGES() or VOP_FLUSHINVAL_PAGES(), make sure to | 1453 | * Before calling toss_page or flushinval_pages, make sure to |
| 1449 | * call remapf() over the same region if the file is mapped. | 1454 | * call remapf() over the same region if the file is mapped. |
| 1450 | * This frees up mapped file references to the pages in the | 1455 | * This frees up mapped file references to the pages in the |
| 1451 | * given range and for the VOP_FLUSHINVAL_PAGES() case it ensures | 1456 | * given range and for the flushinval_pages case it ensures |
| 1452 | * that we get the latest mapped changes flushed out. | 1457 | * that we get the latest mapped changes flushed out. |
| 1453 | */ | 1458 | */ |
| 1454 | toss_start = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); | 1459 | toss_start = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); |
| @@ -1466,9 +1471,9 @@ xfs_itruncate_start( | |||
| 1466 | last_byte); | 1471 | last_byte); |
| 1467 | if (last_byte > toss_start) { | 1472 | if (last_byte > toss_start) { |
| 1468 | if (flags & XFS_ITRUNC_DEFINITE) { | 1473 | if (flags & XFS_ITRUNC_DEFINITE) { |
| 1469 | VOP_TOSS_PAGES(vp, toss_start, -1, FI_REMAPF_LOCKED); | 1474 | bhv_vop_toss_pages(vp, toss_start, -1, FI_REMAPF_LOCKED); |
| 1470 | } else { | 1475 | } else { |
| 1471 | VOP_FLUSHINVAL_PAGES(vp, toss_start, -1, FI_REMAPF_LOCKED); | 1476 | bhv_vop_flushinval_pages(vp, toss_start, -1, FI_REMAPF_LOCKED); |
| 1472 | } | 1477 | } |
| 1473 | } | 1478 | } |
| 1474 | 1479 | ||
| @@ -1666,12 +1671,13 @@ xfs_itruncate_finish( | |||
| 1666 | * runs. | 1671 | * runs. |
| 1667 | */ | 1672 | */ |
| 1668 | XFS_BMAP_INIT(&free_list, &first_block); | 1673 | XFS_BMAP_INIT(&free_list, &first_block); |
| 1669 | error = xfs_bunmapi(ntp, ip, first_unmap_block, | 1674 | error = XFS_BUNMAPI(mp, ntp, &ip->i_iocore, |
| 1670 | unmap_len, | 1675 | first_unmap_block, unmap_len, |
| 1671 | XFS_BMAPI_AFLAG(fork) | | 1676 | XFS_BMAPI_AFLAG(fork) | |
| 1672 | (sync ? 0 : XFS_BMAPI_ASYNC), | 1677 | (sync ? 0 : XFS_BMAPI_ASYNC), |
| 1673 | XFS_ITRUNC_MAX_EXTENTS, | 1678 | XFS_ITRUNC_MAX_EXTENTS, |
| 1674 | &first_block, &free_list, &done); | 1679 | &first_block, &free_list, |
| 1680 | NULL, &done); | ||
| 1675 | if (error) { | 1681 | if (error) { |
| 1676 | /* | 1682 | /* |
| 1677 | * If the bunmapi call encounters an error, | 1683 | * If the bunmapi call encounters an error, |
| @@ -2745,13 +2751,14 @@ xfs_iunpin( | |||
| 2745 | * the inode to become unpinned. | 2751 | * the inode to become unpinned. |
| 2746 | */ | 2752 | */ |
| 2747 | if (!(ip->i_flags & (XFS_IRECLAIM|XFS_IRECLAIMABLE))) { | 2753 | if (!(ip->i_flags & (XFS_IRECLAIM|XFS_IRECLAIMABLE))) { |
| 2748 | vnode_t *vp = XFS_ITOV_NULL(ip); | 2754 | bhv_vnode_t *vp = XFS_ITOV_NULL(ip); |
| 2749 | 2755 | ||
| 2750 | /* make sync come back and flush this inode */ | 2756 | /* make sync come back and flush this inode */ |
| 2751 | if (vp) { | 2757 | if (vp) { |
| 2752 | struct inode *inode = vn_to_inode(vp); | 2758 | struct inode *inode = vn_to_inode(vp); |
| 2753 | 2759 | ||
| 2754 | if (!(inode->i_state & I_NEW)) | 2760 | if (!(inode->i_state & |
| 2761 | (I_NEW|I_FREEING|I_CLEAR))) | ||
| 2755 | mark_inode_dirty_sync(inode); | 2762 | mark_inode_dirty_sync(inode); |
| 2756 | } | 2763 | } |
| 2757 | } | 2764 | } |
| @@ -2916,13 +2923,6 @@ xfs_iflush_fork( | |||
| 2916 | ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); | 2923 | ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); |
| 2917 | memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes); | 2924 | memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes); |
| 2918 | } | 2925 | } |
| 2919 | if (whichfork == XFS_DATA_FORK) { | ||
| 2920 | if (unlikely(XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp, dip))) { | ||
| 2921 | XFS_ERROR_REPORT("xfs_iflush_fork", | ||
| 2922 | XFS_ERRLEVEL_LOW, mp); | ||
| 2923 | return XFS_ERROR(EFSCORRUPTED); | ||
| 2924 | } | ||
| 2925 | } | ||
| 2926 | break; | 2926 | break; |
| 2927 | 2927 | ||
| 2928 | case XFS_DINODE_FMT_EXTENTS: | 2928 | case XFS_DINODE_FMT_EXTENTS: |
| @@ -3006,7 +3006,7 @@ xfs_iflush( | |||
| 3006 | XFS_STATS_INC(xs_iflush_count); | 3006 | XFS_STATS_INC(xs_iflush_count); |
| 3007 | 3007 | ||
| 3008 | ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); | 3008 | ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); |
| 3009 | ASSERT(valusema(&ip->i_flock) <= 0); | 3009 | ASSERT(issemalocked(&(ip->i_flock))); |
| 3010 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || | 3010 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || |
| 3011 | ip->i_d.di_nextents > ip->i_df.if_ext_max); | 3011 | ip->i_d.di_nextents > ip->i_df.if_ext_max); |
| 3012 | 3012 | ||
| @@ -3199,7 +3199,7 @@ xfs_iflush( | |||
| 3199 | 3199 | ||
| 3200 | corrupt_out: | 3200 | corrupt_out: |
| 3201 | xfs_buf_relse(bp); | 3201 | xfs_buf_relse(bp); |
| 3202 | xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); | 3202 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); |
| 3203 | xfs_iflush_abort(ip); | 3203 | xfs_iflush_abort(ip); |
| 3204 | /* | 3204 | /* |
| 3205 | * Unlocks the flush lock | 3205 | * Unlocks the flush lock |
| @@ -3221,7 +3221,7 @@ cluster_corrupt_out: | |||
| 3221 | xfs_buf_relse(bp); | 3221 | xfs_buf_relse(bp); |
| 3222 | } | 3222 | } |
| 3223 | 3223 | ||
| 3224 | xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); | 3224 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); |
| 3225 | 3225 | ||
| 3226 | if(!bufwasdelwri) { | 3226 | if(!bufwasdelwri) { |
| 3227 | /* | 3227 | /* |
| @@ -3264,7 +3264,7 @@ xfs_iflush_int( | |||
| 3264 | SPLDECL(s); | 3264 | SPLDECL(s); |
| 3265 | 3265 | ||
| 3266 | ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); | 3266 | ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); |
| 3267 | ASSERT(valusema(&ip->i_flock) <= 0); | 3267 | ASSERT(issemalocked(&(ip->i_flock))); |
| 3268 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || | 3268 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || |
| 3269 | ip->i_d.di_nextents > ip->i_df.if_ext_max); | 3269 | ip->i_d.di_nextents > ip->i_df.if_ext_max); |
| 3270 | 3270 | ||
| @@ -3504,7 +3504,7 @@ xfs_iflush_all( | |||
| 3504 | xfs_mount_t *mp) | 3504 | xfs_mount_t *mp) |
| 3505 | { | 3505 | { |
| 3506 | xfs_inode_t *ip; | 3506 | xfs_inode_t *ip; |
| 3507 | vnode_t *vp; | 3507 | bhv_vnode_t *vp; |
| 3508 | 3508 | ||
| 3509 | again: | 3509 | again: |
| 3510 | XFS_MOUNT_ILOCK(mp); | 3510 | XFS_MOUNT_ILOCK(mp); |
| @@ -4180,7 +4180,7 @@ xfs_iext_direct_to_inline( | |||
| 4180 | */ | 4180 | */ |
| 4181 | memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, | 4181 | memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, |
| 4182 | nextents * sizeof(xfs_bmbt_rec_t)); | 4182 | nextents * sizeof(xfs_bmbt_rec_t)); |
| 4183 | kmem_free(ifp->if_u1.if_extents, KM_SLEEP); | 4183 | kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); |
| 4184 | ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; | 4184 | ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; |
| 4185 | ifp->if_real_bytes = 0; | 4185 | ifp->if_real_bytes = 0; |
| 4186 | } | 4186 | } |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 3b544db1790b..d10b76ed1e5b 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
| @@ -102,9 +102,9 @@ typedef struct xfs_ifork { | |||
| 102 | 102 | ||
| 103 | #ifdef __KERNEL__ | 103 | #ifdef __KERNEL__ |
| 104 | struct bhv_desc; | 104 | struct bhv_desc; |
| 105 | struct bhv_vnode; | ||
| 105 | struct cred; | 106 | struct cred; |
| 106 | struct ktrace; | 107 | struct ktrace; |
| 107 | struct vnode; | ||
| 108 | struct xfs_buf; | 108 | struct xfs_buf; |
| 109 | struct xfs_bmap_free; | 109 | struct xfs_bmap_free; |
| 110 | struct xfs_bmbt_irec; | 110 | struct xfs_bmbt_irec; |
| @@ -400,7 +400,7 @@ void xfs_chash_init(struct xfs_mount *); | |||
| 400 | void xfs_chash_free(struct xfs_mount *); | 400 | void xfs_chash_free(struct xfs_mount *); |
| 401 | xfs_inode_t *xfs_inode_incore(struct xfs_mount *, xfs_ino_t, | 401 | xfs_inode_t *xfs_inode_incore(struct xfs_mount *, xfs_ino_t, |
| 402 | struct xfs_trans *); | 402 | struct xfs_trans *); |
| 403 | void xfs_inode_lock_init(xfs_inode_t *, struct vnode *); | 403 | void xfs_inode_lock_init(xfs_inode_t *, struct bhv_vnode *); |
| 404 | int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, | 404 | int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, |
| 405 | uint, uint, xfs_inode_t **, xfs_daddr_t); | 405 | uint, uint, xfs_inode_t **, xfs_daddr_t); |
| 406 | void xfs_iput(xfs_inode_t *, uint); | 406 | void xfs_iput(xfs_inode_t *, uint); |
| @@ -461,7 +461,7 @@ void xfs_ichgtime(xfs_inode_t *, int); | |||
| 461 | xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); | 461 | xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); |
| 462 | void xfs_lock_inodes(xfs_inode_t **, int, int, uint); | 462 | void xfs_lock_inodes(xfs_inode_t **, int, int, uint); |
| 463 | 463 | ||
| 464 | xfs_inode_t *xfs_vtoi(struct vnode *vp); | 464 | xfs_inode_t *xfs_vtoi(struct bhv_vnode *vp); |
| 465 | 465 | ||
| 466 | void xfs_synchronize_atime(xfs_inode_t *); | 466 | void xfs_synchronize_atime(xfs_inode_t *); |
| 467 | 467 | ||
| @@ -509,7 +509,6 @@ extern struct kmem_zone *xfs_chashlist_zone; | |||
| 509 | extern struct kmem_zone *xfs_ifork_zone; | 509 | extern struct kmem_zone *xfs_ifork_zone; |
| 510 | extern struct kmem_zone *xfs_inode_zone; | 510 | extern struct kmem_zone *xfs_inode_zone; |
| 511 | extern struct kmem_zone *xfs_ili_zone; | 511 | extern struct kmem_zone *xfs_ili_zone; |
| 512 | extern struct vnodeops xfs_vnodeops; | ||
| 513 | 512 | ||
| 514 | #endif /* __KERNEL__ */ | 513 | #endif /* __KERNEL__ */ |
| 515 | 514 | ||
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 7497a481b2f5..f8e80d8e7237 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | #include "xfs_buf_item.h" | 25 | #include "xfs_buf_item.h" |
| 26 | #include "xfs_sb.h" | 26 | #include "xfs_sb.h" |
| 27 | #include "xfs_ag.h" | 27 | #include "xfs_ag.h" |
| 28 | #include "xfs_dir.h" | ||
| 29 | #include "xfs_dir2.h" | 28 | #include "xfs_dir2.h" |
| 30 | #include "xfs_dmapi.h" | 29 | #include "xfs_dmapi.h" |
| 31 | #include "xfs_mount.h" | 30 | #include "xfs_mount.h" |
| @@ -33,7 +32,6 @@ | |||
| 33 | #include "xfs_bmap_btree.h" | 32 | #include "xfs_bmap_btree.h" |
| 34 | #include "xfs_alloc_btree.h" | 33 | #include "xfs_alloc_btree.h" |
| 35 | #include "xfs_ialloc_btree.h" | 34 | #include "xfs_ialloc_btree.h" |
| 36 | #include "xfs_dir_sf.h" | ||
| 37 | #include "xfs_dir2_sf.h" | 35 | #include "xfs_dir2_sf.h" |
| 38 | #include "xfs_attr_sf.h" | 36 | #include "xfs_attr_sf.h" |
| 39 | #include "xfs_dinode.h" | 37 | #include "xfs_dinode.h" |
| @@ -794,7 +792,7 @@ xfs_inode_item_pushbuf( | |||
| 794 | * inode flush completed and the inode was taken off the AIL. | 792 | * inode flush completed and the inode was taken off the AIL. |
| 795 | * So, just get out. | 793 | * So, just get out. |
| 796 | */ | 794 | */ |
| 797 | if ((valusema(&(ip->i_flock)) > 0) || | 795 | if (!issemalocked(&(ip->i_flock)) || |
| 798 | ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) { | 796 | ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) { |
| 799 | iip->ili_pushbuf_flag = 0; | 797 | iip->ili_pushbuf_flag = 0; |
| 800 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 798 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
| @@ -816,7 +814,7 @@ xfs_inode_item_pushbuf( | |||
| 816 | * If not, we can flush it async. | 814 | * If not, we can flush it async. |
| 817 | */ | 815 | */ |
| 818 | dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) && | 816 | dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) && |
| 819 | (valusema(&(ip->i_flock)) <= 0)); | 817 | issemalocked(&(ip->i_flock))); |
| 820 | iip->ili_pushbuf_flag = 0; | 818 | iip->ili_pushbuf_flag = 0; |
| 821 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 819 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
| 822 | xfs_buftrace("INODE ITEM PUSH", bp); | 820 | xfs_buftrace("INODE ITEM PUSH", bp); |
| @@ -864,7 +862,7 @@ xfs_inode_item_push( | |||
| 864 | ip = iip->ili_inode; | 862 | ip = iip->ili_inode; |
| 865 | 863 | ||
| 866 | ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS)); | 864 | ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS)); |
| 867 | ASSERT(valusema(&(ip->i_flock)) <= 0); | 865 | ASSERT(issemalocked(&(ip->i_flock))); |
| 868 | /* | 866 | /* |
| 869 | * Since we were able to lock the inode's flush lock and | 867 | * Since we were able to lock the inode's flush lock and |
| 870 | * we found it on the AIL, the inode must be dirty. This | 868 | * we found it on the AIL, the inode must be dirty. This |
| @@ -1084,3 +1082,52 @@ xfs_istale_done( | |||
| 1084 | { | 1082 | { |
| 1085 | xfs_iflush_abort(iip->ili_inode); | 1083 | xfs_iflush_abort(iip->ili_inode); |
| 1086 | } | 1084 | } |
| 1085 | |||
| 1086 | /* | ||
| 1087 | * convert an xfs_inode_log_format struct from either 32 or 64 bit versions | ||
| 1088 | * (which can have different field alignments) to the native version | ||
| 1089 | */ | ||
| 1090 | int | ||
| 1091 | xfs_inode_item_format_convert( | ||
| 1092 | xfs_log_iovec_t *buf, | ||
| 1093 | xfs_inode_log_format_t *in_f) | ||
| 1094 | { | ||
| 1095 | if (buf->i_len == sizeof(xfs_inode_log_format_32_t)) { | ||
| 1096 | xfs_inode_log_format_32_t *in_f32; | ||
| 1097 | |||
| 1098 | in_f32 = (xfs_inode_log_format_32_t *)buf->i_addr; | ||
| 1099 | in_f->ilf_type = in_f32->ilf_type; | ||
| 1100 | in_f->ilf_size = in_f32->ilf_size; | ||
| 1101 | in_f->ilf_fields = in_f32->ilf_fields; | ||
| 1102 | in_f->ilf_asize = in_f32->ilf_asize; | ||
| 1103 | in_f->ilf_dsize = in_f32->ilf_dsize; | ||
| 1104 | in_f->ilf_ino = in_f32->ilf_ino; | ||
| 1105 | /* copy biggest field of ilf_u */ | ||
| 1106 | memcpy(in_f->ilf_u.ilfu_uuid.__u_bits, | ||
| 1107 | in_f32->ilf_u.ilfu_uuid.__u_bits, | ||
| 1108 | sizeof(uuid_t)); | ||
| 1109 | in_f->ilf_blkno = in_f32->ilf_blkno; | ||
| 1110 | in_f->ilf_len = in_f32->ilf_len; | ||
| 1111 | in_f->ilf_boffset = in_f32->ilf_boffset; | ||
| 1112 | return 0; | ||
| 1113 | } else if (buf->i_len == sizeof(xfs_inode_log_format_64_t)){ | ||
| 1114 | xfs_inode_log_format_64_t *in_f64; | ||
| 1115 | |||
| 1116 | in_f64 = (xfs_inode_log_format_64_t *)buf->i_addr; | ||
| 1117 | in_f->ilf_type = in_f64->ilf_type; | ||
| 1118 | in_f->ilf_size = in_f64->ilf_size; | ||
| 1119 | in_f->ilf_fields = in_f64->ilf_fields; | ||
| 1120 | in_f->ilf_asize = in_f64->ilf_asize; | ||
| 1121 | in_f->ilf_dsize = in_f64->ilf_dsize; | ||
| 1122 | in_f->ilf_ino = in_f64->ilf_ino; | ||
| 1123 | /* copy biggest field of ilf_u */ | ||
| 1124 | memcpy(in_f->ilf_u.ilfu_uuid.__u_bits, | ||
| 1125 | in_f64->ilf_u.ilfu_uuid.__u_bits, | ||
| 1126 | sizeof(uuid_t)); | ||
| 1127 | in_f->ilf_blkno = in_f64->ilf_blkno; | ||
| 1128 | in_f->ilf_len = in_f64->ilf_len; | ||
| 1129 | in_f->ilf_boffset = in_f64->ilf_boffset; | ||
| 1130 | return 0; | ||
| 1131 | } | ||
| 1132 | return EFSCORRUPTED; | ||
| 1133 | } | ||
diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h index c5dbf93b6661..5db6cd1b4cf3 100644 --- a/fs/xfs/xfs_inode_item.h +++ b/fs/xfs/xfs_inode_item.h | |||
| @@ -23,25 +23,6 @@ | |||
| 23 | * log. The size of the inline data/extents/b-tree root to be logged | 23 | * log. The size of the inline data/extents/b-tree root to be logged |
| 24 | * (if any) is indicated in the ilf_dsize field. Changes to this structure | 24 | * (if any) is indicated in the ilf_dsize field. Changes to this structure |
| 25 | * must be added on to the end. | 25 | * must be added on to the end. |
| 26 | * | ||
| 27 | * Convention for naming inode log item versions : The current version | ||
| 28 | * is always named XFS_LI_INODE. When an inode log item gets superseded, | ||
| 29 | * add the latest version of IRIX that will generate logs with that item | ||
| 30 | * to the version name. | ||
| 31 | * | ||
| 32 | * -Version 1 of this structure (XFS_LI_5_3_INODE) included up to the first | ||
| 33 | * union (ilf_u) field. This was released with IRIX 5.3-XFS. | ||
| 34 | * -Version 2 of this structure (XFS_LI_6_1_INODE) is currently the entire | ||
| 35 | * structure. This was released with IRIX 6.0.1-XFS and IRIX 6.1. | ||
| 36 | * -Version 3 of this structure (XFS_LI_INODE) is the same as version 2 | ||
| 37 | * so a new structure definition wasn't necessary. However, we had | ||
| 38 | * to add a new type because the inode cluster size changed from 4K | ||
| 39 | * to 8K and the version number had to be rev'ved to keep older kernels | ||
| 40 | * from trying to recover logs with the 8K buffers in them. The logging | ||
| 41 | * code can handle recovery on different-sized clusters now so hopefully | ||
| 42 | * this'll be the last time we need to change the inode log item just | ||
| 43 | * for a change in the inode cluster size. This new version was | ||
| 44 | * released with IRIX 6.2. | ||
| 45 | */ | 26 | */ |
| 46 | typedef struct xfs_inode_log_format { | 27 | typedef struct xfs_inode_log_format { |
| 47 | unsigned short ilf_type; /* inode log item type */ | 28 | unsigned short ilf_type; /* inode log item type */ |
| @@ -59,18 +40,38 @@ typedef struct xfs_inode_log_format { | |||
| 59 | int ilf_boffset; /* off of inode in buffer */ | 40 | int ilf_boffset; /* off of inode in buffer */ |
| 60 | } xfs_inode_log_format_t; | 41 | } xfs_inode_log_format_t; |
| 61 | 42 | ||
| 62 | /* Initial version shipped with IRIX 5.3-XFS */ | 43 | typedef struct xfs_inode_log_format_32 { |
| 63 | typedef struct xfs_inode_log_format_v1 { | 44 | unsigned short ilf_type; /* 16: inode log item type */ |
| 64 | unsigned short ilf_type; /* inode log item type */ | 45 | unsigned short ilf_size; /* 16: size of this item */ |
| 65 | unsigned short ilf_size; /* size of this item */ | 46 | uint ilf_fields; /* 32: flags for fields logged */ |
| 66 | uint ilf_fields; /* flags for fields logged */ | 47 | ushort ilf_asize; /* 32: size of attr d/ext/root */ |
| 67 | uint ilf_dsize; /* size of data/ext/root */ | 48 | ushort ilf_dsize; /* 32: size of data/ext/root */ |
| 68 | xfs_ino_t ilf_ino; /* inode number */ | 49 | xfs_ino_t ilf_ino; /* 64: inode number */ |
| 69 | union { | 50 | union { |
| 70 | xfs_dev_t ilfu_rdev; /* rdev value for dev inode*/ | 51 | xfs_dev_t ilfu_rdev; /* 32: rdev value for dev inode*/ |
| 71 | uuid_t ilfu_uuid; /* mount point value */ | 52 | uuid_t ilfu_uuid; /* 128: mount point value */ |
| 53 | } ilf_u; | ||
| 54 | __int64_t ilf_blkno; /* 64: blkno of inode buffer */ | ||
| 55 | int ilf_len; /* 32: len of inode buffer */ | ||
| 56 | int ilf_boffset; /* 32: off of inode in buffer */ | ||
| 57 | } __attribute__((packed)) xfs_inode_log_format_32_t; | ||
| 58 | |||
| 59 | typedef struct xfs_inode_log_format_64 { | ||
| 60 | unsigned short ilf_type; /* 16: inode log item type */ | ||
| 61 | unsigned short ilf_size; /* 16: size of this item */ | ||
| 62 | uint ilf_fields; /* 32: flags for fields logged */ | ||
| 63 | ushort ilf_asize; /* 32: size of attr d/ext/root */ | ||
| 64 | ushort ilf_dsize; /* 32: size of data/ext/root */ | ||
| 65 | __uint32_t ilf_pad; /* 32: pad for 64 bit boundary */ | ||
| 66 | xfs_ino_t ilf_ino; /* 64: inode number */ | ||
| 67 | union { | ||
| 68 | xfs_dev_t ilfu_rdev; /* 32: rdev value for dev inode*/ | ||
| 69 | uuid_t ilfu_uuid; /* 128: mount point value */ | ||
| 72 | } ilf_u; | 70 | } ilf_u; |
| 73 | } xfs_inode_log_format_t_v1; | 71 | __int64_t ilf_blkno; /* 64: blkno of inode buffer */ |
| 72 | int ilf_len; /* 32: len of inode buffer */ | ||
| 73 | int ilf_boffset; /* 32: off of inode in buffer */ | ||
| 74 | } xfs_inode_log_format_64_t; | ||
| 74 | 75 | ||
| 75 | /* | 76 | /* |
| 76 | * Flags for xfs_trans_log_inode flags field. | 77 | * Flags for xfs_trans_log_inode flags field. |
| @@ -172,6 +173,8 @@ extern void xfs_inode_item_destroy(struct xfs_inode *); | |||
| 172 | extern void xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *); | 173 | extern void xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *); |
| 173 | extern void xfs_istale_done(struct xfs_buf *, xfs_inode_log_item_t *); | 174 | extern void xfs_istale_done(struct xfs_buf *, xfs_inode_log_item_t *); |
| 174 | extern void xfs_iflush_abort(struct xfs_inode *); | 175 | extern void xfs_iflush_abort(struct xfs_inode *); |
| 176 | extern int xfs_inode_item_format_convert(xfs_log_iovec_t *, | ||
| 177 | xfs_inode_log_format_t *); | ||
| 175 | 178 | ||
| 176 | #endif /* __KERNEL__ */ | 179 | #endif /* __KERNEL__ */ |
| 177 | 180 | ||
diff --git a/fs/xfs/xfs_iocore.c b/fs/xfs/xfs_iocore.c index a07815661a8c..06d710c9ce4b 100644 --- a/fs/xfs/xfs_iocore.c +++ b/fs/xfs/xfs_iocore.c | |||
| @@ -24,14 +24,13 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 28 | #include "xfs_dfrag.h" | ||
| 29 | #include "xfs_dmapi.h" | 29 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 30 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| @@ -58,7 +57,7 @@ xfs_size_fn( | |||
| 58 | 57 | ||
| 59 | STATIC int | 58 | STATIC int |
| 60 | xfs_ioinit( | 59 | xfs_ioinit( |
| 61 | struct vfs *vfsp, | 60 | struct bhv_vfs *vfsp, |
| 62 | struct xfs_mount_args *mntargs, | 61 | struct xfs_mount_args *mntargs, |
| 63 | int flags) | 62 | int flags) |
| 64 | { | 63 | { |
| @@ -68,6 +67,7 @@ xfs_ioinit( | |||
| 68 | xfs_ioops_t xfs_iocore_xfs = { | 67 | xfs_ioops_t xfs_iocore_xfs = { |
| 69 | .xfs_ioinit = (xfs_ioinit_t) xfs_ioinit, | 68 | .xfs_ioinit = (xfs_ioinit_t) xfs_ioinit, |
| 70 | .xfs_bmapi_func = (xfs_bmapi_t) xfs_bmapi, | 69 | .xfs_bmapi_func = (xfs_bmapi_t) xfs_bmapi, |
| 70 | .xfs_bunmapi_func = (xfs_bunmapi_t) xfs_bunmapi, | ||
| 71 | .xfs_bmap_eof_func = (xfs_bmap_eof_t) xfs_bmap_eof, | 71 | .xfs_bmap_eof_func = (xfs_bmap_eof_t) xfs_bmap_eof, |
| 72 | .xfs_iomap_write_direct = | 72 | .xfs_iomap_write_direct = |
| 73 | (xfs_iomap_write_direct_t) xfs_iomap_write_direct, | 73 | (xfs_iomap_write_direct_t) xfs_iomap_write_direct, |
| @@ -84,6 +84,7 @@ xfs_ioops_t xfs_iocore_xfs = { | |||
| 84 | .xfs_unlock = (xfs_unlk_t) xfs_iunlock, | 84 | .xfs_unlock = (xfs_unlk_t) xfs_iunlock, |
| 85 | .xfs_size_func = (xfs_size_t) xfs_size_fn, | 85 | .xfs_size_func = (xfs_size_t) xfs_size_fn, |
| 86 | .xfs_iodone = (xfs_iodone_t) fs_noerr, | 86 | .xfs_iodone = (xfs_iodone_t) fs_noerr, |
| 87 | .xfs_swap_extents_func = (xfs_swap_extents_t) xfs_swap_extents, | ||
| 87 | }; | 88 | }; |
| 88 | 89 | ||
| 89 | void | 90 | void |
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index d5dfedcb8922..f1949c16df15 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_alloc.h" | 27 | #include "xfs_alloc.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| @@ -252,7 +250,7 @@ xfs_iomap( | |||
| 252 | error = XFS_BMAPI(mp, NULL, io, offset_fsb, | 250 | error = XFS_BMAPI(mp, NULL, io, offset_fsb, |
| 253 | (xfs_filblks_t)(end_fsb - offset_fsb), | 251 | (xfs_filblks_t)(end_fsb - offset_fsb), |
| 254 | bmapi_flags, NULL, 0, &imap, | 252 | bmapi_flags, NULL, 0, &imap, |
| 255 | &nimaps, NULL); | 253 | &nimaps, NULL, NULL); |
| 256 | 254 | ||
| 257 | if (error) | 255 | if (error) |
| 258 | goto out; | 256 | goto out; |
| @@ -519,8 +517,8 @@ xfs_iomap_write_direct( | |||
| 519 | */ | 517 | */ |
| 520 | XFS_BMAP_INIT(&free_list, &firstfsb); | 518 | XFS_BMAP_INIT(&free_list, &firstfsb); |
| 521 | nimaps = 1; | 519 | nimaps = 1; |
| 522 | error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, | 520 | error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, bmapi_flag, |
| 523 | bmapi_flag, &firstfsb, 0, &imap, &nimaps, &free_list); | 521 | &firstfsb, 0, &imap, &nimaps, &free_list, NULL); |
| 524 | if (error) | 522 | if (error) |
| 525 | goto error0; | 523 | goto error0; |
| 526 | 524 | ||
| @@ -610,8 +608,8 @@ xfs_iomap_eof_want_preallocate( | |||
| 610 | while (count_fsb > 0) { | 608 | while (count_fsb > 0) { |
| 611 | imaps = nimaps; | 609 | imaps = nimaps; |
| 612 | firstblock = NULLFSBLOCK; | 610 | firstblock = NULLFSBLOCK; |
| 613 | error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb, | 611 | error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb, 0, |
| 614 | 0, &firstblock, 0, imap, &imaps, NULL); | 612 | &firstblock, 0, imap, &imaps, NULL, NULL); |
| 615 | if (error) | 613 | if (error) |
| 616 | return error; | 614 | return error; |
| 617 | for (n = 0; n < imaps; n++) { | 615 | for (n = 0; n < imaps; n++) { |
| @@ -695,11 +693,11 @@ retry: | |||
| 695 | 693 | ||
| 696 | nimaps = XFS_WRITE_IMAPS; | 694 | nimaps = XFS_WRITE_IMAPS; |
| 697 | firstblock = NULLFSBLOCK; | 695 | firstblock = NULLFSBLOCK; |
| 698 | error = xfs_bmapi(NULL, ip, offset_fsb, | 696 | error = XFS_BMAPI(mp, NULL, io, offset_fsb, |
| 699 | (xfs_filblks_t)(last_fsb - offset_fsb), | 697 | (xfs_filblks_t)(last_fsb - offset_fsb), |
| 700 | XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | | 698 | XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | |
| 701 | XFS_BMAPI_ENTIRE, &firstblock, 1, imap, | 699 | XFS_BMAPI_ENTIRE, &firstblock, 1, imap, |
| 702 | &nimaps, NULL); | 700 | &nimaps, NULL, NULL); |
| 703 | if (error && (error != ENOSPC)) | 701 | if (error && (error != ENOSPC)) |
| 704 | return XFS_ERROR(error); | 702 | return XFS_ERROR(error); |
| 705 | 703 | ||
| @@ -832,9 +830,9 @@ xfs_iomap_write_allocate( | |||
| 832 | } | 830 | } |
| 833 | 831 | ||
| 834 | /* Go get the actual blocks */ | 832 | /* Go get the actual blocks */ |
| 835 | error = xfs_bmapi(tp, ip, map_start_fsb, count_fsb, | 833 | error = XFS_BMAPI(mp, tp, io, map_start_fsb, count_fsb, |
| 836 | XFS_BMAPI_WRITE, &first_block, 1, | 834 | XFS_BMAPI_WRITE, &first_block, 1, |
| 837 | imap, &nimaps, &free_list); | 835 | imap, &nimaps, &free_list, NULL); |
| 838 | if (error) | 836 | if (error) |
| 839 | goto trans_cancel; | 837 | goto trans_cancel; |
| 840 | 838 | ||
| @@ -955,9 +953,9 @@ xfs_iomap_write_unwritten( | |||
| 955 | */ | 953 | */ |
| 956 | XFS_BMAP_INIT(&free_list, &firstfsb); | 954 | XFS_BMAP_INIT(&free_list, &firstfsb); |
| 957 | nimaps = 1; | 955 | nimaps = 1; |
| 958 | error = xfs_bmapi(tp, ip, offset_fsb, count_fsb, | 956 | error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, |
| 959 | XFS_BMAPI_WRITE|XFS_BMAPI_CONVERT, &firstfsb, | 957 | XFS_BMAPI_WRITE|XFS_BMAPI_CONVERT, &firstfsb, |
| 960 | 1, &imap, &nimaps, &free_list); | 958 | 1, &imap, &nimaps, &free_list, NULL); |
| 961 | if (error) | 959 | if (error) |
| 962 | goto error_on_bmapi_transaction; | 960 | goto error_on_bmapi_transaction; |
| 963 | 961 | ||
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 94068d014f27..46249e4d1fea 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -41,11 +39,6 @@ | |||
| 41 | #include "xfs_error.h" | 39 | #include "xfs_error.h" |
| 42 | #include "xfs_btree.h" | 40 | #include "xfs_btree.h" |
| 43 | 41 | ||
| 44 | #ifndef HAVE_USERACC | ||
| 45 | #define useracc(ubuffer, size, flags, foo) (0) | ||
| 46 | #define unuseracc(ubuffer, size, flags) | ||
| 47 | #endif | ||
| 48 | |||
| 49 | STATIC int | 42 | STATIC int |
| 50 | xfs_bulkstat_one_iget( | 43 | xfs_bulkstat_one_iget( |
| 51 | xfs_mount_t *mp, /* mount point for filesystem */ | 44 | xfs_mount_t *mp, /* mount point for filesystem */ |
| @@ -56,7 +49,7 @@ xfs_bulkstat_one_iget( | |||
| 56 | { | 49 | { |
| 57 | xfs_dinode_core_t *dic; /* dinode core info pointer */ | 50 | xfs_dinode_core_t *dic; /* dinode core info pointer */ |
| 58 | xfs_inode_t *ip; /* incore inode pointer */ | 51 | xfs_inode_t *ip; /* incore inode pointer */ |
| 59 | vnode_t *vp; | 52 | bhv_vnode_t *vp; |
| 60 | int error; | 53 | int error; |
| 61 | 54 | ||
| 62 | error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, bno); | 55 | error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, bno); |
| @@ -336,15 +329,6 @@ xfs_bulkstat( | |||
| 336 | nimask = ~(nicluster - 1); | 329 | nimask = ~(nicluster - 1); |
| 337 | nbcluster = nicluster >> mp->m_sb.sb_inopblog; | 330 | nbcluster = nicluster >> mp->m_sb.sb_inopblog; |
| 338 | /* | 331 | /* |
| 339 | * Lock down the user's buffer. If a buffer was not sent, as in the case | ||
| 340 | * disk quota code calls here, we skip this. | ||
| 341 | */ | ||
| 342 | if (ubuffer && | ||
| 343 | (error = useracc(ubuffer, ubcount * statstruct_size, | ||
| 344 | (B_READ|B_PHYS), NULL))) { | ||
| 345 | return error; | ||
| 346 | } | ||
| 347 | /* | ||
| 348 | * Allocate a page-sized buffer for inode btree records. | 332 | * Allocate a page-sized buffer for inode btree records. |
| 349 | * We could try allocating something smaller, but for normal | 333 | * We could try allocating something smaller, but for normal |
| 350 | * calls we'll always (potentially) need the whole page. | 334 | * calls we'll always (potentially) need the whole page. |
| @@ -650,8 +634,6 @@ xfs_bulkstat( | |||
| 650 | * Done, we're either out of filesystem or space to put the data. | 634 | * Done, we're either out of filesystem or space to put the data. |
| 651 | */ | 635 | */ |
| 652 | kmem_free(irbuf, NBPC); | 636 | kmem_free(irbuf, NBPC); |
| 653 | if (ubuffer) | ||
| 654 | unuseracc(ubuffer, ubcount * statstruct_size, (B_READ|B_PHYS)); | ||
| 655 | *ubcountp = ubelem; | 637 | *ubcountp = ubelem; |
| 656 | if (agno >= mp->m_sb.sb_agcount) { | 638 | if (agno >= mp->m_sb.sb_agcount) { |
| 657 | /* | 639 | /* |
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h index 11eb4e1b18c4..be5f12e07d22 100644 --- a/fs/xfs/xfs_itable.h +++ b/fs/xfs/xfs_itable.h | |||
| @@ -45,7 +45,6 @@ typedef int (*bulkstat_one_pf)(struct xfs_mount *mp, | |||
| 45 | */ | 45 | */ |
| 46 | #define BULKSTAT_FG_IGET 0x1 /* Go through the buffer cache */ | 46 | #define BULKSTAT_FG_IGET 0x1 /* Go through the buffer cache */ |
| 47 | #define BULKSTAT_FG_QUICK 0x2 /* No iget, walk the dinode cluster */ | 47 | #define BULKSTAT_FG_QUICK 0x2 /* No iget, walk the dinode cluster */ |
| 48 | #define BULKSTAT_FG_VFSLOCKED 0x4 /* Already have vfs lock */ | ||
| 49 | 48 | ||
| 50 | /* | 49 | /* |
| 51 | * Return stat information in bulk (by-inode) for the filesystem. | 50 | * Return stat information in bulk (by-inode) for the filesystem. |
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 32e841d2f26d..d8f5d4cbe8b7 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| @@ -36,7 +35,6 @@ | |||
| 36 | #include "xfs_ialloc_btree.h" | 35 | #include "xfs_ialloc_btree.h" |
| 37 | #include "xfs_log_recover.h" | 36 | #include "xfs_log_recover.h" |
| 38 | #include "xfs_trans_priv.h" | 37 | #include "xfs_trans_priv.h" |
| 39 | #include "xfs_dir_sf.h" | ||
| 40 | #include "xfs_dir2_sf.h" | 38 | #include "xfs_dir2_sf.h" |
| 41 | #include "xfs_attr_sf.h" | 39 | #include "xfs_attr_sf.h" |
| 42 | #include "xfs_dinode.h" | 40 | #include "xfs_dinode.h" |
| @@ -402,7 +400,7 @@ xfs_log_release_iclog(xfs_mount_t *mp, | |||
| 402 | xlog_in_core_t *iclog = (xlog_in_core_t *)iclog_hndl; | 400 | xlog_in_core_t *iclog = (xlog_in_core_t *)iclog_hndl; |
| 403 | 401 | ||
| 404 | if (xlog_state_release_iclog(log, iclog)) { | 402 | if (xlog_state_release_iclog(log, iclog)) { |
| 405 | xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); | 403 | xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); |
| 406 | return EIO; | 404 | return EIO; |
| 407 | } | 405 | } |
| 408 | 406 | ||
| @@ -498,9 +496,8 @@ xfs_log_mount(xfs_mount_t *mp, | |||
| 498 | * just worked. | 496 | * just worked. |
| 499 | */ | 497 | */ |
| 500 | if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) { | 498 | if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) { |
| 501 | int error; | 499 | bhv_vfs_t *vfsp = XFS_MTOVFS(mp); |
| 502 | vfs_t *vfsp = XFS_MTOVFS(mp); | 500 | int error, readonly = (vfsp->vfs_flag & VFS_RDONLY); |
| 503 | int readonly = (vfsp->vfs_flag & VFS_RDONLY); | ||
| 504 | 501 | ||
| 505 | if (readonly) | 502 | if (readonly) |
| 506 | vfsp->vfs_flag &= ~VFS_RDONLY; | 503 | vfsp->vfs_flag &= ~VFS_RDONLY; |
| @@ -726,7 +723,7 @@ xfs_log_write(xfs_mount_t * mp, | |||
| 726 | return XFS_ERROR(EIO); | 723 | return XFS_ERROR(EIO); |
| 727 | 724 | ||
| 728 | if ((error = xlog_write(mp, reg, nentries, tic, start_lsn, NULL, 0))) { | 725 | if ((error = xlog_write(mp, reg, nentries, tic, start_lsn, NULL, 0))) { |
| 729 | xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); | 726 | xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); |
| 730 | } | 727 | } |
| 731 | return error; | 728 | return error; |
| 732 | } /* xfs_log_write */ | 729 | } /* xfs_log_write */ |
| @@ -816,9 +813,9 @@ xfs_log_need_covered(xfs_mount_t *mp) | |||
| 816 | SPLDECL(s); | 813 | SPLDECL(s); |
| 817 | int needed = 0, gen; | 814 | int needed = 0, gen; |
| 818 | xlog_t *log = mp->m_log; | 815 | xlog_t *log = mp->m_log; |
| 819 | vfs_t *vfsp = XFS_MTOVFS(mp); | 816 | bhv_vfs_t *vfsp = XFS_MTOVFS(mp); |
| 820 | 817 | ||
| 821 | if (fs_frozen(vfsp) || XFS_FORCED_SHUTDOWN(mp) || | 818 | if (vfs_test_for_freeze(vfsp) || XFS_FORCED_SHUTDOWN(mp) || |
| 822 | (vfsp->vfs_flag & VFS_RDONLY)) | 819 | (vfsp->vfs_flag & VFS_RDONLY)) |
| 823 | return 0; | 820 | return 0; |
| 824 | 821 | ||
| @@ -956,7 +953,7 @@ xlog_iodone(xfs_buf_t *bp) | |||
| 956 | XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) { | 953 | XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) { |
| 957 | xfs_ioerror_alert("xlog_iodone", l->l_mp, bp, XFS_BUF_ADDR(bp)); | 954 | xfs_ioerror_alert("xlog_iodone", l->l_mp, bp, XFS_BUF_ADDR(bp)); |
| 958 | XFS_BUF_STALE(bp); | 955 | XFS_BUF_STALE(bp); |
| 959 | xfs_force_shutdown(l->l_mp, XFS_LOG_IO_ERROR); | 956 | xfs_force_shutdown(l->l_mp, SHUTDOWN_LOG_IO_ERROR); |
| 960 | /* | 957 | /* |
| 961 | * This flag will be propagated to the trans-committed | 958 | * This flag will be propagated to the trans-committed |
| 962 | * callback routines to let them know that the log-commit | 959 | * callback routines to let them know that the log-commit |
| @@ -1261,7 +1258,7 @@ xlog_commit_record(xfs_mount_t *mp, | |||
| 1261 | ASSERT_ALWAYS(iclog); | 1258 | ASSERT_ALWAYS(iclog); |
| 1262 | if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp, | 1259 | if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp, |
| 1263 | iclog, XLOG_COMMIT_TRANS))) { | 1260 | iclog, XLOG_COMMIT_TRANS))) { |
| 1264 | xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); | 1261 | xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); |
| 1265 | } | 1262 | } |
| 1266 | return error; | 1263 | return error; |
| 1267 | } /* xlog_commit_record */ | 1264 | } /* xlog_commit_record */ |
| @@ -1790,7 +1787,7 @@ xlog_write(xfs_mount_t * mp, | |||
| 1790 | xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, mp, | 1787 | xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, mp, |
| 1791 | "xfs_log_write: reservation ran out. Need to up reservation"); | 1788 | "xfs_log_write: reservation ran out. Need to up reservation"); |
| 1792 | /* If we did not panic, shutdown the filesystem */ | 1789 | /* If we did not panic, shutdown the filesystem */ |
| 1793 | xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); | 1790 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); |
| 1794 | #endif | 1791 | #endif |
| 1795 | } else | 1792 | } else |
| 1796 | ticket->t_curr_res -= len; | 1793 | ticket->t_curr_res -= len; |
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 1f0016b0b4ec..55b4237c2153 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -24,7 +24,6 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_alloc_btree.h" | 32 | #include "xfs_alloc_btree.h" |
| 34 | #include "xfs_ialloc_btree.h" | 33 | #include "xfs_ialloc_btree.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| @@ -193,14 +191,14 @@ xlog_header_check_dump( | |||
| 193 | { | 191 | { |
| 194 | int b; | 192 | int b; |
| 195 | 193 | ||
| 196 | printk("%s: SB : uuid = ", __FUNCTION__); | 194 | cmn_err(CE_DEBUG, "%s: SB : uuid = ", __FUNCTION__); |
| 197 | for (b = 0; b < 16; b++) | 195 | for (b = 0; b < 16; b++) |
| 198 | printk("%02x",((unsigned char *)&mp->m_sb.sb_uuid)[b]); | 196 | cmn_err(CE_DEBUG, "%02x", ((uchar_t *)&mp->m_sb.sb_uuid)[b]); |
| 199 | printk(", fmt = %d\n", XLOG_FMT); | 197 | cmn_err(CE_DEBUG, ", fmt = %d\n", XLOG_FMT); |
| 200 | printk(" log : uuid = "); | 198 | cmn_err(CE_DEBUG, " log : uuid = "); |
| 201 | for (b = 0; b < 16; b++) | 199 | for (b = 0; b < 16; b++) |
| 202 | printk("%02x",((unsigned char *)&head->h_fs_uuid)[b]); | 200 | cmn_err(CE_DEBUG, "%02x",((uchar_t *)&head->h_fs_uuid)[b]); |
| 203 | printk(", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT)); | 201 | cmn_err(CE_DEBUG, ", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT)); |
| 204 | } | 202 | } |
| 205 | #else | 203 | #else |
| 206 | #define xlog_header_check_dump(mp, head) | 204 | #define xlog_header_check_dump(mp, head) |
| @@ -282,7 +280,7 @@ xlog_recover_iodone( | |||
| 282 | mp = XFS_BUF_FSPRIVATE(bp, xfs_mount_t *); | 280 | mp = XFS_BUF_FSPRIVATE(bp, xfs_mount_t *); |
| 283 | xfs_ioerror_alert("xlog_recover_iodone", | 281 | xfs_ioerror_alert("xlog_recover_iodone", |
| 284 | mp, bp, XFS_BUF_ADDR(bp)); | 282 | mp, bp, XFS_BUF_ADDR(bp)); |
| 285 | xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); | 283 | xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); |
| 286 | } | 284 | } |
| 287 | XFS_BUF_SET_FSPRIVATE(bp, NULL); | 285 | XFS_BUF_SET_FSPRIVATE(bp, NULL); |
| 288 | XFS_BUF_CLR_IODONE_FUNC(bp); | 286 | XFS_BUF_CLR_IODONE_FUNC(bp); |
| @@ -1889,7 +1887,7 @@ xlog_recover_do_inode_buffer( | |||
| 1889 | 1887 | ||
| 1890 | buffer_nextp = (xfs_agino_t *)xfs_buf_offset(bp, | 1888 | buffer_nextp = (xfs_agino_t *)xfs_buf_offset(bp, |
| 1891 | next_unlinked_offset); | 1889 | next_unlinked_offset); |
| 1892 | INT_SET(*buffer_nextp, ARCH_CONVERT, *logged_nextp); | 1890 | *buffer_nextp = *logged_nextp; |
| 1893 | } | 1891 | } |
| 1894 | 1892 | ||
| 1895 | return 0; | 1893 | return 0; |
| @@ -2292,12 +2290,22 @@ xlog_recover_do_inode_trans( | |||
| 2292 | int attr_index; | 2290 | int attr_index; |
| 2293 | uint fields; | 2291 | uint fields; |
| 2294 | xfs_dinode_core_t *dicp; | 2292 | xfs_dinode_core_t *dicp; |
| 2293 | int need_free = 0; | ||
| 2295 | 2294 | ||
| 2296 | if (pass == XLOG_RECOVER_PASS1) { | 2295 | if (pass == XLOG_RECOVER_PASS1) { |
| 2297 | return 0; | 2296 | return 0; |
| 2298 | } | 2297 | } |
| 2299 | 2298 | ||
| 2300 | in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr; | 2299 | if (item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)) { |
| 2300 | in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr; | ||
| 2301 | } else { | ||
| 2302 | in_f = (xfs_inode_log_format_t *)kmem_alloc( | ||
| 2303 | sizeof(xfs_inode_log_format_t), KM_SLEEP); | ||
| 2304 | need_free = 1; | ||
| 2305 | error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f); | ||
| 2306 | if (error) | ||
| 2307 | goto error; | ||
| 2308 | } | ||
| 2301 | ino = in_f->ilf_ino; | 2309 | ino = in_f->ilf_ino; |
| 2302 | mp = log->l_mp; | 2310 | mp = log->l_mp; |
| 2303 | if (ITEM_TYPE(item) == XFS_LI_INODE) { | 2311 | if (ITEM_TYPE(item) == XFS_LI_INODE) { |
| @@ -2323,8 +2331,10 @@ xlog_recover_do_inode_trans( | |||
| 2323 | * Inode buffers can be freed, look out for it, | 2331 | * Inode buffers can be freed, look out for it, |
| 2324 | * and do not replay the inode. | 2332 | * and do not replay the inode. |
| 2325 | */ | 2333 | */ |
| 2326 | if (xlog_check_buffer_cancelled(log, imap.im_blkno, imap.im_len, 0)) | 2334 | if (xlog_check_buffer_cancelled(log, imap.im_blkno, imap.im_len, 0)) { |
| 2327 | return 0; | 2335 | error = 0; |
| 2336 | goto error; | ||
| 2337 | } | ||
| 2328 | 2338 | ||
| 2329 | bp = xfs_buf_read_flags(mp->m_ddev_targp, imap.im_blkno, imap.im_len, | 2339 | bp = xfs_buf_read_flags(mp->m_ddev_targp, imap.im_blkno, imap.im_len, |
| 2330 | XFS_BUF_LOCK); | 2340 | XFS_BUF_LOCK); |
| @@ -2333,7 +2343,7 @@ xlog_recover_do_inode_trans( | |||
| 2333 | bp, imap.im_blkno); | 2343 | bp, imap.im_blkno); |
| 2334 | error = XFS_BUF_GETERROR(bp); | 2344 | error = XFS_BUF_GETERROR(bp); |
| 2335 | xfs_buf_relse(bp); | 2345 | xfs_buf_relse(bp); |
| 2336 | return error; | 2346 | goto error; |
| 2337 | } | 2347 | } |
| 2338 | error = 0; | 2348 | error = 0; |
| 2339 | ASSERT(in_f->ilf_fields & XFS_ILOG_CORE); | 2349 | ASSERT(in_f->ilf_fields & XFS_ILOG_CORE); |
| @@ -2350,7 +2360,8 @@ xlog_recover_do_inode_trans( | |||
| 2350 | dip, bp, ino); | 2360 | dip, bp, ino); |
| 2351 | XFS_ERROR_REPORT("xlog_recover_do_inode_trans(1)", | 2361 | XFS_ERROR_REPORT("xlog_recover_do_inode_trans(1)", |
| 2352 | XFS_ERRLEVEL_LOW, mp); | 2362 | XFS_ERRLEVEL_LOW, mp); |
| 2353 | return XFS_ERROR(EFSCORRUPTED); | 2363 | error = EFSCORRUPTED; |
| 2364 | goto error; | ||
| 2354 | } | 2365 | } |
| 2355 | dicp = (xfs_dinode_core_t*)(item->ri_buf[1].i_addr); | 2366 | dicp = (xfs_dinode_core_t*)(item->ri_buf[1].i_addr); |
| 2356 | if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) { | 2367 | if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) { |
| @@ -2360,7 +2371,8 @@ xlog_recover_do_inode_trans( | |||
| 2360 | item, ino); | 2371 | item, ino); |
| 2361 | XFS_ERROR_REPORT("xlog_recover_do_inode_trans(2)", | 2372 | XFS_ERROR_REPORT("xlog_recover_do_inode_trans(2)", |
| 2362 | XFS_ERRLEVEL_LOW, mp); | 2373 | XFS_ERRLEVEL_LOW, mp); |
| 2363 | return XFS_ERROR(EFSCORRUPTED); | 2374 | error = EFSCORRUPTED; |
| 2375 | goto error; | ||
| 2364 | } | 2376 | } |
| 2365 | 2377 | ||
| 2366 | /* Skip replay when the on disk inode is newer than the log one */ | 2378 | /* Skip replay when the on disk inode is newer than the log one */ |
| @@ -2376,7 +2388,8 @@ xlog_recover_do_inode_trans( | |||
| 2376 | /* do nothing */ | 2388 | /* do nothing */ |
| 2377 | } else { | 2389 | } else { |
| 2378 | xfs_buf_relse(bp); | 2390 | xfs_buf_relse(bp); |
| 2379 | return 0; | 2391 | error = 0; |
| 2392 | goto error; | ||
| 2380 | } | 2393 | } |
| 2381 | } | 2394 | } |
| 2382 | /* Take the opportunity to reset the flush iteration count */ | 2395 | /* Take the opportunity to reset the flush iteration count */ |
| @@ -2391,7 +2404,8 @@ xlog_recover_do_inode_trans( | |||
| 2391 | xfs_fs_cmn_err(CE_ALERT, mp, | 2404 | xfs_fs_cmn_err(CE_ALERT, mp, |
| 2392 | "xfs_inode_recover: Bad regular inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", | 2405 | "xfs_inode_recover: Bad regular inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", |
| 2393 | item, dip, bp, ino); | 2406 | item, dip, bp, ino); |
| 2394 | return XFS_ERROR(EFSCORRUPTED); | 2407 | error = EFSCORRUPTED; |
| 2408 | goto error; | ||
| 2395 | } | 2409 | } |
| 2396 | } else if (unlikely((dicp->di_mode & S_IFMT) == S_IFDIR)) { | 2410 | } else if (unlikely((dicp->di_mode & S_IFMT) == S_IFDIR)) { |
| 2397 | if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && | 2411 | if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && |
| @@ -2403,7 +2417,8 @@ xlog_recover_do_inode_trans( | |||
| 2403 | xfs_fs_cmn_err(CE_ALERT, mp, | 2417 | xfs_fs_cmn_err(CE_ALERT, mp, |
| 2404 | "xfs_inode_recover: Bad dir inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", | 2418 | "xfs_inode_recover: Bad dir inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", |
| 2405 | item, dip, bp, ino); | 2419 | item, dip, bp, ino); |
| 2406 | return XFS_ERROR(EFSCORRUPTED); | 2420 | error = EFSCORRUPTED; |
| 2421 | goto error; | ||
| 2407 | } | 2422 | } |
| 2408 | } | 2423 | } |
| 2409 | if (unlikely(dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks)){ | 2424 | if (unlikely(dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks)){ |
| @@ -2415,7 +2430,8 @@ xlog_recover_do_inode_trans( | |||
| 2415 | item, dip, bp, ino, | 2430 | item, dip, bp, ino, |
| 2416 | dicp->di_nextents + dicp->di_anextents, | 2431 | dicp->di_nextents + dicp->di_anextents, |
| 2417 | dicp->di_nblocks); | 2432 | dicp->di_nblocks); |
| 2418 | return XFS_ERROR(EFSCORRUPTED); | 2433 | error = EFSCORRUPTED; |
| 2434 | goto error; | ||
| 2419 | } | 2435 | } |
| 2420 | if (unlikely(dicp->di_forkoff > mp->m_sb.sb_inodesize)) { | 2436 | if (unlikely(dicp->di_forkoff > mp->m_sb.sb_inodesize)) { |
| 2421 | XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(6)", | 2437 | XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(6)", |
| @@ -2424,7 +2440,8 @@ xlog_recover_do_inode_trans( | |||
| 2424 | xfs_fs_cmn_err(CE_ALERT, mp, | 2440 | xfs_fs_cmn_err(CE_ALERT, mp, |
| 2425 | "xfs_inode_recover: Bad inode log rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, forkoff 0x%x", | 2441 | "xfs_inode_recover: Bad inode log rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, forkoff 0x%x", |
| 2426 | item, dip, bp, ino, dicp->di_forkoff); | 2442 | item, dip, bp, ino, dicp->di_forkoff); |
| 2427 | return XFS_ERROR(EFSCORRUPTED); | 2443 | error = EFSCORRUPTED; |
| 2444 | goto error; | ||
| 2428 | } | 2445 | } |
| 2429 | if (unlikely(item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t))) { | 2446 | if (unlikely(item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t))) { |
| 2430 | XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(7)", | 2447 | XFS_CORRUPTION_ERROR("xlog_recover_do_inode_trans(7)", |
| @@ -2433,7 +2450,8 @@ xlog_recover_do_inode_trans( | |||
| 2433 | xfs_fs_cmn_err(CE_ALERT, mp, | 2450 | xfs_fs_cmn_err(CE_ALERT, mp, |
| 2434 | "xfs_inode_recover: Bad inode log record length %d, rec ptr 0x%p", | 2451 | "xfs_inode_recover: Bad inode log record length %d, rec ptr 0x%p", |
| 2435 | item->ri_buf[1].i_len, item); | 2452 | item->ri_buf[1].i_len, item); |
| 2436 | return XFS_ERROR(EFSCORRUPTED); | 2453 | error = EFSCORRUPTED; |
| 2454 | goto error; | ||
| 2437 | } | 2455 | } |
| 2438 | 2456 | ||
| 2439 | /* The core is in in-core format */ | 2457 | /* The core is in in-core format */ |
| @@ -2521,7 +2539,8 @@ xlog_recover_do_inode_trans( | |||
| 2521 | xlog_warn("XFS: xlog_recover_do_inode_trans: Invalid flag"); | 2539 | xlog_warn("XFS: xlog_recover_do_inode_trans: Invalid flag"); |
| 2522 | ASSERT(0); | 2540 | ASSERT(0); |
| 2523 | xfs_buf_relse(bp); | 2541 | xfs_buf_relse(bp); |
| 2524 | return XFS_ERROR(EIO); | 2542 | error = EIO; |
| 2543 | goto error; | ||
| 2525 | } | 2544 | } |
| 2526 | } | 2545 | } |
| 2527 | 2546 | ||
| @@ -2537,7 +2556,10 @@ write_inode_buffer: | |||
| 2537 | error = xfs_bwrite(mp, bp); | 2556 | error = xfs_bwrite(mp, bp); |
| 2538 | } | 2557 | } |
| 2539 | 2558 | ||
| 2540 | return (error); | 2559 | error: |
| 2560 | if (need_free) | ||
| 2561 | kmem_free(in_f, sizeof(*in_f)); | ||
| 2562 | return XFS_ERROR(error); | ||
| 2541 | } | 2563 | } |
| 2542 | 2564 | ||
| 2543 | /* | 2565 | /* |
| @@ -2674,32 +2696,32 @@ xlog_recover_do_dquot_trans( | |||
| 2674 | * structure into it, and adds the efi to the AIL with the given | 2696 | * structure into it, and adds the efi to the AIL with the given |
| 2675 | * LSN. | 2697 | * LSN. |
| 2676 | */ | 2698 | */ |
| 2677 | STATIC void | 2699 | STATIC int |
| 2678 | xlog_recover_do_efi_trans( | 2700 | xlog_recover_do_efi_trans( |
| 2679 | xlog_t *log, | 2701 | xlog_t *log, |
| 2680 | xlog_recover_item_t *item, | 2702 | xlog_recover_item_t *item, |
| 2681 | xfs_lsn_t lsn, | 2703 | xfs_lsn_t lsn, |
| 2682 | int pass) | 2704 | int pass) |
| 2683 | { | 2705 | { |
| 2706 | int error; | ||
| 2684 | xfs_mount_t *mp; | 2707 | xfs_mount_t *mp; |
| 2685 | xfs_efi_log_item_t *efip; | 2708 | xfs_efi_log_item_t *efip; |
| 2686 | xfs_efi_log_format_t *efi_formatp; | 2709 | xfs_efi_log_format_t *efi_formatp; |
| 2687 | SPLDECL(s); | 2710 | SPLDECL(s); |
| 2688 | 2711 | ||
| 2689 | if (pass == XLOG_RECOVER_PASS1) { | 2712 | if (pass == XLOG_RECOVER_PASS1) { |
| 2690 | return; | 2713 | return 0; |
| 2691 | } | 2714 | } |
| 2692 | 2715 | ||
| 2693 | efi_formatp = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr; | 2716 | efi_formatp = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr; |
| 2694 | ASSERT(item->ri_buf[0].i_len == | ||
| 2695 | (sizeof(xfs_efi_log_format_t) + | ||
| 2696 | ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t)))); | ||
| 2697 | 2717 | ||
| 2698 | mp = log->l_mp; | 2718 | mp = log->l_mp; |
| 2699 | efip = xfs_efi_init(mp, efi_formatp->efi_nextents); | 2719 | efip = xfs_efi_init(mp, efi_formatp->efi_nextents); |
| 2700 | memcpy((char *)&(efip->efi_format), (char *)efi_formatp, | 2720 | if ((error = xfs_efi_copy_format(&(item->ri_buf[0]), |
| 2701 | sizeof(xfs_efi_log_format_t) + | 2721 | &(efip->efi_format)))) { |
| 2702 | ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t))); | 2722 | xfs_efi_item_free(efip); |
| 2723 | return error; | ||
| 2724 | } | ||
| 2703 | efip->efi_next_extent = efi_formatp->efi_nextents; | 2725 | efip->efi_next_extent = efi_formatp->efi_nextents; |
| 2704 | efip->efi_flags |= XFS_EFI_COMMITTED; | 2726 | efip->efi_flags |= XFS_EFI_COMMITTED; |
| 2705 | 2727 | ||
| @@ -2708,6 +2730,7 @@ xlog_recover_do_efi_trans( | |||
| 2708 | * xfs_trans_update_ail() drops the AIL lock. | 2730 | * xfs_trans_update_ail() drops the AIL lock. |
| 2709 | */ | 2731 | */ |
| 2710 | xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, s); | 2732 | xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, s); |
| 2733 | return 0; | ||
| 2711 | } | 2734 | } |
| 2712 | 2735 | ||
| 2713 | 2736 | ||
| @@ -2738,9 +2761,10 @@ xlog_recover_do_efd_trans( | |||
| 2738 | } | 2761 | } |
| 2739 | 2762 | ||
| 2740 | efd_formatp = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr; | 2763 | efd_formatp = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr; |
| 2741 | ASSERT(item->ri_buf[0].i_len == | 2764 | ASSERT((item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_32_t) + |
| 2742 | (sizeof(xfs_efd_log_format_t) + | 2765 | ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_32_t)))) || |
| 2743 | ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_t)))); | 2766 | (item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_64_t) + |
| 2767 | ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_64_t))))); | ||
| 2744 | efi_id = efd_formatp->efd_efi_id; | 2768 | efi_id = efd_formatp->efd_efi_id; |
| 2745 | 2769 | ||
| 2746 | /* | 2770 | /* |
| @@ -2810,15 +2834,14 @@ xlog_recover_do_trans( | |||
| 2810 | if ((error = xlog_recover_do_buffer_trans(log, item, | 2834 | if ((error = xlog_recover_do_buffer_trans(log, item, |
| 2811 | pass))) | 2835 | pass))) |
| 2812 | break; | 2836 | break; |
| 2813 | } else if ((ITEM_TYPE(item) == XFS_LI_INODE) || | 2837 | } else if ((ITEM_TYPE(item) == XFS_LI_INODE)) { |
| 2814 | (ITEM_TYPE(item) == XFS_LI_6_1_INODE) || | ||
| 2815 | (ITEM_TYPE(item) == XFS_LI_5_3_INODE)) { | ||
| 2816 | if ((error = xlog_recover_do_inode_trans(log, item, | 2838 | if ((error = xlog_recover_do_inode_trans(log, item, |
| 2817 | pass))) | 2839 | pass))) |
| 2818 | break; | 2840 | break; |
| 2819 | } else if (ITEM_TYPE(item) == XFS_LI_EFI) { | 2841 | } else if (ITEM_TYPE(item) == XFS_LI_EFI) { |
| 2820 | xlog_recover_do_efi_trans(log, item, trans->r_lsn, | 2842 | if ((error = xlog_recover_do_efi_trans(log, item, trans->r_lsn, |
| 2821 | pass); | 2843 | pass))) |
| 2844 | break; | ||
| 2822 | } else if (ITEM_TYPE(item) == XFS_LI_EFD) { | 2845 | } else if (ITEM_TYPE(item) == XFS_LI_EFD) { |
| 2823 | xlog_recover_do_efd_trans(log, item, pass); | 2846 | xlog_recover_do_efd_trans(log, item, pass); |
| 2824 | } else if (ITEM_TYPE(item) == XFS_LI_DQUOT) { | 2847 | } else if (ITEM_TYPE(item) == XFS_LI_DQUOT) { |
| @@ -3419,13 +3442,13 @@ xlog_unpack_data_checksum( | |||
| 3419 | if (rhead->h_chksum || | 3442 | if (rhead->h_chksum || |
| 3420 | ((log->l_flags & XLOG_CHKSUM_MISMATCH) == 0)) { | 3443 | ((log->l_flags & XLOG_CHKSUM_MISMATCH) == 0)) { |
| 3421 | cmn_err(CE_DEBUG, | 3444 | cmn_err(CE_DEBUG, |
| 3422 | "XFS: LogR chksum mismatch: was (0x%x) is (0x%x)", | 3445 | "XFS: LogR chksum mismatch: was (0x%x) is (0x%x)\n", |
| 3423 | INT_GET(rhead->h_chksum, ARCH_CONVERT), chksum); | 3446 | INT_GET(rhead->h_chksum, ARCH_CONVERT), chksum); |
| 3424 | cmn_err(CE_DEBUG, | 3447 | cmn_err(CE_DEBUG, |
| 3425 | "XFS: Disregard message if filesystem was created with non-DEBUG kernel"); | 3448 | "XFS: Disregard message if filesystem was created with non-DEBUG kernel"); |
| 3426 | if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { | 3449 | if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) { |
| 3427 | cmn_err(CE_DEBUG, | 3450 | cmn_err(CE_DEBUG, |
| 3428 | "XFS: LogR this is a LogV2 filesystem"); | 3451 | "XFS: LogR this is a LogV2 filesystem\n"); |
| 3429 | } | 3452 | } |
| 3430 | log->l_flags |= XLOG_CHKSUM_MISMATCH; | 3453 | log->l_flags |= XLOG_CHKSUM_MISMATCH; |
| 3431 | } | 3454 | } |
| @@ -3798,7 +3821,7 @@ xlog_do_log_recovery( | |||
| 3798 | error = xlog_do_recovery_pass(log, head_blk, tail_blk, | 3821 | error = xlog_do_recovery_pass(log, head_blk, tail_blk, |
| 3799 | XLOG_RECOVER_PASS2); | 3822 | XLOG_RECOVER_PASS2); |
| 3800 | #ifdef DEBUG | 3823 | #ifdef DEBUG |
| 3801 | { | 3824 | if (!error) { |
| 3802 | int i; | 3825 | int i; |
| 3803 | 3826 | ||
| 3804 | for (i = 0; i < XLOG_BC_TABLE_SIZE; i++) | 3827 | for (i = 0; i < XLOG_BC_TABLE_SIZE; i++) |
| @@ -3974,7 +3997,7 @@ xlog_recover_finish( | |||
| 3974 | log->l_flags &= ~XLOG_RECOVERY_NEEDED; | 3997 | log->l_flags &= ~XLOG_RECOVERY_NEEDED; |
| 3975 | } else { | 3998 | } else { |
| 3976 | cmn_err(CE_DEBUG, | 3999 | cmn_err(CE_DEBUG, |
| 3977 | "!Ending clean XFS mount for filesystem: %s", | 4000 | "!Ending clean XFS mount for filesystem: %s\n", |
| 3978 | log->l_mp->m_fsname); | 4001 | log->l_mp->m_fsname); |
| 3979 | } | 4002 | } |
| 3980 | return 0; | 4003 | return 0; |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index c0b1c2906880..10dbf203c62f 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -196,7 +194,7 @@ xfs_mount_free( | |||
| 196 | kmem_free(mp->m_logname, strlen(mp->m_logname) + 1); | 194 | kmem_free(mp->m_logname, strlen(mp->m_logname) + 1); |
| 197 | 195 | ||
| 198 | if (remove_bhv) { | 196 | if (remove_bhv) { |
| 199 | struct vfs *vfsp = XFS_MTOVFS(mp); | 197 | struct bhv_vfs *vfsp = XFS_MTOVFS(mp); |
| 200 | 198 | ||
| 201 | bhv_remove_all_vfsops(vfsp, 0); | 199 | bhv_remove_all_vfsops(vfsp, 0); |
| 202 | VFS_REMOVEBHV(vfsp, &mp->m_bhv); | 200 | VFS_REMOVEBHV(vfsp, &mp->m_bhv); |
| @@ -337,7 +335,7 @@ xfs_mount_validate_sb( | |||
| 337 | 335 | ||
| 338 | xfs_agnumber_t | 336 | xfs_agnumber_t |
| 339 | xfs_initialize_perag( | 337 | xfs_initialize_perag( |
| 340 | struct vfs *vfs, | 338 | bhv_vfs_t *vfs, |
| 341 | xfs_mount_t *mp, | 339 | xfs_mount_t *mp, |
| 342 | xfs_agnumber_t agcount) | 340 | xfs_agnumber_t agcount) |
| 343 | { | 341 | { |
| @@ -651,14 +649,14 @@ xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) | |||
| 651 | */ | 649 | */ |
| 652 | int | 650 | int |
| 653 | xfs_mountfs( | 651 | xfs_mountfs( |
| 654 | vfs_t *vfsp, | 652 | bhv_vfs_t *vfsp, |
| 655 | xfs_mount_t *mp, | 653 | xfs_mount_t *mp, |
| 656 | int mfsi_flags) | 654 | int mfsi_flags) |
| 657 | { | 655 | { |
| 658 | xfs_buf_t *bp; | 656 | xfs_buf_t *bp; |
| 659 | xfs_sb_t *sbp = &(mp->m_sb); | 657 | xfs_sb_t *sbp = &(mp->m_sb); |
| 660 | xfs_inode_t *rip; | 658 | xfs_inode_t *rip; |
| 661 | vnode_t *rvp = NULL; | 659 | bhv_vnode_t *rvp = NULL; |
| 662 | int readio_log, writeio_log; | 660 | int readio_log, writeio_log; |
| 663 | xfs_daddr_t d; | 661 | xfs_daddr_t d; |
| 664 | __uint64_t ret64; | 662 | __uint64_t ret64; |
| @@ -934,18 +932,7 @@ xfs_mountfs( | |||
| 934 | vfsp->vfs_altfsid = (xfs_fsid_t *)mp->m_fixedfsid; | 932 | vfsp->vfs_altfsid = (xfs_fsid_t *)mp->m_fixedfsid; |
| 935 | mp->m_dmevmask = 0; /* not persistent; set after each mount */ | 933 | mp->m_dmevmask = 0; /* not persistent; set after each mount */ |
| 936 | 934 | ||
| 937 | /* | 935 | xfs_dir_mount(mp); |
| 938 | * Select the right directory manager. | ||
| 939 | */ | ||
| 940 | mp->m_dirops = | ||
| 941 | XFS_SB_VERSION_HASDIRV2(&mp->m_sb) ? | ||
| 942 | xfsv2_dirops : | ||
| 943 | xfsv1_dirops; | ||
| 944 | |||
| 945 | /* | ||
| 946 | * Initialize directory manager's entries. | ||
| 947 | */ | ||
| 948 | XFS_DIR_MOUNT(mp); | ||
| 949 | 936 | ||
| 950 | /* | 937 | /* |
| 951 | * Initialize the attribute manager's entries. | 938 | * Initialize the attribute manager's entries. |
| @@ -1006,8 +993,9 @@ xfs_mountfs( | |||
| 1006 | 993 | ||
| 1007 | if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) { | 994 | if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) { |
| 1008 | cmn_err(CE_WARN, "XFS: corrupted root inode"); | 995 | cmn_err(CE_WARN, "XFS: corrupted root inode"); |
| 1009 | prdev("Root inode %llu is not a directory", | 996 | cmn_err(CE_WARN, "Device %s - root %llu is not a directory", |
| 1010 | mp->m_ddev_targp, (unsigned long long)rip->i_ino); | 997 | XFS_BUFTARG_NAME(mp->m_ddev_targp), |
| 998 | (unsigned long long)rip->i_ino); | ||
| 1011 | xfs_iunlock(rip, XFS_ILOCK_EXCL); | 999 | xfs_iunlock(rip, XFS_ILOCK_EXCL); |
| 1012 | XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW, | 1000 | XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW, |
| 1013 | mp); | 1001 | mp); |
| @@ -1094,7 +1082,7 @@ xfs_mountfs( | |||
| 1094 | int | 1082 | int |
| 1095 | xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) | 1083 | xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) |
| 1096 | { | 1084 | { |
| 1097 | struct vfs *vfsp = XFS_MTOVFS(mp); | 1085 | struct bhv_vfs *vfsp = XFS_MTOVFS(mp); |
| 1098 | #if defined(DEBUG) || defined(INDUCE_IO_ERROR) | 1086 | #if defined(DEBUG) || defined(INDUCE_IO_ERROR) |
| 1099 | int64_t fsid; | 1087 | int64_t fsid; |
| 1100 | #endif | 1088 | #endif |
| @@ -1254,6 +1242,26 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) | |||
| 1254 | 1242 | ||
| 1255 | xfs_trans_log_buf(tp, bp, first, last); | 1243 | xfs_trans_log_buf(tp, bp, first, last); |
| 1256 | } | 1244 | } |
| 1245 | |||
| 1246 | /* | ||
| 1247 | * In order to avoid ENOSPC-related deadlock caused by | ||
| 1248 | * out-of-order locking of AGF buffer (PV 947395), we place | ||
| 1249 | * constraints on the relationship among actual allocations for | ||
| 1250 | * data blocks, freelist blocks, and potential file data bmap | ||
| 1251 | * btree blocks. However, these restrictions may result in no | ||
| 1252 | * actual space allocated for a delayed extent, for example, a data | ||
| 1253 | * block in a certain AG is allocated but there is no additional | ||
| 1254 | * block for the additional bmap btree block due to a split of the | ||
| 1255 | * bmap btree of the file. The result of this may lead to an | ||
| 1256 | * infinite loop in xfssyncd when the file gets flushed to disk and | ||
| 1257 | * all delayed extents need to be actually allocated. To get around | ||
| 1258 | * this, we explicitly set aside a few blocks which will not be | ||
| 1259 | * reserved in delayed allocation. Considering the minimum number of | ||
| 1260 | * needed freelist blocks is 4 fsbs, a potential split of file's bmap | ||
| 1261 | * btree requires 1 fsb, so we set the number of set-aside blocks to 8. | ||
| 1262 | */ | ||
| 1263 | #define SET_ASIDE_BLOCKS 8 | ||
| 1264 | |||
| 1257 | /* | 1265 | /* |
| 1258 | * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply | 1266 | * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply |
| 1259 | * a delta to a specified field in the in-core superblock. Simply | 1267 | * a delta to a specified field in the in-core superblock. Simply |
| @@ -1298,7 +1306,7 @@ xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, | |||
| 1298 | return 0; | 1306 | return 0; |
| 1299 | case XFS_SBS_FDBLOCKS: | 1307 | case XFS_SBS_FDBLOCKS: |
| 1300 | 1308 | ||
| 1301 | lcounter = (long long)mp->m_sb.sb_fdblocks; | 1309 | lcounter = (long long)mp->m_sb.sb_fdblocks - SET_ASIDE_BLOCKS; |
| 1302 | res_used = (long long)(mp->m_resblks - mp->m_resblks_avail); | 1310 | res_used = (long long)(mp->m_resblks - mp->m_resblks_avail); |
| 1303 | 1311 | ||
| 1304 | if (delta > 0) { /* Putting blocks back */ | 1312 | if (delta > 0) { /* Putting blocks back */ |
| @@ -1332,7 +1340,7 @@ xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, | |||
| 1332 | } | 1340 | } |
| 1333 | } | 1341 | } |
| 1334 | 1342 | ||
| 1335 | mp->m_sb.sb_fdblocks = lcounter; | 1343 | mp->m_sb.sb_fdblocks = lcounter + SET_ASIDE_BLOCKS; |
| 1336 | return 0; | 1344 | return 0; |
| 1337 | case XFS_SBS_FREXTENTS: | 1345 | case XFS_SBS_FREXTENTS: |
| 1338 | lcounter = (long long)mp->m_sb.sb_frextents; | 1346 | lcounter = (long long)mp->m_sb.sb_frextents; |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 668ad23fd37c..b2bd4be4200a 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
| @@ -53,8 +53,8 @@ typedef struct xfs_trans_reservations { | |||
| 53 | #else | 53 | #else |
| 54 | struct cred; | 54 | struct cred; |
| 55 | struct log; | 55 | struct log; |
| 56 | struct vfs; | 56 | struct bhv_vfs; |
| 57 | struct vnode; | 57 | struct bhv_vnode; |
| 58 | struct xfs_mount_args; | 58 | struct xfs_mount_args; |
| 59 | struct xfs_ihash; | 59 | struct xfs_ihash; |
| 60 | struct xfs_chash; | 60 | struct xfs_chash; |
| @@ -63,9 +63,11 @@ struct xfs_perag; | |||
| 63 | struct xfs_iocore; | 63 | struct xfs_iocore; |
| 64 | struct xfs_bmbt_irec; | 64 | struct xfs_bmbt_irec; |
| 65 | struct xfs_bmap_free; | 65 | struct xfs_bmap_free; |
| 66 | struct xfs_extdelta; | ||
| 67 | struct xfs_swapext; | ||
| 66 | 68 | ||
| 67 | extern struct vfsops xfs_vfsops; | 69 | extern struct bhv_vfsops xfs_vfsops; |
| 68 | extern struct vnodeops xfs_vnodeops; | 70 | extern struct bhv_vnodeops xfs_vnodeops; |
| 69 | 71 | ||
| 70 | #define AIL_LOCK_T lock_t | 72 | #define AIL_LOCK_T lock_t |
| 71 | #define AIL_LOCKINIT(x,y) spinlock_init(x,y) | 73 | #define AIL_LOCKINIT(x,y) spinlock_init(x,y) |
| @@ -78,15 +80,15 @@ extern struct vnodeops xfs_vnodeops; | |||
| 78 | * Prototypes and functions for the Data Migration subsystem. | 80 | * Prototypes and functions for the Data Migration subsystem. |
| 79 | */ | 81 | */ |
| 80 | 82 | ||
| 81 | typedef int (*xfs_send_data_t)(int, struct vnode *, | 83 | typedef int (*xfs_send_data_t)(int, struct bhv_vnode *, |
| 82 | xfs_off_t, size_t, int, vrwlock_t *); | 84 | xfs_off_t, size_t, int, bhv_vrwlock_t *); |
| 83 | typedef int (*xfs_send_mmap_t)(struct vm_area_struct *, uint); | 85 | typedef int (*xfs_send_mmap_t)(struct vm_area_struct *, uint); |
| 84 | typedef int (*xfs_send_destroy_t)(struct vnode *, dm_right_t); | 86 | typedef int (*xfs_send_destroy_t)(struct bhv_vnode *, dm_right_t); |
| 85 | typedef int (*xfs_send_namesp_t)(dm_eventtype_t, struct vfs *, | 87 | typedef int (*xfs_send_namesp_t)(dm_eventtype_t, struct bhv_vfs *, |
| 86 | struct vnode *, | 88 | struct bhv_vnode *, |
| 87 | dm_right_t, struct vnode *, dm_right_t, | 89 | dm_right_t, struct bhv_vnode *, dm_right_t, |
| 88 | char *, char *, mode_t, int, int); | 90 | char *, char *, mode_t, int, int); |
| 89 | typedef void (*xfs_send_unmount_t)(struct vfs *, struct vnode *, | 91 | typedef void (*xfs_send_unmount_t)(struct bhv_vfs *, struct bhv_vnode *, |
| 90 | dm_right_t, mode_t, int, int); | 92 | dm_right_t, mode_t, int, int); |
| 91 | 93 | ||
| 92 | typedef struct xfs_dmops { | 94 | typedef struct xfs_dmops { |
| @@ -188,13 +190,18 @@ typedef struct xfs_qmops { | |||
| 188 | * Prototypes and functions for I/O core modularization. | 190 | * Prototypes and functions for I/O core modularization. |
| 189 | */ | 191 | */ |
| 190 | 192 | ||
| 191 | typedef int (*xfs_ioinit_t)(struct vfs *, | 193 | typedef int (*xfs_ioinit_t)(struct bhv_vfs *, |
| 192 | struct xfs_mount_args *, int); | 194 | struct xfs_mount_args *, int); |
| 193 | typedef int (*xfs_bmapi_t)(struct xfs_trans *, void *, | 195 | typedef int (*xfs_bmapi_t)(struct xfs_trans *, void *, |
| 194 | xfs_fileoff_t, xfs_filblks_t, int, | 196 | xfs_fileoff_t, xfs_filblks_t, int, |
| 195 | xfs_fsblock_t *, xfs_extlen_t, | 197 | xfs_fsblock_t *, xfs_extlen_t, |
| 196 | struct xfs_bmbt_irec *, int *, | 198 | struct xfs_bmbt_irec *, int *, |
| 197 | struct xfs_bmap_free *); | 199 | struct xfs_bmap_free *, struct xfs_extdelta *); |
| 200 | typedef int (*xfs_bunmapi_t)(struct xfs_trans *, | ||
| 201 | void *, xfs_fileoff_t, | ||
| 202 | xfs_filblks_t, int, xfs_extnum_t, | ||
| 203 | xfs_fsblock_t *, struct xfs_bmap_free *, | ||
| 204 | struct xfs_extdelta *, int *); | ||
| 198 | typedef int (*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *); | 205 | typedef int (*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *); |
| 199 | typedef int (*xfs_iomap_write_direct_t)( | 206 | typedef int (*xfs_iomap_write_direct_t)( |
| 200 | void *, xfs_off_t, size_t, int, | 207 | void *, xfs_off_t, size_t, int, |
| @@ -213,11 +220,14 @@ typedef void (*xfs_lock_demote_t)(void *, uint); | |||
| 213 | typedef int (*xfs_lock_nowait_t)(void *, uint); | 220 | typedef int (*xfs_lock_nowait_t)(void *, uint); |
| 214 | typedef void (*xfs_unlk_t)(void *, unsigned int); | 221 | typedef void (*xfs_unlk_t)(void *, unsigned int); |
| 215 | typedef xfs_fsize_t (*xfs_size_t)(void *); | 222 | typedef xfs_fsize_t (*xfs_size_t)(void *); |
| 216 | typedef xfs_fsize_t (*xfs_iodone_t)(struct vfs *); | 223 | typedef xfs_fsize_t (*xfs_iodone_t)(struct bhv_vfs *); |
| 224 | typedef int (*xfs_swap_extents_t)(void *, void *, | ||
| 225 | struct xfs_swapext*); | ||
| 217 | 226 | ||
| 218 | typedef struct xfs_ioops { | 227 | typedef struct xfs_ioops { |
| 219 | xfs_ioinit_t xfs_ioinit; | 228 | xfs_ioinit_t xfs_ioinit; |
| 220 | xfs_bmapi_t xfs_bmapi_func; | 229 | xfs_bmapi_t xfs_bmapi_func; |
| 230 | xfs_bunmapi_t xfs_bunmapi_func; | ||
| 221 | xfs_bmap_eof_t xfs_bmap_eof_func; | 231 | xfs_bmap_eof_t xfs_bmap_eof_func; |
| 222 | xfs_iomap_write_direct_t xfs_iomap_write_direct; | 232 | xfs_iomap_write_direct_t xfs_iomap_write_direct; |
| 223 | xfs_iomap_write_delay_t xfs_iomap_write_delay; | 233 | xfs_iomap_write_delay_t xfs_iomap_write_delay; |
| @@ -230,13 +240,17 @@ typedef struct xfs_ioops { | |||
| 230 | xfs_unlk_t xfs_unlock; | 240 | xfs_unlk_t xfs_unlock; |
| 231 | xfs_size_t xfs_size_func; | 241 | xfs_size_t xfs_size_func; |
| 232 | xfs_iodone_t xfs_iodone; | 242 | xfs_iodone_t xfs_iodone; |
| 243 | xfs_swap_extents_t xfs_swap_extents_func; | ||
| 233 | } xfs_ioops_t; | 244 | } xfs_ioops_t; |
| 234 | 245 | ||
| 235 | #define XFS_IOINIT(vfsp, args, flags) \ | 246 | #define XFS_IOINIT(vfsp, args, flags) \ |
| 236 | (*(mp)->m_io_ops.xfs_ioinit)(vfsp, args, flags) | 247 | (*(mp)->m_io_ops.xfs_ioinit)(vfsp, args, flags) |
| 237 | #define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist) \ | 248 | #define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist,delta) \ |
| 238 | (*(mp)->m_io_ops.xfs_bmapi_func) \ | 249 | (*(mp)->m_io_ops.xfs_bmapi_func) \ |
| 239 | (trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist) | 250 | (trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist,delta) |
| 251 | #define XFS_BUNMAPI(mp, trans,io,bno,len,f,nexts,first,flist,delta,done) \ | ||
| 252 | (*(mp)->m_io_ops.xfs_bunmapi_func) \ | ||
| 253 | (trans,(io)->io_obj,bno,len,f,nexts,first,flist,delta,done) | ||
| 240 | #define XFS_BMAP_EOF(mp, io, endoff, whichfork, eof) \ | 254 | #define XFS_BMAP_EOF(mp, io, endoff, whichfork, eof) \ |
| 241 | (*(mp)->m_io_ops.xfs_bmap_eof_func) \ | 255 | (*(mp)->m_io_ops.xfs_bmap_eof_func) \ |
| 242 | ((io)->io_obj, endoff, whichfork, eof) | 256 | ((io)->io_obj, endoff, whichfork, eof) |
| @@ -266,6 +280,9 @@ typedef struct xfs_ioops { | |||
| 266 | (*(mp)->m_io_ops.xfs_size_func)((io)->io_obj) | 280 | (*(mp)->m_io_ops.xfs_size_func)((io)->io_obj) |
| 267 | #define XFS_IODONE(vfsp) \ | 281 | #define XFS_IODONE(vfsp) \ |
| 268 | (*(mp)->m_io_ops.xfs_iodone)(vfsp) | 282 | (*(mp)->m_io_ops.xfs_iodone)(vfsp) |
| 283 | #define XFS_SWAP_EXTENTS(mp, io, tio, sxp) \ | ||
| 284 | (*(mp)->m_io_ops.xfs_swap_extents_func) \ | ||
| 285 | ((io)->io_obj, (tio)->io_obj, sxp) | ||
| 269 | 286 | ||
| 270 | #ifdef HAVE_PERCPU_SB | 287 | #ifdef HAVE_PERCPU_SB |
| 271 | 288 | ||
| @@ -386,8 +403,6 @@ typedef struct xfs_mount { | |||
| 386 | __uint8_t m_inode_quiesce;/* call quiesce on new inodes. | 403 | __uint8_t m_inode_quiesce;/* call quiesce on new inodes. |
| 387 | field governed by m_ilock */ | 404 | field governed by m_ilock */ |
| 388 | __uint8_t m_sectbb_log; /* sectlog - BBSHIFT */ | 405 | __uint8_t m_sectbb_log; /* sectlog - BBSHIFT */ |
| 389 | __uint8_t m_dirversion; /* 1 or 2 */ | ||
| 390 | xfs_dirops_t m_dirops; /* table of dir funcs */ | ||
| 391 | int m_dirblksize; /* directory block sz--bytes */ | 406 | int m_dirblksize; /* directory block sz--bytes */ |
| 392 | int m_dirblkfsbs; /* directory block sz--fsbs */ | 407 | int m_dirblkfsbs; /* directory block sz--fsbs */ |
| 393 | xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ | 408 | xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ |
| @@ -494,16 +509,7 @@ xfs_preferred_iosize(xfs_mount_t *mp) | |||
| 494 | 509 | ||
| 495 | #define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN) | 510 | #define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN) |
| 496 | #define xfs_force_shutdown(m,f) \ | 511 | #define xfs_force_shutdown(m,f) \ |
| 497 | VFS_FORCE_SHUTDOWN((XFS_MTOVFS(m)), f, __FILE__, __LINE__) | 512 | bhv_vfs_force_shutdown((XFS_MTOVFS(m)), f, __FILE__, __LINE__) |
| 498 | |||
| 499 | /* | ||
| 500 | * Flags sent to xfs_force_shutdown. | ||
| 501 | */ | ||
| 502 | #define XFS_METADATA_IO_ERROR 0x1 | ||
| 503 | #define XFS_LOG_IO_ERROR 0x2 | ||
| 504 | #define XFS_FORCE_UMOUNT 0x4 | ||
| 505 | #define XFS_CORRUPT_INCORE 0x8 /* Corrupt in-memory data structures */ | ||
| 506 | #define XFS_SHUTDOWN_REMOTE_REQ 0x10 /* Shutdown came from remote cell */ | ||
| 507 | 513 | ||
| 508 | /* | 514 | /* |
| 509 | * Flags for xfs_mountfs | 515 | * Flags for xfs_mountfs |
| @@ -521,7 +527,7 @@ xfs_preferred_iosize(xfs_mount_t *mp) | |||
| 521 | * Macros for getting from mount to vfs and back. | 527 | * Macros for getting from mount to vfs and back. |
| 522 | */ | 528 | */ |
| 523 | #define XFS_MTOVFS(mp) xfs_mtovfs(mp) | 529 | #define XFS_MTOVFS(mp) xfs_mtovfs(mp) |
| 524 | static inline struct vfs *xfs_mtovfs(xfs_mount_t *mp) | 530 | static inline struct bhv_vfs *xfs_mtovfs(xfs_mount_t *mp) |
| 525 | { | 531 | { |
| 526 | return bhvtovfs(&mp->m_bhv); | 532 | return bhvtovfs(&mp->m_bhv); |
| 527 | } | 533 | } |
| @@ -533,7 +539,7 @@ static inline xfs_mount_t *xfs_bhvtom(bhv_desc_t *bdp) | |||
| 533 | } | 539 | } |
| 534 | 540 | ||
| 535 | #define XFS_VFSTOM(vfs) xfs_vfstom(vfs) | 541 | #define XFS_VFSTOM(vfs) xfs_vfstom(vfs) |
| 536 | static inline xfs_mount_t *xfs_vfstom(vfs_t *vfs) | 542 | static inline xfs_mount_t *xfs_vfstom(bhv_vfs_t *vfs) |
| 537 | { | 543 | { |
| 538 | return XFS_BHVTOM(bhv_lookup(VFS_BHVHEAD(vfs), &xfs_vfsops)); | 544 | return XFS_BHVTOM(bhv_lookup(VFS_BHVHEAD(vfs), &xfs_vfsops)); |
| 539 | } | 545 | } |
| @@ -571,7 +577,7 @@ typedef struct xfs_mod_sb { | |||
| 571 | extern xfs_mount_t *xfs_mount_init(void); | 577 | extern xfs_mount_t *xfs_mount_init(void); |
| 572 | extern void xfs_mod_sb(xfs_trans_t *, __int64_t); | 578 | extern void xfs_mod_sb(xfs_trans_t *, __int64_t); |
| 573 | extern void xfs_mount_free(xfs_mount_t *mp, int remove_bhv); | 579 | extern void xfs_mount_free(xfs_mount_t *mp, int remove_bhv); |
| 574 | extern int xfs_mountfs(struct vfs *, xfs_mount_t *mp, int); | 580 | extern int xfs_mountfs(struct bhv_vfs *, xfs_mount_t *mp, int); |
| 575 | extern void xfs_mountfs_check_barriers(xfs_mount_t *mp); | 581 | extern void xfs_mountfs_check_barriers(xfs_mount_t *mp); |
| 576 | 582 | ||
| 577 | extern int xfs_unmountfs(xfs_mount_t *, struct cred *); | 583 | extern int xfs_unmountfs(xfs_mount_t *, struct cred *); |
| @@ -589,7 +595,7 @@ extern void xfs_freesb(xfs_mount_t *); | |||
| 589 | extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int); | 595 | extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int); |
| 590 | extern int xfs_syncsub(xfs_mount_t *, int, int, int *); | 596 | extern int xfs_syncsub(xfs_mount_t *, int, int, int *); |
| 591 | extern int xfs_sync_inodes(xfs_mount_t *, int, int, int *); | 597 | extern int xfs_sync_inodes(xfs_mount_t *, int, int, int *); |
| 592 | extern xfs_agnumber_t xfs_initialize_perag(struct vfs *, xfs_mount_t *, | 598 | extern xfs_agnumber_t xfs_initialize_perag(struct bhv_vfs *, xfs_mount_t *, |
| 593 | xfs_agnumber_t); | 599 | xfs_agnumber_t); |
| 594 | extern void xfs_xlatesb(void *, struct xfs_sb *, int, __int64_t); | 600 | extern void xfs_xlatesb(void *, struct xfs_sb *, int, __int64_t); |
| 595 | 601 | ||
diff --git a/fs/xfs/xfs_qmops.c b/fs/xfs/xfs_qmops.c index 1408a32eef88..320d63ff9ca2 100644 --- a/fs/xfs/xfs_qmops.c +++ b/fs/xfs/xfs_qmops.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_ag.h" | 25 | #include "xfs_ag.h" |
| 26 | #include "xfs_dir.h" | ||
| 27 | #include "xfs_dir2.h" | 26 | #include "xfs_dir2.h" |
| 28 | #include "xfs_dmapi.h" | 27 | #include "xfs_dmapi.h" |
| 29 | #include "xfs_mount.h" | 28 | #include "xfs_mount.h" |
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h index 7fbef974bce6..acb853b33ebb 100644 --- a/fs/xfs/xfs_quota.h +++ b/fs/xfs/xfs_quota.h | |||
| @@ -365,7 +365,7 @@ typedef struct xfs_dqtrxops { | |||
| 365 | extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *); | 365 | extern int xfs_qm_dqcheck(xfs_disk_dquot_t *, xfs_dqid_t, uint, uint, char *); |
| 366 | extern int xfs_mount_reset_sbqflags(struct xfs_mount *); | 366 | extern int xfs_mount_reset_sbqflags(struct xfs_mount *); |
| 367 | 367 | ||
| 368 | extern struct bhv_vfsops xfs_qmops; | 368 | extern struct bhv_module_vfsops xfs_qmops; |
| 369 | 369 | ||
| 370 | #endif /* __KERNEL__ */ | 370 | #endif /* __KERNEL__ */ |
| 371 | 371 | ||
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index 1f148762eb28..d98171deaa1c 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c | |||
| @@ -22,13 +22,11 @@ | |||
| 22 | #include "xfs_inum.h" | 22 | #include "xfs_inum.h" |
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_dir.h" | ||
| 26 | #include "xfs_dir2.h" | 25 | #include "xfs_dir2.h" |
| 27 | #include "xfs_dmapi.h" | 26 | #include "xfs_dmapi.h" |
| 28 | #include "xfs_mount.h" | 27 | #include "xfs_mount.h" |
| 29 | #include "xfs_da_btree.h" | 28 | #include "xfs_da_btree.h" |
| 30 | #include "xfs_bmap_btree.h" | 29 | #include "xfs_bmap_btree.h" |
| 31 | #include "xfs_dir_sf.h" | ||
| 32 | #include "xfs_dir2_sf.h" | 30 | #include "xfs_dir2_sf.h" |
| 33 | #include "xfs_attr_sf.h" | 31 | #include "xfs_attr_sf.h" |
| 34 | #include "xfs_dinode.h" | 32 | #include "xfs_dinode.h" |
| @@ -40,7 +38,6 @@ | |||
| 40 | #include "xfs_refcache.h" | 38 | #include "xfs_refcache.h" |
| 41 | #include "xfs_utils.h" | 39 | #include "xfs_utils.h" |
| 42 | #include "xfs_trans_space.h" | 40 | #include "xfs_trans_space.h" |
| 43 | #include "xfs_dir_leaf.h" | ||
| 44 | 41 | ||
| 45 | 42 | ||
| 46 | /* | 43 | /* |
| @@ -87,8 +84,8 @@ STATIC int | |||
| 87 | xfs_lock_for_rename( | 84 | xfs_lock_for_rename( |
| 88 | xfs_inode_t *dp1, /* old (source) directory inode */ | 85 | xfs_inode_t *dp1, /* old (source) directory inode */ |
| 89 | xfs_inode_t *dp2, /* new (target) directory inode */ | 86 | xfs_inode_t *dp2, /* new (target) directory inode */ |
| 90 | vname_t *vname1,/* old entry name */ | 87 | bhv_vname_t *vname1,/* old entry name */ |
| 91 | vname_t *vname2,/* new entry name */ | 88 | bhv_vname_t *vname2,/* new entry name */ |
| 92 | xfs_inode_t **ipp1, /* inode of old entry */ | 89 | xfs_inode_t **ipp1, /* inode of old entry */ |
| 93 | xfs_inode_t **ipp2, /* inode of new entry, if it | 90 | xfs_inode_t **ipp2, /* inode of new entry, if it |
| 94 | already exists, NULL otherwise. */ | 91 | already exists, NULL otherwise. */ |
| @@ -225,9 +222,9 @@ xfs_lock_for_rename( | |||
| 225 | int | 222 | int |
| 226 | xfs_rename( | 223 | xfs_rename( |
| 227 | bhv_desc_t *src_dir_bdp, | 224 | bhv_desc_t *src_dir_bdp, |
| 228 | vname_t *src_vname, | 225 | bhv_vname_t *src_vname, |
| 229 | vnode_t *target_dir_vp, | 226 | bhv_vnode_t *target_dir_vp, |
| 230 | vname_t *target_vname, | 227 | bhv_vname_t *target_vname, |
| 231 | cred_t *credp) | 228 | cred_t *credp) |
| 232 | { | 229 | { |
| 233 | xfs_trans_t *tp; | 230 | xfs_trans_t *tp; |
| @@ -242,7 +239,7 @@ xfs_rename( | |||
| 242 | int committed; | 239 | int committed; |
| 243 | xfs_inode_t *inodes[4]; | 240 | xfs_inode_t *inodes[4]; |
| 244 | int target_ip_dropped = 0; /* dropped target_ip link? */ | 241 | int target_ip_dropped = 0; /* dropped target_ip link? */ |
| 245 | vnode_t *src_dir_vp; | 242 | bhv_vnode_t *src_dir_vp; |
| 246 | int spaceres; | 243 | int spaceres; |
| 247 | int target_link_zero = 0; | 244 | int target_link_zero = 0; |
| 248 | int num_inodes; | 245 | int num_inodes; |
| @@ -398,34 +395,29 @@ xfs_rename( | |||
| 398 | * fit before actually inserting it. | 395 | * fit before actually inserting it. |
| 399 | */ | 396 | */ |
| 400 | if (spaceres == 0 && | 397 | if (spaceres == 0 && |
| 401 | (error = XFS_DIR_CANENTER(mp, tp, target_dp, target_name, | 398 | (error = xfs_dir_canenter(tp, target_dp, target_name, |
| 402 | target_namelen))) { | 399 | target_namelen))) |
| 403 | goto error_return; | 400 | goto error_return; |
| 404 | } | ||
| 405 | /* | 401 | /* |
| 406 | * If target does not exist and the rename crosses | 402 | * If target does not exist and the rename crosses |
| 407 | * directories, adjust the target directory link count | 403 | * directories, adjust the target directory link count |
| 408 | * to account for the ".." reference from the new entry. | 404 | * to account for the ".." reference from the new entry. |
| 409 | */ | 405 | */ |
| 410 | error = XFS_DIR_CREATENAME(mp, tp, target_dp, target_name, | 406 | error = xfs_dir_createname(tp, target_dp, target_name, |
| 411 | target_namelen, src_ip->i_ino, | 407 | target_namelen, src_ip->i_ino, |
| 412 | &first_block, &free_list, spaceres); | 408 | &first_block, &free_list, spaceres); |
| 413 | if (error == ENOSPC) { | 409 | if (error == ENOSPC) |
| 414 | goto error_return; | 410 | goto error_return; |
| 415 | } | 411 | if (error) |
| 416 | if (error) { | ||
| 417 | goto abort_return; | 412 | goto abort_return; |
| 418 | } | ||
| 419 | xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 413 | xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 420 | 414 | ||
| 421 | if (new_parent && src_is_directory) { | 415 | if (new_parent && src_is_directory) { |
| 422 | error = xfs_bumplink(tp, target_dp); | 416 | error = xfs_bumplink(tp, target_dp); |
| 423 | if (error) { | 417 | if (error) |
| 424 | goto abort_return; | 418 | goto abort_return; |
| 425 | } | ||
| 426 | } | 419 | } |
| 427 | } else { /* target_ip != NULL */ | 420 | } else { /* target_ip != NULL */ |
| 428 | |||
| 429 | /* | 421 | /* |
| 430 | * If target exists and it's a directory, check that both | 422 | * If target exists and it's a directory, check that both |
| 431 | * target and source are directories and that target can be | 423 | * target and source are directories and that target can be |
| @@ -435,7 +427,7 @@ xfs_rename( | |||
| 435 | /* | 427 | /* |
| 436 | * Make sure target dir is empty. | 428 | * Make sure target dir is empty. |
| 437 | */ | 429 | */ |
| 438 | if (!(XFS_DIR_ISEMPTY(target_ip->i_mount, target_ip)) || | 430 | if (!(xfs_dir_isempty(target_ip)) || |
| 439 | (target_ip->i_d.di_nlink > 2)) { | 431 | (target_ip->i_d.di_nlink > 2)) { |
| 440 | error = XFS_ERROR(EEXIST); | 432 | error = XFS_ERROR(EEXIST); |
| 441 | goto error_return; | 433 | goto error_return; |
| @@ -451,12 +443,11 @@ xfs_rename( | |||
| 451 | * In case there is already an entry with the same | 443 | * In case there is already an entry with the same |
| 452 | * name at the destination directory, remove it first. | 444 | * name at the destination directory, remove it first. |
| 453 | */ | 445 | */ |
| 454 | error = XFS_DIR_REPLACE(mp, tp, target_dp, target_name, | 446 | error = xfs_dir_replace(tp, target_dp, target_name, |
| 455 | target_namelen, src_ip->i_ino, &first_block, | 447 | target_namelen, src_ip->i_ino, |
| 456 | &free_list, spaceres); | 448 | &first_block, &free_list, spaceres); |
| 457 | if (error) { | 449 | if (error) |
| 458 | goto abort_return; | 450 | goto abort_return; |
| 459 | } | ||
| 460 | xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 451 | xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 461 | 452 | ||
| 462 | /* | 453 | /* |
| @@ -464,9 +455,8 @@ xfs_rename( | |||
| 464 | * dir no longer points to it. | 455 | * dir no longer points to it. |
| 465 | */ | 456 | */ |
| 466 | error = xfs_droplink(tp, target_ip); | 457 | error = xfs_droplink(tp, target_ip); |
| 467 | if (error) { | 458 | if (error) |
| 468 | goto abort_return; | 459 | goto abort_return; |
| 469 | } | ||
| 470 | target_ip_dropped = 1; | 460 | target_ip_dropped = 1; |
| 471 | 461 | ||
| 472 | if (src_is_directory) { | 462 | if (src_is_directory) { |
| @@ -474,9 +464,8 @@ xfs_rename( | |||
| 474 | * Drop the link from the old "." entry. | 464 | * Drop the link from the old "." entry. |
| 475 | */ | 465 | */ |
| 476 | error = xfs_droplink(tp, target_ip); | 466 | error = xfs_droplink(tp, target_ip); |
| 477 | if (error) { | 467 | if (error) |
| 478 | goto abort_return; | 468 | goto abort_return; |
| 479 | } | ||
| 480 | } | 469 | } |
| 481 | 470 | ||
| 482 | /* Do this test while we still hold the locks */ | 471 | /* Do this test while we still hold the locks */ |
| @@ -488,18 +477,15 @@ xfs_rename( | |||
| 488 | * Remove the source. | 477 | * Remove the source. |
| 489 | */ | 478 | */ |
| 490 | if (new_parent && src_is_directory) { | 479 | if (new_parent && src_is_directory) { |
| 491 | |||
| 492 | /* | 480 | /* |
| 493 | * Rewrite the ".." entry to point to the new | 481 | * Rewrite the ".." entry to point to the new |
| 494 | * directory. | 482 | * directory. |
| 495 | */ | 483 | */ |
| 496 | error = XFS_DIR_REPLACE(mp, tp, src_ip, "..", 2, | 484 | error = xfs_dir_replace(tp, src_ip, "..", 2, target_dp->i_ino, |
| 497 | target_dp->i_ino, &first_block, | 485 | &first_block, &free_list, spaceres); |
| 498 | &free_list, spaceres); | ||
| 499 | ASSERT(error != EEXIST); | 486 | ASSERT(error != EEXIST); |
| 500 | if (error) { | 487 | if (error) |
| 501 | goto abort_return; | 488 | goto abort_return; |
| 502 | } | ||
| 503 | xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 489 | xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 504 | 490 | ||
| 505 | } else { | 491 | } else { |
| @@ -527,16 +513,14 @@ xfs_rename( | |||
| 527 | * entry that's moved no longer points to it. | 513 | * entry that's moved no longer points to it. |
| 528 | */ | 514 | */ |
| 529 | error = xfs_droplink(tp, src_dp); | 515 | error = xfs_droplink(tp, src_dp); |
| 530 | if (error) { | 516 | if (error) |
| 531 | goto abort_return; | 517 | goto abort_return; |
| 532 | } | ||
| 533 | } | 518 | } |
| 534 | 519 | ||
| 535 | error = XFS_DIR_REMOVENAME(mp, tp, src_dp, src_name, src_namelen, | 520 | error = xfs_dir_removename(tp, src_dp, src_name, src_namelen, |
| 536 | src_ip->i_ino, &first_block, &free_list, spaceres); | 521 | src_ip->i_ino, &first_block, &free_list, spaceres); |
| 537 | if (error) { | 522 | if (error) |
| 538 | goto abort_return; | 523 | goto abort_return; |
| 539 | } | ||
| 540 | xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 524 | xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 541 | 525 | ||
| 542 | /* | 526 | /* |
| @@ -609,7 +593,7 @@ xfs_rename( | |||
| 609 | * Let interposed file systems know about removed links. | 593 | * Let interposed file systems know about removed links. |
| 610 | */ | 594 | */ |
| 611 | if (target_ip_dropped) { | 595 | if (target_ip_dropped) { |
| 612 | VOP_LINK_REMOVED(XFS_ITOV(target_ip), target_dir_vp, | 596 | bhv_vop_link_removed(XFS_ITOV(target_ip), target_dir_vp, |
| 613 | target_link_zero); | 597 | target_link_zero); |
| 614 | IRELE(target_ip); | 598 | IRELE(target_ip); |
| 615 | } | 599 | } |
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 5b413946b1c5..0c1e42b037ef 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -141,7 +139,7 @@ xfs_growfs_rt_alloc( | |||
| 141 | cancelflags |= XFS_TRANS_ABORT; | 139 | cancelflags |= XFS_TRANS_ABORT; |
| 142 | error = xfs_bmapi(tp, ip, oblocks, nblocks - oblocks, | 140 | error = xfs_bmapi(tp, ip, oblocks, nblocks - oblocks, |
| 143 | XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, &firstblock, | 141 | XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, &firstblock, |
| 144 | resblks, &map, &nmap, &flist); | 142 | resblks, &map, &nmap, &flist, NULL); |
| 145 | if (!error && nmap < 1) | 143 | if (!error && nmap < 1) |
| 146 | error = XFS_ERROR(ENOSPC); | 144 | error = XFS_ERROR(ENOSPC); |
| 147 | if (error) | 145 | if (error) |
| @@ -2404,10 +2402,10 @@ xfs_rtprint_range( | |||
| 2404 | { | 2402 | { |
| 2405 | xfs_extlen_t i; /* block number in the extent */ | 2403 | xfs_extlen_t i; /* block number in the extent */ |
| 2406 | 2404 | ||
| 2407 | printk("%Ld: ", (long long)start); | 2405 | cmn_err(CE_DEBUG, "%Ld: ", (long long)start); |
| 2408 | for (i = 0; i < len; i++) | 2406 | for (i = 0; i < len; i++) |
| 2409 | printk("%d", xfs_rtcheck_bit(mp, tp, start + i, 1)); | 2407 | cmn_err(CE_DEBUG, "%d", xfs_rtcheck_bit(mp, tp, start + i, 1)); |
| 2410 | printk("\n"); | 2408 | cmn_err(CE_DEBUG, "\n"); |
| 2411 | } | 2409 | } |
| 2412 | 2410 | ||
| 2413 | /* | 2411 | /* |
| @@ -2431,17 +2429,17 @@ xfs_rtprint_summary( | |||
| 2431 | (void)xfs_rtget_summary(mp, tp, l, i, &sumbp, &sb, &c); | 2429 | (void)xfs_rtget_summary(mp, tp, l, i, &sumbp, &sb, &c); |
| 2432 | if (c) { | 2430 | if (c) { |
| 2433 | if (!p) { | 2431 | if (!p) { |
| 2434 | printk("%Ld-%Ld:", 1LL << l, | 2432 | cmn_err(CE_DEBUG, "%Ld-%Ld:", 1LL << l, |
| 2435 | XFS_RTMIN((1LL << l) + | 2433 | XFS_RTMIN((1LL << l) + |
| 2436 | ((1LL << l) - 1LL), | 2434 | ((1LL << l) - 1LL), |
| 2437 | mp->m_sb.sb_rextents)); | 2435 | mp->m_sb.sb_rextents)); |
| 2438 | p = 1; | 2436 | p = 1; |
| 2439 | } | 2437 | } |
| 2440 | printk(" %Ld:%d", (long long)i, c); | 2438 | cmn_err(CE_DEBUG, " %Ld:%d", (long long)i, c); |
| 2441 | } | 2439 | } |
| 2442 | } | 2440 | } |
| 2443 | if (p) | 2441 | if (p) |
| 2444 | printk("\n"); | 2442 | cmn_err(CE_DEBUG, "\n"); |
| 2445 | } | 2443 | } |
| 2446 | if (sumbp) | 2444 | if (sumbp) |
| 2447 | xfs_trans_brelse(tp, sumbp); | 2445 | xfs_trans_brelse(tp, sumbp); |
diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c index a59c102cf214..defb2febaaf5 100644 --- a/fs/xfs/xfs_rw.c +++ b/fs/xfs/xfs_rw.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -92,6 +90,90 @@ xfs_write_clear_setuid( | |||
| 92 | } | 90 | } |
| 93 | 91 | ||
| 94 | /* | 92 | /* |
| 93 | * Handle logging requirements of various synchronous types of write. | ||
| 94 | */ | ||
| 95 | int | ||
| 96 | xfs_write_sync_logforce( | ||
| 97 | xfs_mount_t *mp, | ||
| 98 | xfs_inode_t *ip) | ||
| 99 | { | ||
| 100 | int error = 0; | ||
| 101 | |||
| 102 | /* | ||
| 103 | * If we're treating this as O_DSYNC and we have not updated the | ||
| 104 | * size, force the log. | ||
| 105 | */ | ||
| 106 | if (!(mp->m_flags & XFS_MOUNT_OSYNCISOSYNC) && | ||
| 107 | !(ip->i_update_size)) { | ||
| 108 | xfs_inode_log_item_t *iip = ip->i_itemp; | ||
| 109 | |||
| 110 | /* | ||
| 111 | * If an allocation transaction occurred | ||
| 112 | * without extending the size, then we have to force | ||
| 113 | * the log up the proper point to ensure that the | ||
| 114 | * allocation is permanent. We can't count on | ||
| 115 | * the fact that buffered writes lock out direct I/O | ||
| 116 | * writes - the direct I/O write could have extended | ||
| 117 | * the size nontransactionally, then finished before | ||
| 118 | * we started. xfs_write_file will think that the file | ||
| 119 | * didn't grow but the update isn't safe unless the | ||
| 120 | * size change is logged. | ||
| 121 | * | ||
| 122 | * Force the log if we've committed a transaction | ||
| 123 | * against the inode or if someone else has and | ||
| 124 | * the commit record hasn't gone to disk (e.g. | ||
| 125 | * the inode is pinned). This guarantees that | ||
| 126 | * all changes affecting the inode are permanent | ||
| 127 | * when we return. | ||
| 128 | */ | ||
| 129 | if (iip && iip->ili_last_lsn) { | ||
| 130 | xfs_log_force(mp, iip->ili_last_lsn, | ||
| 131 | XFS_LOG_FORCE | XFS_LOG_SYNC); | ||
| 132 | } else if (xfs_ipincount(ip) > 0) { | ||
| 133 | xfs_log_force(mp, (xfs_lsn_t)0, | ||
| 134 | XFS_LOG_FORCE | XFS_LOG_SYNC); | ||
| 135 | } | ||
| 136 | |||
| 137 | } else { | ||
| 138 | xfs_trans_t *tp; | ||
| 139 | |||
| 140 | /* | ||
| 141 | * O_SYNC or O_DSYNC _with_ a size update are handled | ||
| 142 | * the same way. | ||
| 143 | * | ||
| 144 | * If the write was synchronous then we need to make | ||
| 145 | * sure that the inode modification time is permanent. | ||
| 146 | * We'll have updated the timestamp above, so here | ||
| 147 | * we use a synchronous transaction to log the inode. | ||
| 148 | * It's not fast, but it's necessary. | ||
| 149 | * | ||
| 150 | * If this a dsync write and the size got changed | ||
| 151 | * non-transactionally, then we need to ensure that | ||
| 152 | * the size change gets logged in a synchronous | ||
| 153 | * transaction. | ||
| 154 | */ | ||
| 155 | tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC); | ||
| 156 | if ((error = xfs_trans_reserve(tp, 0, | ||
| 157 | XFS_SWRITE_LOG_RES(mp), | ||
| 158 | 0, 0, 0))) { | ||
| 159 | /* Transaction reserve failed */ | ||
| 160 | xfs_trans_cancel(tp, 0); | ||
| 161 | } else { | ||
| 162 | /* Transaction reserve successful */ | ||
| 163 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
| 164 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | ||
| 165 | xfs_trans_ihold(tp, ip); | ||
| 166 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
| 167 | xfs_trans_set_sync(tp); | ||
| 168 | error = xfs_trans_commit(tp, 0, NULL); | ||
| 169 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | return error; | ||
| 174 | } | ||
| 175 | |||
| 176 | /* | ||
| 95 | * Force a shutdown of the filesystem instantly while keeping | 177 | * Force a shutdown of the filesystem instantly while keeping |
| 96 | * the filesystem consistent. We don't do an unmount here; just shutdown | 178 | * the filesystem consistent. We don't do an unmount here; just shutdown |
| 97 | * the shop, make sure that absolutely nothing persistent happens to | 179 | * the shop, make sure that absolutely nothing persistent happens to |
| @@ -109,12 +191,12 @@ xfs_do_force_shutdown( | |||
| 109 | xfs_mount_t *mp; | 191 | xfs_mount_t *mp; |
| 110 | 192 | ||
| 111 | mp = XFS_BHVTOM(bdp); | 193 | mp = XFS_BHVTOM(bdp); |
| 112 | logerror = flags & XFS_LOG_IO_ERROR; | 194 | logerror = flags & SHUTDOWN_LOG_IO_ERROR; |
| 113 | 195 | ||
| 114 | if (!(flags & XFS_FORCE_UMOUNT)) { | 196 | if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { |
| 115 | cmn_err(CE_NOTE, | 197 | cmn_err(CE_NOTE, "xfs_force_shutdown(%s,0x%x) called from " |
| 116 | "xfs_force_shutdown(%s,0x%x) called from line %d of file %s. Return address = 0x%p", | 198 | "line %d of file %s. Return address = 0x%p", |
| 117 | mp->m_fsname,flags,lnnum,fname,__return_address); | 199 | mp->m_fsname, flags, lnnum, fname, __return_address); |
| 118 | } | 200 | } |
| 119 | /* | 201 | /* |
| 120 | * No need to duplicate efforts. | 202 | * No need to duplicate efforts. |
| @@ -125,33 +207,37 @@ xfs_do_force_shutdown( | |||
| 125 | /* | 207 | /* |
| 126 | * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't | 208 | * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't |
| 127 | * queue up anybody new on the log reservations, and wakes up | 209 | * queue up anybody new on the log reservations, and wakes up |
| 128 | * everybody who's sleeping on log reservations and tells | 210 | * everybody who's sleeping on log reservations to tell them |
| 129 | * them the bad news. | 211 | * the bad news. |
| 130 | */ | 212 | */ |
| 131 | if (xfs_log_force_umount(mp, logerror)) | 213 | if (xfs_log_force_umount(mp, logerror)) |
| 132 | return; | 214 | return; |
| 133 | 215 | ||
| 134 | if (flags & XFS_CORRUPT_INCORE) { | 216 | if (flags & SHUTDOWN_CORRUPT_INCORE) { |
| 135 | xfs_cmn_err(XFS_PTAG_SHUTDOWN_CORRUPT, CE_ALERT, mp, | 217 | xfs_cmn_err(XFS_PTAG_SHUTDOWN_CORRUPT, CE_ALERT, mp, |
| 136 | "Corruption of in-memory data detected. Shutting down filesystem: %s", | 218 | "Corruption of in-memory data detected. Shutting down filesystem: %s", |
| 137 | mp->m_fsname); | 219 | mp->m_fsname); |
| 138 | if (XFS_ERRLEVEL_HIGH <= xfs_error_level) { | 220 | if (XFS_ERRLEVEL_HIGH <= xfs_error_level) { |
| 139 | xfs_stack_trace(); | 221 | xfs_stack_trace(); |
| 140 | } | 222 | } |
| 141 | } else if (!(flags & XFS_FORCE_UMOUNT)) { | 223 | } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { |
| 142 | if (logerror) { | 224 | if (logerror) { |
| 143 | xfs_cmn_err(XFS_PTAG_SHUTDOWN_LOGERROR, CE_ALERT, mp, | 225 | xfs_cmn_err(XFS_PTAG_SHUTDOWN_LOGERROR, CE_ALERT, mp, |
| 144 | "Log I/O Error Detected. Shutting down filesystem: %s", | 226 | "Log I/O Error Detected. Shutting down filesystem: %s", |
| 227 | mp->m_fsname); | ||
| 228 | } else if (flags & SHUTDOWN_DEVICE_REQ) { | ||
| 229 | xfs_cmn_err(XFS_PTAG_SHUTDOWN_IOERROR, CE_ALERT, mp, | ||
| 230 | "All device paths lost. Shutting down filesystem: %s", | ||
| 145 | mp->m_fsname); | 231 | mp->m_fsname); |
| 146 | } else if (!(flags & XFS_SHUTDOWN_REMOTE_REQ)) { | 232 | } else if (!(flags & SHUTDOWN_REMOTE_REQ)) { |
| 147 | xfs_cmn_err(XFS_PTAG_SHUTDOWN_IOERROR, CE_ALERT, mp, | 233 | xfs_cmn_err(XFS_PTAG_SHUTDOWN_IOERROR, CE_ALERT, mp, |
| 148 | "I/O Error Detected. Shutting down filesystem: %s", | 234 | "I/O Error Detected. Shutting down filesystem: %s", |
| 149 | mp->m_fsname); | 235 | mp->m_fsname); |
| 150 | } | 236 | } |
| 151 | } | 237 | } |
| 152 | if (!(flags & XFS_FORCE_UMOUNT)) { | 238 | if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { |
| 153 | cmn_err(CE_ALERT, | 239 | cmn_err(CE_ALERT, "Please umount the filesystem, " |
| 154 | "Please umount the filesystem, and rectify the problem(s)"); | 240 | "and rectify the problem(s)"); |
| 155 | } | 241 | } |
| 156 | } | 242 | } |
| 157 | 243 | ||
| @@ -335,7 +421,7 @@ xfs_bwrite( | |||
| 335 | * from bwrite and we could be tracing a buffer that has | 421 | * from bwrite and we could be tracing a buffer that has |
| 336 | * been reused. | 422 | * been reused. |
| 337 | */ | 423 | */ |
| 338 | xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); | 424 | xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); |
| 339 | } | 425 | } |
| 340 | return (error); | 426 | return (error); |
| 341 | } | 427 | } |
diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h index e63795644478..188b296ff50c 100644 --- a/fs/xfs/xfs_rw.h +++ b/fs/xfs/xfs_rw.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -75,6 +75,7 @@ xfs_fsb_to_db_io(struct xfs_iocore *io, xfs_fsblock_t fsb) | |||
| 75 | * Prototypes for functions in xfs_rw.c. | 75 | * Prototypes for functions in xfs_rw.c. |
| 76 | */ | 76 | */ |
| 77 | extern int xfs_write_clear_setuid(struct xfs_inode *ip); | 77 | extern int xfs_write_clear_setuid(struct xfs_inode *ip); |
| 78 | extern int xfs_write_sync_logforce(struct xfs_mount *mp, struct xfs_inode *ip); | ||
| 78 | extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp); | 79 | extern int xfs_bwrite(struct xfs_mount *mp, struct xfs_buf *bp); |
| 79 | extern int xfs_bioerror(struct xfs_buf *bp); | 80 | extern int xfs_bioerror(struct xfs_buf *bp); |
| 80 | extern int xfs_bioerror_relse(struct xfs_buf *bp); | 81 | extern int xfs_bioerror_relse(struct xfs_buf *bp); |
| @@ -87,9 +88,10 @@ extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp, | |||
| 87 | /* | 88 | /* |
| 88 | * Prototypes for functions in xfs_vnodeops.c. | 89 | * Prototypes for functions in xfs_vnodeops.c. |
| 89 | */ | 90 | */ |
| 90 | extern int xfs_rwlock(bhv_desc_t *bdp, vrwlock_t write_lock); | 91 | extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock); |
| 91 | extern void xfs_rwunlock(bhv_desc_t *bdp, vrwlock_t write_lock); | 92 | extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock); |
| 92 | extern int xfs_setattr(bhv_desc_t *bdp, vattr_t *vap, int flags, cred_t *credp); | 93 | extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags, |
| 94 | cred_t *credp); | ||
| 93 | extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf, | 95 | extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf, |
| 94 | xfs_off_t offset, cred_t *credp, int flags); | 96 | xfs_off_t offset, cred_t *credp, int flags); |
| 95 | extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state, | 97 | extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state, |
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 8d056cef5d1f..ee2721e0de4d 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| @@ -33,7 +32,6 @@ | |||
| 33 | #include "xfs_bmap_btree.h" | 32 | #include "xfs_bmap_btree.h" |
| 34 | #include "xfs_alloc_btree.h" | 33 | #include "xfs_alloc_btree.h" |
| 35 | #include "xfs_ialloc_btree.h" | 34 | #include "xfs_ialloc_btree.h" |
| 36 | #include "xfs_dir_sf.h" | ||
| 37 | #include "xfs_dir2_sf.h" | 35 | #include "xfs_dir2_sf.h" |
| 38 | #include "xfs_attr_sf.h" | 36 | #include "xfs_attr_sf.h" |
| 39 | #include "xfs_dinode.h" | 37 | #include "xfs_dinode.h" |
| @@ -236,11 +234,8 @@ xfs_trans_alloc( | |||
| 236 | xfs_mount_t *mp, | 234 | xfs_mount_t *mp, |
| 237 | uint type) | 235 | uint type) |
| 238 | { | 236 | { |
| 239 | fs_check_frozen(XFS_MTOVFS(mp), SB_FREEZE_TRANS); | 237 | vfs_wait_for_freeze(XFS_MTOVFS(mp), SB_FREEZE_TRANS); |
| 240 | atomic_inc(&mp->m_active_trans); | 238 | return _xfs_trans_alloc(mp, type); |
| 241 | |||
| 242 | return (_xfs_trans_alloc(mp, type)); | ||
| 243 | |||
| 244 | } | 239 | } |
| 245 | 240 | ||
| 246 | xfs_trans_t * | 241 | xfs_trans_t * |
| @@ -250,12 +245,9 @@ _xfs_trans_alloc( | |||
| 250 | { | 245 | { |
| 251 | xfs_trans_t *tp; | 246 | xfs_trans_t *tp; |
| 252 | 247 | ||
| 253 | ASSERT(xfs_trans_zone != NULL); | 248 | atomic_inc(&mp->m_active_trans); |
| 254 | tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); | ||
| 255 | 249 | ||
| 256 | /* | 250 | tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); |
| 257 | * Initialize the transaction structure. | ||
| 258 | */ | ||
| 259 | tp->t_magic = XFS_TRANS_MAGIC; | 251 | tp->t_magic = XFS_TRANS_MAGIC; |
| 260 | tp->t_type = type; | 252 | tp->t_type = type; |
| 261 | tp->t_mountp = mp; | 253 | tp->t_mountp = mp; |
| @@ -263,8 +255,7 @@ _xfs_trans_alloc( | |||
| 263 | tp->t_busy_free = XFS_LBC_NUM_SLOTS; | 255 | tp->t_busy_free = XFS_LBC_NUM_SLOTS; |
| 264 | XFS_LIC_INIT(&(tp->t_items)); | 256 | XFS_LIC_INIT(&(tp->t_items)); |
| 265 | XFS_LBC_INIT(&(tp->t_busy)); | 257 | XFS_LBC_INIT(&(tp->t_busy)); |
| 266 | 258 | return tp; | |
| 267 | return (tp); | ||
| 268 | } | 259 | } |
| 269 | 260 | ||
| 270 | /* | 261 | /* |
| @@ -303,7 +294,7 @@ xfs_trans_dup( | |||
| 303 | tp->t_blk_res = tp->t_blk_res_used; | 294 | tp->t_blk_res = tp->t_blk_res_used; |
| 304 | ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; | 295 | ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; |
| 305 | tp->t_rtx_res = tp->t_rtx_res_used; | 296 | tp->t_rtx_res = tp->t_rtx_res_used; |
| 306 | PFLAGS_DUP(&tp->t_pflags, &ntp->t_pflags); | 297 | ntp->t_pflags = tp->t_pflags; |
| 307 | 298 | ||
| 308 | XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp); | 299 | XFS_TRANS_DUP_DQINFO(tp->t_mountp, tp, ntp); |
| 309 | 300 | ||
| @@ -335,14 +326,11 @@ xfs_trans_reserve( | |||
| 335 | uint logcount) | 326 | uint logcount) |
| 336 | { | 327 | { |
| 337 | int log_flags; | 328 | int log_flags; |
| 338 | int error; | 329 | int error = 0; |
| 339 | int rsvd; | 330 | int rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; |
| 340 | |||
| 341 | error = 0; | ||
| 342 | rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; | ||
| 343 | 331 | ||
| 344 | /* Mark this thread as being in a transaction */ | 332 | /* Mark this thread as being in a transaction */ |
| 345 | PFLAGS_SET_FSTRANS(&tp->t_pflags); | 333 | current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); |
| 346 | 334 | ||
| 347 | /* | 335 | /* |
| 348 | * Attempt to reserve the needed disk blocks by decrementing | 336 | * Attempt to reserve the needed disk blocks by decrementing |
| @@ -353,7 +341,7 @@ xfs_trans_reserve( | |||
| 353 | error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, | 341 | error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, |
| 354 | -blocks, rsvd); | 342 | -blocks, rsvd); |
| 355 | if (error != 0) { | 343 | if (error != 0) { |
| 356 | PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); | 344 | current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); |
| 357 | return (XFS_ERROR(ENOSPC)); | 345 | return (XFS_ERROR(ENOSPC)); |
| 358 | } | 346 | } |
| 359 | tp->t_blk_res += blocks; | 347 | tp->t_blk_res += blocks; |
| @@ -426,9 +414,9 @@ undo_blocks: | |||
| 426 | tp->t_blk_res = 0; | 414 | tp->t_blk_res = 0; |
| 427 | } | 415 | } |
| 428 | 416 | ||
| 429 | PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); | 417 | current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); |
| 430 | 418 | ||
| 431 | return (error); | 419 | return error; |
| 432 | } | 420 | } |
| 433 | 421 | ||
| 434 | 422 | ||
| @@ -819,7 +807,7 @@ shut_us_down: | |||
| 819 | if (commit_lsn == -1 && !shutdown) | 807 | if (commit_lsn == -1 && !shutdown) |
| 820 | shutdown = XFS_ERROR(EIO); | 808 | shutdown = XFS_ERROR(EIO); |
| 821 | } | 809 | } |
| 822 | PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); | 810 | current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); |
| 823 | xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0); | 811 | xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0); |
| 824 | xfs_trans_free_busy(tp); | 812 | xfs_trans_free_busy(tp); |
| 825 | xfs_trans_free(tp); | 813 | xfs_trans_free(tp); |
| @@ -846,7 +834,7 @@ shut_us_down: | |||
| 846 | */ | 834 | */ |
| 847 | nvec = xfs_trans_count_vecs(tp); | 835 | nvec = xfs_trans_count_vecs(tp); |
| 848 | if (nvec == 0) { | 836 | if (nvec == 0) { |
| 849 | xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); | 837 | xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); |
| 850 | goto shut_us_down; | 838 | goto shut_us_down; |
| 851 | } else if (nvec <= XFS_TRANS_LOGVEC_COUNT) { | 839 | } else if (nvec <= XFS_TRANS_LOGVEC_COUNT) { |
| 852 | log_vector = log_vector_fast; | 840 | log_vector = log_vector_fast; |
| @@ -884,7 +872,7 @@ shut_us_down: | |||
| 884 | * had pinned, clean up, free trans structure, and return error. | 872 | * had pinned, clean up, free trans structure, and return error. |
| 885 | */ | 873 | */ |
| 886 | if (error || commit_lsn == -1) { | 874 | if (error || commit_lsn == -1) { |
| 887 | PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); | 875 | current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); |
| 888 | xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT); | 876 | xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT); |
| 889 | return XFS_ERROR(EIO); | 877 | return XFS_ERROR(EIO); |
| 890 | } | 878 | } |
| @@ -926,7 +914,7 @@ shut_us_down: | |||
| 926 | /* | 914 | /* |
| 927 | * Mark this thread as no longer being in a transaction | 915 | * Mark this thread as no longer being in a transaction |
| 928 | */ | 916 | */ |
| 929 | PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); | 917 | current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); |
| 930 | 918 | ||
| 931 | /* | 919 | /* |
| 932 | * Once all the items of the transaction have been copied | 920 | * Once all the items of the transaction have been copied |
| @@ -1148,7 +1136,7 @@ xfs_trans_cancel( | |||
| 1148 | */ | 1136 | */ |
| 1149 | if ((tp->t_flags & XFS_TRANS_DIRTY) && !XFS_FORCED_SHUTDOWN(mp)) { | 1137 | if ((tp->t_flags & XFS_TRANS_DIRTY) && !XFS_FORCED_SHUTDOWN(mp)) { |
| 1150 | XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp); | 1138 | XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp); |
| 1151 | xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); | 1139 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); |
| 1152 | } | 1140 | } |
| 1153 | #ifdef DEBUG | 1141 | #ifdef DEBUG |
| 1154 | if (!(flags & XFS_TRANS_ABORT)) { | 1142 | if (!(flags & XFS_TRANS_ABORT)) { |
| @@ -1182,7 +1170,7 @@ xfs_trans_cancel( | |||
| 1182 | } | 1170 | } |
| 1183 | 1171 | ||
| 1184 | /* mark this thread as no longer being in a transaction */ | 1172 | /* mark this thread as no longer being in a transaction */ |
| 1185 | PFLAGS_RESTORE_FSTRANS(&tp->t_pflags); | 1173 | current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); |
| 1186 | 1174 | ||
| 1187 | xfs_trans_free_items(tp, flags); | 1175 | xfs_trans_free_items(tp, flags); |
| 1188 | xfs_trans_free_busy(tp); | 1176 | xfs_trans_free_busy(tp); |
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 100d9a4b38ee..cb65c3a603f5 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h | |||
| @@ -805,12 +805,9 @@ typedef struct xfs_trans { | |||
| 805 | ((mp)->m_sb.sb_inodesize + \ | 805 | ((mp)->m_sb.sb_inodesize + \ |
| 806 | (mp)->m_sb.sb_sectsize * 2 + \ | 806 | (mp)->m_sb.sb_sectsize * 2 + \ |
| 807 | (mp)->m_dirblksize + \ | 807 | (mp)->m_dirblksize + \ |
| 808 | (XFS_DIR_IS_V1(mp) ? 0 : \ | 808 | XFS_FSB_TO_B(mp, (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1)) + \ |
| 809 | XFS_FSB_TO_B(mp, (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1))) + \ | ||
| 810 | XFS_ALLOCFREE_LOG_RES(mp, 1) + \ | 809 | XFS_ALLOCFREE_LOG_RES(mp, 1) + \ |
| 811 | (128 * (4 + \ | 810 | (128 * (4 + (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) + \ |
| 812 | (XFS_DIR_IS_V1(mp) ? 0 : \ | ||
| 813 | XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) + \ | ||
| 814 | XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) | 811 | XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) |
| 815 | 812 | ||
| 816 | #define XFS_ADDAFORK_LOG_RES(mp) ((mp)->m_reservations.tr_addafork) | 813 | #define XFS_ADDAFORK_LOG_RES(mp) ((mp)->m_reservations.tr_addafork) |
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index 19ab24af1c1c..558c87ff0c41 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c | |||
| @@ -22,7 +22,6 @@ | |||
| 22 | #include "xfs_inum.h" | 22 | #include "xfs_inum.h" |
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_dir.h" | ||
| 26 | #include "xfs_dmapi.h" | 25 | #include "xfs_dmapi.h" |
| 27 | #include "xfs_mount.h" | 26 | #include "xfs_mount.h" |
| 28 | #include "xfs_trans_priv.h" | 27 | #include "xfs_trans_priv.h" |
| @@ -363,9 +362,10 @@ xfs_trans_delete_ail( | |||
| 363 | AIL_UNLOCK(mp, s); | 362 | AIL_UNLOCK(mp, s); |
| 364 | else { | 363 | else { |
| 365 | xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp, | 364 | xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp, |
| 366 | "xfs_trans_delete_ail: attempting to delete a log item that is not in the AIL"); | 365 | "%s: attempting to delete a log item that is not in the AIL", |
| 366 | __FUNCTION__); | ||
| 367 | AIL_UNLOCK(mp, s); | 367 | AIL_UNLOCK(mp, s); |
| 368 | xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); | 368 | xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); |
| 369 | } | 369 | } |
| 370 | } | 370 | } |
| 371 | } | 371 | } |
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index c74c31ebc81c..60b6b898022b 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
| @@ -320,7 +318,7 @@ xfs_trans_read_buf( | |||
| 320 | if (xfs_error_target == target) { | 318 | if (xfs_error_target == target) { |
| 321 | if (((xfs_req_num++) % xfs_error_mod) == 0) { | 319 | if (((xfs_req_num++) % xfs_error_mod) == 0) { |
| 322 | xfs_buf_relse(bp); | 320 | xfs_buf_relse(bp); |
| 323 | printk("Returning error!\n"); | 321 | cmn_err(CE_DEBUG, "Returning error!\n"); |
| 324 | return XFS_ERROR(EIO); | 322 | return XFS_ERROR(EIO); |
| 325 | } | 323 | } |
| 326 | } | 324 | } |
| @@ -369,7 +367,7 @@ xfs_trans_read_buf( | |||
| 369 | */ | 367 | */ |
| 370 | if (tp->t_flags & XFS_TRANS_DIRTY) | 368 | if (tp->t_flags & XFS_TRANS_DIRTY) |
| 371 | xfs_force_shutdown(tp->t_mountp, | 369 | xfs_force_shutdown(tp->t_mountp, |
| 372 | XFS_METADATA_IO_ERROR); | 370 | SHUTDOWN_META_IO_ERROR); |
| 373 | return error; | 371 | return error; |
| 374 | } | 372 | } |
| 375 | } | 373 | } |
| @@ -414,7 +412,7 @@ xfs_trans_read_buf( | |||
| 414 | xfs_ioerror_alert("xfs_trans_read_buf", mp, | 412 | xfs_ioerror_alert("xfs_trans_read_buf", mp, |
| 415 | bp, blkno); | 413 | bp, blkno); |
| 416 | if (tp->t_flags & XFS_TRANS_DIRTY) | 414 | if (tp->t_flags & XFS_TRANS_DIRTY) |
| 417 | xfs_force_shutdown(tp->t_mountp, XFS_METADATA_IO_ERROR); | 415 | xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR); |
| 418 | xfs_buf_relse(bp); | 416 | xfs_buf_relse(bp); |
| 419 | return error; | 417 | return error; |
| 420 | } | 418 | } |
| @@ -423,9 +421,9 @@ xfs_trans_read_buf( | |||
| 423 | if (xfs_error_target == target) { | 421 | if (xfs_error_target == target) { |
| 424 | if (((xfs_req_num++) % xfs_error_mod) == 0) { | 422 | if (((xfs_req_num++) % xfs_error_mod) == 0) { |
| 425 | xfs_force_shutdown(tp->t_mountp, | 423 | xfs_force_shutdown(tp->t_mountp, |
| 426 | XFS_METADATA_IO_ERROR); | 424 | SHUTDOWN_META_IO_ERROR); |
| 427 | xfs_buf_relse(bp); | 425 | xfs_buf_relse(bp); |
| 428 | printk("Returning error in trans!\n"); | 426 | cmn_err(CE_DEBUG, "Returning trans error!\n"); |
| 429 | return XFS_ERROR(EIO); | 427 | return XFS_ERROR(EIO); |
| 430 | } | 428 | } |
| 431 | } | 429 | } |
diff --git a/fs/xfs/xfs_trans_extfree.c b/fs/xfs/xfs_trans_extfree.c index 7d7d627f25df..b290270dd4a6 100644 --- a/fs/xfs/xfs_trans_extfree.c +++ b/fs/xfs/xfs_trans_extfree.c | |||
| @@ -22,7 +22,6 @@ | |||
| 22 | #include "xfs_inum.h" | 22 | #include "xfs_inum.h" |
| 23 | #include "xfs_trans.h" | 23 | #include "xfs_trans.h" |
| 24 | #include "xfs_sb.h" | 24 | #include "xfs_sb.h" |
| 25 | #include "xfs_dir.h" | ||
| 26 | #include "xfs_dmapi.h" | 25 | #include "xfs_dmapi.h" |
| 27 | #include "xfs_mount.h" | 26 | #include "xfs_mount.h" |
| 28 | #include "xfs_trans_priv.h" | 27 | #include "xfs_trans_priv.h" |
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c index 7c5894d59f81..b8db1d5cde5a 100644 --- a/fs/xfs/xfs_trans_inode.c +++ b/fs/xfs/xfs_trans_inode.c | |||
| @@ -24,14 +24,12 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_alloc_btree.h" | 31 | #include "xfs_alloc_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_dir_sf.h" | ||
| 35 | #include "xfs_dir2_sf.h" | 33 | #include "xfs_dir2_sf.h" |
| 36 | #include "xfs_attr_sf.h" | 34 | #include "xfs_attr_sf.h" |
| 37 | #include "xfs_dinode.h" | 35 | #include "xfs_dinode.h" |
diff --git a/fs/xfs/xfs_trans_item.c b/fs/xfs/xfs_trans_item.c index 1117d600d741..2912aac07c7b 100644 --- a/fs/xfs/xfs_trans_item.c +++ b/fs/xfs/xfs_trans_item.c | |||
| @@ -493,7 +493,7 @@ xfs_trans_add_busy(xfs_trans_t *tp, xfs_agnumber_t ag, xfs_extlen_t idx) | |||
| 493 | break; | 493 | break; |
| 494 | } else { | 494 | } else { |
| 495 | /* out-of-order vacancy */ | 495 | /* out-of-order vacancy */ |
| 496 | printk("OOO vacancy lbcp 0x%p\n", lbcp); | 496 | cmn_err(CE_DEBUG, "OOO vacancy lbcp 0x%p\n", lbcp); |
| 497 | ASSERT(0); | 497 | ASSERT(0); |
| 498 | } | 498 | } |
| 499 | } | 499 | } |
diff --git a/fs/xfs/xfs_trans_space.h b/fs/xfs/xfs_trans_space.h index 7fe3792b18df..4ea2e5074bdd 100644 --- a/fs/xfs/xfs_trans_space.h +++ b/fs/xfs/xfs_trans_space.h | |||
| @@ -30,8 +30,7 @@ | |||
| 30 | XFS_EXTENTADD_SPACE_RES(mp,w)) | 30 | XFS_EXTENTADD_SPACE_RES(mp,w)) |
| 31 | #define XFS_DAENTER_1B(mp,w) ((w) == XFS_DATA_FORK ? (mp)->m_dirblkfsbs : 1) | 31 | #define XFS_DAENTER_1B(mp,w) ((w) == XFS_DATA_FORK ? (mp)->m_dirblkfsbs : 1) |
| 32 | #define XFS_DAENTER_DBS(mp,w) \ | 32 | #define XFS_DAENTER_DBS(mp,w) \ |
| 33 | (XFS_DA_NODE_MAXDEPTH + \ | 33 | (XFS_DA_NODE_MAXDEPTH + (((w) == XFS_DATA_FORK) ? 2 : 0)) |
| 34 | ((XFS_DIR_IS_V2(mp) && (w) == XFS_DATA_FORK) ? 2 : 0)) | ||
| 35 | #define XFS_DAENTER_BLOCKS(mp,w) \ | 34 | #define XFS_DAENTER_BLOCKS(mp,w) \ |
| 36 | (XFS_DAENTER_1B(mp,w) * XFS_DAENTER_DBS(mp,w)) | 35 | (XFS_DAENTER_1B(mp,w) * XFS_DAENTER_DBS(mp,w)) |
| 37 | #define XFS_DAENTER_BMAP1B(mp,w) \ | 36 | #define XFS_DAENTER_BMAP1B(mp,w) \ |
| @@ -41,10 +40,7 @@ | |||
| 41 | #define XFS_DAENTER_SPACE_RES(mp,w) \ | 40 | #define XFS_DAENTER_SPACE_RES(mp,w) \ |
| 42 | (XFS_DAENTER_BLOCKS(mp,w) + XFS_DAENTER_BMAPS(mp,w)) | 41 | (XFS_DAENTER_BLOCKS(mp,w) + XFS_DAENTER_BMAPS(mp,w)) |
| 43 | #define XFS_DAREMOVE_SPACE_RES(mp,w) XFS_DAENTER_BMAPS(mp,w) | 42 | #define XFS_DAREMOVE_SPACE_RES(mp,w) XFS_DAENTER_BMAPS(mp,w) |
| 44 | #define XFS_DIRENTER_MAX_SPLIT(mp,nl) \ | 43 | #define XFS_DIRENTER_MAX_SPLIT(mp,nl) 1 |
| 45 | (((mp)->m_sb.sb_blocksize == 512 && \ | ||
| 46 | XFS_DIR_IS_V1(mp) && \ | ||
| 47 | (nl) >= XFS_DIR_LEAF_CAN_DOUBLE_SPLIT_LEN) ? 2 : 1) | ||
| 48 | #define XFS_DIRENTER_SPACE_RES(mp,nl) \ | 44 | #define XFS_DIRENTER_SPACE_RES(mp,nl) \ |
| 49 | (XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK) * \ | 45 | (XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK) * \ |
| 50 | XFS_DIRENTER_MAX_SPLIT(mp,nl)) | 46 | XFS_DIRENTER_MAX_SPLIT(mp,nl)) |
| @@ -57,8 +53,7 @@ | |||
| 57 | * Space reservation values for various transactions. | 53 | * Space reservation values for various transactions. |
| 58 | */ | 54 | */ |
| 59 | #define XFS_ADDAFORK_SPACE_RES(mp) \ | 55 | #define XFS_ADDAFORK_SPACE_RES(mp) \ |
| 60 | ((mp)->m_dirblkfsbs + \ | 56 | ((mp)->m_dirblkfsbs + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK)) |
| 61 | (XFS_DIR_IS_V1(mp) ? 0 : XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK))) | ||
| 62 | #define XFS_ATTRRM_SPACE_RES(mp) \ | 57 | #define XFS_ATTRRM_SPACE_RES(mp) \ |
| 63 | XFS_DAREMOVE_SPACE_RES(mp, XFS_ATTR_FORK) | 58 | XFS_DAREMOVE_SPACE_RES(mp, XFS_ATTR_FORK) |
| 64 | /* This macro is not used - see inline code in xfs_attr_set */ | 59 | /* This macro is not used - see inline code in xfs_attr_set */ |
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c index 34654ec6ae10..9014d7e44488 100644 --- a/fs/xfs/xfs_utils.c +++ b/fs/xfs/xfs_utils.c | |||
| @@ -24,12 +24,10 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| 31 | #include "xfs_bmap_btree.h" | 30 | #include "xfs_bmap_btree.h" |
| 32 | #include "xfs_dir_sf.h" | ||
| 33 | #include "xfs_dir2_sf.h" | 31 | #include "xfs_dir2_sf.h" |
| 34 | #include "xfs_attr_sf.h" | 32 | #include "xfs_attr_sf.h" |
| 35 | #include "xfs_dinode.h" | 33 | #include "xfs_dinode.h" |
| @@ -51,10 +49,10 @@ | |||
| 51 | */ | 49 | */ |
| 52 | int | 50 | int |
| 53 | xfs_get_dir_entry( | 51 | xfs_get_dir_entry( |
| 54 | vname_t *dentry, | 52 | bhv_vname_t *dentry, |
| 55 | xfs_inode_t **ipp) | 53 | xfs_inode_t **ipp) |
| 56 | { | 54 | { |
| 57 | vnode_t *vp; | 55 | bhv_vnode_t *vp; |
| 58 | 56 | ||
| 59 | vp = VNAME_TO_VNODE(dentry); | 57 | vp = VNAME_TO_VNODE(dentry); |
| 60 | 58 | ||
| @@ -69,11 +67,11 @@ int | |||
| 69 | xfs_dir_lookup_int( | 67 | xfs_dir_lookup_int( |
| 70 | bhv_desc_t *dir_bdp, | 68 | bhv_desc_t *dir_bdp, |
| 71 | uint lock_mode, | 69 | uint lock_mode, |
| 72 | vname_t *dentry, | 70 | bhv_vname_t *dentry, |
| 73 | xfs_ino_t *inum, | 71 | xfs_ino_t *inum, |
| 74 | xfs_inode_t **ipp) | 72 | xfs_inode_t **ipp) |
| 75 | { | 73 | { |
| 76 | vnode_t *dir_vp; | 74 | bhv_vnode_t *dir_vp; |
| 77 | xfs_inode_t *dp; | 75 | xfs_inode_t *dp; |
| 78 | int error; | 76 | int error; |
| 79 | 77 | ||
| @@ -82,8 +80,7 @@ xfs_dir_lookup_int( | |||
| 82 | 80 | ||
| 83 | dp = XFS_BHVTOI(dir_bdp); | 81 | dp = XFS_BHVTOI(dir_bdp); |
| 84 | 82 | ||
| 85 | error = XFS_DIR_LOOKUP(dp->i_mount, NULL, dp, | 83 | error = xfs_dir_lookup(NULL, dp, VNAME(dentry), VNAMELEN(dentry), inum); |
| 86 | VNAME(dentry), VNAMELEN(dentry), inum); | ||
| 87 | if (!error) { | 84 | if (!error) { |
| 88 | /* | 85 | /* |
| 89 | * Unlock the directory. We do this because we can't | 86 | * Unlock the directory. We do this because we can't |
diff --git a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h index 472661a3b6d8..fe953e98afa7 100644 --- a/fs/xfs/xfs_utils.h +++ b/fs/xfs/xfs_utils.h | |||
| @@ -23,9 +23,10 @@ | |||
| 23 | #define ITRACE(ip) vn_trace_ref(XFS_ITOV(ip), __FILE__, __LINE__, \ | 23 | #define ITRACE(ip) vn_trace_ref(XFS_ITOV(ip), __FILE__, __LINE__, \ |
| 24 | (inst_t *)__return_address) | 24 | (inst_t *)__return_address) |
| 25 | 25 | ||
| 26 | extern int xfs_rename (bhv_desc_t *, vname_t *, vnode_t *, vname_t *, cred_t *); | 26 | extern int xfs_rename (bhv_desc_t *, bhv_vname_t *, bhv_vnode_t *, |
| 27 | extern int xfs_get_dir_entry (vname_t *, xfs_inode_t **); | 27 | bhv_vname_t *, cred_t *); |
| 28 | extern int xfs_dir_lookup_int (bhv_desc_t *, uint, vname_t *, xfs_ino_t *, | 28 | extern int xfs_get_dir_entry (bhv_vname_t *, xfs_inode_t **); |
| 29 | extern int xfs_dir_lookup_int (bhv_desc_t *, uint, bhv_vname_t *, xfs_ino_t *, | ||
| 29 | xfs_inode_t **); | 30 | xfs_inode_t **); |
| 30 | extern int xfs_truncate_file (xfs_mount_t *, xfs_inode_t *); | 31 | extern int xfs_truncate_file (xfs_mount_t *, xfs_inode_t *); |
| 31 | extern int xfs_dir_ialloc (xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t, | 32 | extern int xfs_dir_ialloc (xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t, |
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index 36ea1b2094f2..6c96391f3f1a 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include "xfs_trans.h" | 24 | #include "xfs_trans.h" |
| 25 | #include "xfs_sb.h" | 25 | #include "xfs_sb.h" |
| 26 | #include "xfs_ag.h" | 26 | #include "xfs_ag.h" |
| 27 | #include "xfs_dir.h" | ||
| 28 | #include "xfs_dir2.h" | 27 | #include "xfs_dir2.h" |
| 29 | #include "xfs_dmapi.h" | 28 | #include "xfs_dmapi.h" |
| 30 | #include "xfs_mount.h" | 29 | #include "xfs_mount.h" |
| @@ -32,7 +31,6 @@ | |||
| 32 | #include "xfs_bmap_btree.h" | 31 | #include "xfs_bmap_btree.h" |
| 33 | #include "xfs_ialloc_btree.h" | 32 | #include "xfs_ialloc_btree.h" |
| 34 | #include "xfs_alloc_btree.h" | 33 | #include "xfs_alloc_btree.h" |
| 35 | #include "xfs_dir_sf.h" | ||
| 36 | #include "xfs_dir2_sf.h" | 34 | #include "xfs_dir2_sf.h" |
| 37 | #include "xfs_attr_sf.h" | 35 | #include "xfs_attr_sf.h" |
| 38 | #include "xfs_dinode.h" | 36 | #include "xfs_dinode.h" |
| @@ -131,9 +129,6 @@ xfs_init(void) | |||
| 131 | #ifdef XFS_BMBT_TRACE | 129 | #ifdef XFS_BMBT_TRACE |
| 132 | xfs_bmbt_trace_buf = ktrace_alloc(XFS_BMBT_TRACE_SIZE, KM_SLEEP); | 130 | xfs_bmbt_trace_buf = ktrace_alloc(XFS_BMBT_TRACE_SIZE, KM_SLEEP); |
| 133 | #endif | 131 | #endif |
| 134 | #ifdef XFS_DIR_TRACE | ||
| 135 | xfs_dir_trace_buf = ktrace_alloc(XFS_DIR_TRACE_SIZE, KM_SLEEP); | ||
| 136 | #endif | ||
| 137 | #ifdef XFS_ATTR_TRACE | 132 | #ifdef XFS_ATTR_TRACE |
| 138 | xfs_attr_trace_buf = ktrace_alloc(XFS_ATTR_TRACE_SIZE, KM_SLEEP); | 133 | xfs_attr_trace_buf = ktrace_alloc(XFS_ATTR_TRACE_SIZE, KM_SLEEP); |
| 139 | #endif | 134 | #endif |
| @@ -177,9 +172,6 @@ xfs_cleanup(void) | |||
| 177 | #ifdef XFS_ATTR_TRACE | 172 | #ifdef XFS_ATTR_TRACE |
| 178 | ktrace_free(xfs_attr_trace_buf); | 173 | ktrace_free(xfs_attr_trace_buf); |
| 179 | #endif | 174 | #endif |
| 180 | #ifdef XFS_DIR_TRACE | ||
| 181 | ktrace_free(xfs_dir_trace_buf); | ||
| 182 | #endif | ||
| 183 | #ifdef XFS_BMBT_TRACE | 175 | #ifdef XFS_BMBT_TRACE |
| 184 | ktrace_free(xfs_bmbt_trace_buf); | 176 | ktrace_free(xfs_bmbt_trace_buf); |
| 185 | #endif | 177 | #endif |
| @@ -212,7 +204,7 @@ xfs_cleanup(void) | |||
| 212 | */ | 204 | */ |
| 213 | STATIC int | 205 | STATIC int |
| 214 | xfs_start_flags( | 206 | xfs_start_flags( |
| 215 | struct vfs *vfs, | 207 | struct bhv_vfs *vfs, |
| 216 | struct xfs_mount_args *ap, | 208 | struct xfs_mount_args *ap, |
| 217 | struct xfs_mount *mp) | 209 | struct xfs_mount *mp) |
| 218 | { | 210 | { |
| @@ -337,7 +329,7 @@ xfs_start_flags( | |||
| 337 | */ | 329 | */ |
| 338 | STATIC int | 330 | STATIC int |
| 339 | xfs_finish_flags( | 331 | xfs_finish_flags( |
| 340 | struct vfs *vfs, | 332 | struct bhv_vfs *vfs, |
| 341 | struct xfs_mount_args *ap, | 333 | struct xfs_mount_args *ap, |
| 342 | struct xfs_mount *mp) | 334 | struct xfs_mount *mp) |
| 343 | { | 335 | { |
| @@ -423,7 +415,7 @@ xfs_mount( | |||
| 423 | struct xfs_mount_args *args, | 415 | struct xfs_mount_args *args, |
| 424 | cred_t *credp) | 416 | cred_t *credp) |
| 425 | { | 417 | { |
| 426 | struct vfs *vfsp = bhvtovfs(bhvp); | 418 | struct bhv_vfs *vfsp = bhvtovfs(bhvp); |
| 427 | struct bhv_desc *p; | 419 | struct bhv_desc *p; |
| 428 | struct xfs_mount *mp = XFS_BHVTOM(bhvp); | 420 | struct xfs_mount *mp = XFS_BHVTOM(bhvp); |
| 429 | struct block_device *ddev, *logdev, *rtdev; | 421 | struct block_device *ddev, *logdev, *rtdev; |
| @@ -552,10 +544,10 @@ xfs_unmount( | |||
| 552 | int flags, | 544 | int flags, |
| 553 | cred_t *credp) | 545 | cred_t *credp) |
| 554 | { | 546 | { |
| 555 | struct vfs *vfsp = bhvtovfs(bdp); | 547 | bhv_vfs_t *vfsp = bhvtovfs(bdp); |
| 556 | xfs_mount_t *mp = XFS_BHVTOM(bdp); | 548 | xfs_mount_t *mp = XFS_BHVTOM(bdp); |
| 557 | xfs_inode_t *rip; | 549 | xfs_inode_t *rip; |
| 558 | vnode_t *rvp; | 550 | bhv_vnode_t *rvp; |
| 559 | int unmount_event_wanted = 0; | 551 | int unmount_event_wanted = 0; |
| 560 | int unmount_event_flags = 0; | 552 | int unmount_event_flags = 0; |
| 561 | int xfs_unmountfs_needed = 0; | 553 | int xfs_unmountfs_needed = 0; |
| @@ -665,9 +657,8 @@ xfs_mntupdate( | |||
| 665 | int *flags, | 657 | int *flags, |
| 666 | struct xfs_mount_args *args) | 658 | struct xfs_mount_args *args) |
| 667 | { | 659 | { |
| 668 | struct vfs *vfsp = bhvtovfs(bdp); | 660 | bhv_vfs_t *vfsp = bhvtovfs(bdp); |
| 669 | xfs_mount_t *mp = XFS_BHVTOM(bdp); | 661 | xfs_mount_t *mp = XFS_BHVTOM(bdp); |
| 670 | int error; | ||
| 671 | 662 | ||
| 672 | if (!(*flags & MS_RDONLY)) { /* rw/ro -> rw */ | 663 | if (!(*flags & MS_RDONLY)) { /* rw/ro -> rw */ |
| 673 | if (vfsp->vfs_flag & VFS_RDONLY) | 664 | if (vfsp->vfs_flag & VFS_RDONLY) |
| @@ -679,7 +670,7 @@ xfs_mntupdate( | |||
| 679 | mp->m_flags &= ~XFS_MOUNT_BARRIER; | 670 | mp->m_flags &= ~XFS_MOUNT_BARRIER; |
| 680 | } | 671 | } |
| 681 | } else if (!(vfsp->vfs_flag & VFS_RDONLY)) { /* rw -> ro */ | 672 | } else if (!(vfsp->vfs_flag & VFS_RDONLY)) { /* rw -> ro */ |
| 682 | VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL, error); | 673 | bhv_vfs_sync(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL); |
| 683 | xfs_quiesce_fs(mp); | 674 | xfs_quiesce_fs(mp); |
| 684 | xfs_log_unmount_write(mp); | 675 | xfs_log_unmount_write(mp); |
| 685 | xfs_unmountfs_writesb(mp); | 676 | xfs_unmountfs_writesb(mp); |
| @@ -702,7 +693,7 @@ xfs_unmount_flush( | |||
| 702 | xfs_inode_t *rip = mp->m_rootip; | 693 | xfs_inode_t *rip = mp->m_rootip; |
| 703 | xfs_inode_t *rbmip; | 694 | xfs_inode_t *rbmip; |
| 704 | xfs_inode_t *rsumip = NULL; | 695 | xfs_inode_t *rsumip = NULL; |
| 705 | vnode_t *rvp = XFS_ITOV(rip); | 696 | bhv_vnode_t *rvp = XFS_ITOV(rip); |
| 706 | int error; | 697 | int error; |
| 707 | 698 | ||
| 708 | xfs_ilock(rip, XFS_ILOCK_EXCL); | 699 | xfs_ilock(rip, XFS_ILOCK_EXCL); |
| @@ -781,9 +772,9 @@ fscorrupt_out2: | |||
| 781 | STATIC int | 772 | STATIC int |
| 782 | xfs_root( | 773 | xfs_root( |
| 783 | bhv_desc_t *bdp, | 774 | bhv_desc_t *bdp, |
| 784 | vnode_t **vpp) | 775 | bhv_vnode_t **vpp) |
| 785 | { | 776 | { |
| 786 | vnode_t *vp; | 777 | bhv_vnode_t *vp; |
| 787 | 778 | ||
| 788 | vp = XFS_ITOV((XFS_BHVTOM(bdp))->m_rootip); | 779 | vp = XFS_ITOV((XFS_BHVTOM(bdp))->m_rootip); |
| 789 | VN_HOLD(vp); | 780 | VN_HOLD(vp); |
| @@ -801,8 +792,8 @@ xfs_root( | |||
| 801 | STATIC int | 792 | STATIC int |
| 802 | xfs_statvfs( | 793 | xfs_statvfs( |
| 803 | bhv_desc_t *bdp, | 794 | bhv_desc_t *bdp, |
| 804 | xfs_statfs_t *statp, | 795 | bhv_statvfs_t *statp, |
| 805 | vnode_t *vp) | 796 | bhv_vnode_t *vp) |
| 806 | { | 797 | { |
| 807 | __uint64_t fakeinos; | 798 | __uint64_t fakeinos; |
| 808 | xfs_extlen_t lsize; | 799 | xfs_extlen_t lsize; |
| @@ -900,7 +891,7 @@ xfs_sync( | |||
| 900 | /* | 891 | /* |
| 901 | * xfs sync routine for internal use | 892 | * xfs sync routine for internal use |
| 902 | * | 893 | * |
| 903 | * This routine supports all of the flags defined for the generic VFS_SYNC | 894 | * This routine supports all of the flags defined for the generic vfs_sync |
| 904 | * interface as explained above under xfs_sync. In the interests of not | 895 | * interface as explained above under xfs_sync. In the interests of not |
| 905 | * changing interfaces within the 6.5 family, additional internally- | 896 | * changing interfaces within the 6.5 family, additional internally- |
| 906 | * required functions are specified within a separate xflags parameter, | 897 | * required functions are specified within a separate xflags parameter, |
| @@ -917,7 +908,7 @@ xfs_sync_inodes( | |||
| 917 | xfs_inode_t *ip = NULL; | 908 | xfs_inode_t *ip = NULL; |
| 918 | xfs_inode_t *ip_next; | 909 | xfs_inode_t *ip_next; |
| 919 | xfs_buf_t *bp; | 910 | xfs_buf_t *bp; |
| 920 | vnode_t *vp = NULL; | 911 | bhv_vnode_t *vp = NULL; |
| 921 | int error; | 912 | int error; |
| 922 | int last_error; | 913 | int last_error; |
| 923 | uint64_t fflag; | 914 | uint64_t fflag; |
| @@ -1156,9 +1147,9 @@ xfs_sync_inodes( | |||
| 1156 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 1147 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
| 1157 | 1148 | ||
| 1158 | if (XFS_FORCED_SHUTDOWN(mp)) { | 1149 | if (XFS_FORCED_SHUTDOWN(mp)) { |
| 1159 | VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF); | 1150 | bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF); |
| 1160 | } else { | 1151 | } else { |
| 1161 | VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_REMAPF); | 1152 | bhv_vop_flushinval_pages(vp, 0, -1, FI_REMAPF); |
| 1162 | } | 1153 | } |
| 1163 | 1154 | ||
| 1164 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 1155 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
| @@ -1178,8 +1169,8 @@ xfs_sync_inodes( | |||
| 1178 | * across calls to the buffer cache. | 1169 | * across calls to the buffer cache. |
| 1179 | */ | 1170 | */ |
| 1180 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 1171 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
| 1181 | VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, | 1172 | error = bhv_vop_flush_pages(vp, (xfs_off_t)0, |
| 1182 | fflag, FI_NONE, error); | 1173 | -1, fflag, FI_NONE); |
| 1183 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 1174 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
| 1184 | } | 1175 | } |
| 1185 | 1176 | ||
| @@ -1231,9 +1222,7 @@ xfs_sync_inodes( | |||
| 1231 | * marker and free it. | 1222 | * marker and free it. |
| 1232 | */ | 1223 | */ |
| 1233 | XFS_MOUNT_ILOCK(mp); | 1224 | XFS_MOUNT_ILOCK(mp); |
| 1234 | |||
| 1235 | IPOINTER_REMOVE(ip, mp); | 1225 | IPOINTER_REMOVE(ip, mp); |
| 1236 | |||
| 1237 | XFS_MOUNT_IUNLOCK(mp); | 1226 | XFS_MOUNT_IUNLOCK(mp); |
| 1238 | 1227 | ||
| 1239 | ASSERT(!(lock_flags & | 1228 | ASSERT(!(lock_flags & |
| @@ -1421,7 +1410,7 @@ xfs_sync_inodes( | |||
| 1421 | /* | 1410 | /* |
| 1422 | * xfs sync routine for internal use | 1411 | * xfs sync routine for internal use |
| 1423 | * | 1412 | * |
| 1424 | * This routine supports all of the flags defined for the generic VFS_SYNC | 1413 | * This routine supports all of the flags defined for the generic vfs_sync |
| 1425 | * interface as explained above under xfs_sync. In the interests of not | 1414 | * interface as explained above under xfs_sync. In the interests of not |
| 1426 | * changing interfaces within the 6.5 family, additional internally- | 1415 | * changing interfaces within the 6.5 family, additional internally- |
| 1427 | * required functions are specified within a separate xflags parameter, | 1416 | * required functions are specified within a separate xflags parameter, |
| @@ -1574,7 +1563,7 @@ xfs_syncsub( | |||
| 1574 | STATIC int | 1563 | STATIC int |
| 1575 | xfs_vget( | 1564 | xfs_vget( |
| 1576 | bhv_desc_t *bdp, | 1565 | bhv_desc_t *bdp, |
| 1577 | vnode_t **vpp, | 1566 | bhv_vnode_t **vpp, |
| 1578 | fid_t *fidp) | 1567 | fid_t *fidp) |
| 1579 | { | 1568 | { |
| 1580 | xfs_mount_t *mp = XFS_BHVTOM(bdp); | 1569 | xfs_mount_t *mp = XFS_BHVTOM(bdp); |
| @@ -1657,10 +1646,10 @@ xfs_vget( | |||
| 1657 | #define MNTOPT_NOATTR2 "noattr2" /* do not use attr2 attribute format */ | 1646 | #define MNTOPT_NOATTR2 "noattr2" /* do not use attr2 attribute format */ |
| 1658 | 1647 | ||
| 1659 | STATIC unsigned long | 1648 | STATIC unsigned long |
| 1660 | suffix_strtoul(const char *cp, char **endp, unsigned int base) | 1649 | suffix_strtoul(char *s, char **endp, unsigned int base) |
| 1661 | { | 1650 | { |
| 1662 | int last, shift_left_factor = 0; | 1651 | int last, shift_left_factor = 0; |
| 1663 | char *value = (char *)cp; | 1652 | char *value = s; |
| 1664 | 1653 | ||
| 1665 | last = strlen(value) - 1; | 1654 | last = strlen(value) - 1; |
| 1666 | if (value[last] == 'K' || value[last] == 'k') { | 1655 | if (value[last] == 'K' || value[last] == 'k') { |
| @@ -1676,7 +1665,7 @@ suffix_strtoul(const char *cp, char **endp, unsigned int base) | |||
| 1676 | value[last] = '\0'; | 1665 | value[last] = '\0'; |
| 1677 | } | 1666 | } |
| 1678 | 1667 | ||
| 1679 | return simple_strtoul(cp, endp, base) << shift_left_factor; | 1668 | return simple_strtoul((const char *)s, endp, base) << shift_left_factor; |
| 1680 | } | 1669 | } |
| 1681 | 1670 | ||
| 1682 | STATIC int | 1671 | STATIC int |
| @@ -1686,7 +1675,7 @@ xfs_parseargs( | |||
| 1686 | struct xfs_mount_args *args, | 1675 | struct xfs_mount_args *args, |
| 1687 | int update) | 1676 | int update) |
| 1688 | { | 1677 | { |
| 1689 | struct vfs *vfsp = bhvtovfs(bhv); | 1678 | bhv_vfs_t *vfsp = bhvtovfs(bhv); |
| 1690 | char *this_char, *value, *eov; | 1679 | char *this_char, *value, *eov; |
| 1691 | int dsunit, dswidth, vol_dsunit, vol_dswidth; | 1680 | int dsunit, dswidth, vol_dsunit, vol_dswidth; |
| 1692 | int iosize; | 1681 | int iosize; |
| @@ -1708,42 +1697,48 @@ xfs_parseargs( | |||
| 1708 | 1697 | ||
| 1709 | if (!strcmp(this_char, MNTOPT_LOGBUFS)) { | 1698 | if (!strcmp(this_char, MNTOPT_LOGBUFS)) { |
| 1710 | if (!value || !*value) { | 1699 | if (!value || !*value) { |
| 1711 | printk("XFS: %s option requires an argument\n", | 1700 | cmn_err(CE_WARN, |
| 1701 | "XFS: %s option requires an argument", | ||
| 1712 | this_char); | 1702 | this_char); |
| 1713 | return EINVAL; | 1703 | return EINVAL; |
| 1714 | } | 1704 | } |
| 1715 | args->logbufs = simple_strtoul(value, &eov, 10); | 1705 | args->logbufs = simple_strtoul(value, &eov, 10); |
| 1716 | } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) { | 1706 | } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) { |
| 1717 | if (!value || !*value) { | 1707 | if (!value || !*value) { |
| 1718 | printk("XFS: %s option requires an argument\n", | 1708 | cmn_err(CE_WARN, |
| 1709 | "XFS: %s option requires an argument", | ||
| 1719 | this_char); | 1710 | this_char); |
| 1720 | return EINVAL; | 1711 | return EINVAL; |
| 1721 | } | 1712 | } |
| 1722 | args->logbufsize = suffix_strtoul(value, &eov, 10); | 1713 | args->logbufsize = suffix_strtoul(value, &eov, 10); |
| 1723 | } else if (!strcmp(this_char, MNTOPT_LOGDEV)) { | 1714 | } else if (!strcmp(this_char, MNTOPT_LOGDEV)) { |
| 1724 | if (!value || !*value) { | 1715 | if (!value || !*value) { |
| 1725 | printk("XFS: %s option requires an argument\n", | 1716 | cmn_err(CE_WARN, |
| 1717 | "XFS: %s option requires an argument", | ||
| 1726 | this_char); | 1718 | this_char); |
| 1727 | return EINVAL; | 1719 | return EINVAL; |
| 1728 | } | 1720 | } |
| 1729 | strncpy(args->logname, value, MAXNAMELEN); | 1721 | strncpy(args->logname, value, MAXNAMELEN); |
| 1730 | } else if (!strcmp(this_char, MNTOPT_MTPT)) { | 1722 | } else if (!strcmp(this_char, MNTOPT_MTPT)) { |
| 1731 | if (!value || !*value) { | 1723 | if (!value || !*value) { |
| 1732 | printk("XFS: %s option requires an argument\n", | 1724 | cmn_err(CE_WARN, |
| 1725 | "XFS: %s option requires an argument", | ||
| 1733 | this_char); | 1726 | this_char); |
| 1734 | return EINVAL; | 1727 | return EINVAL; |
| 1735 | } | 1728 | } |
| 1736 | strncpy(args->mtpt, value, MAXNAMELEN); | 1729 | strncpy(args->mtpt, value, MAXNAMELEN); |
| 1737 | } else if (!strcmp(this_char, MNTOPT_RTDEV)) { | 1730 | } else if (!strcmp(this_char, MNTOPT_RTDEV)) { |
| 1738 | if (!value || !*value) { | 1731 | if (!value || !*value) { |
| 1739 | printk("XFS: %s option requires an argument\n", | 1732 | cmn_err(CE_WARN, |
| 1733 | "XFS: %s option requires an argument", | ||
| 1740 | this_char); | 1734 | this_char); |
| 1741 | return EINVAL; | 1735 | return EINVAL; |
| 1742 | } | 1736 | } |
| 1743 | strncpy(args->rtname, value, MAXNAMELEN); | 1737 | strncpy(args->rtname, value, MAXNAMELEN); |
| 1744 | } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) { | 1738 | } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) { |
| 1745 | if (!value || !*value) { | 1739 | if (!value || !*value) { |
| 1746 | printk("XFS: %s option requires an argument\n", | 1740 | cmn_err(CE_WARN, |
| 1741 | "XFS: %s option requires an argument", | ||
| 1747 | this_char); | 1742 | this_char); |
| 1748 | return EINVAL; | 1743 | return EINVAL; |
| 1749 | } | 1744 | } |
| @@ -1752,7 +1747,8 @@ xfs_parseargs( | |||
| 1752 | args->iosizelog = (uint8_t) iosize; | 1747 | args->iosizelog = (uint8_t) iosize; |
| 1753 | } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) { | 1748 | } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) { |
| 1754 | if (!value || !*value) { | 1749 | if (!value || !*value) { |
| 1755 | printk("XFS: %s option requires an argument\n", | 1750 | cmn_err(CE_WARN, |
| 1751 | "XFS: %s option requires an argument", | ||
| 1756 | this_char); | 1752 | this_char); |
| 1757 | return EINVAL; | 1753 | return EINVAL; |
| 1758 | } | 1754 | } |
| @@ -1761,7 +1757,8 @@ xfs_parseargs( | |||
| 1761 | args->iosizelog = ffs(iosize) - 1; | 1757 | args->iosizelog = ffs(iosize) - 1; |
| 1762 | } else if (!strcmp(this_char, MNTOPT_IHASHSIZE)) { | 1758 | } else if (!strcmp(this_char, MNTOPT_IHASHSIZE)) { |
| 1763 | if (!value || !*value) { | 1759 | if (!value || !*value) { |
| 1764 | printk("XFS: %s option requires an argument\n", | 1760 | cmn_err(CE_WARN, |
| 1761 | "XFS: %s option requires an argument", | ||
| 1765 | this_char); | 1762 | this_char); |
| 1766 | return EINVAL; | 1763 | return EINVAL; |
| 1767 | } | 1764 | } |
| @@ -1782,7 +1779,8 @@ xfs_parseargs( | |||
| 1782 | } else if (!strcmp(this_char, MNTOPT_INO64)) { | 1779 | } else if (!strcmp(this_char, MNTOPT_INO64)) { |
| 1783 | args->flags |= XFSMNT_INO64; | 1780 | args->flags |= XFSMNT_INO64; |
| 1784 | #if !XFS_BIG_INUMS | 1781 | #if !XFS_BIG_INUMS |
| 1785 | printk("XFS: %s option not allowed on this system\n", | 1782 | cmn_err(CE_WARN, |
| 1783 | "XFS: %s option not allowed on this system", | ||
| 1786 | this_char); | 1784 | this_char); |
| 1787 | return EINVAL; | 1785 | return EINVAL; |
| 1788 | #endif | 1786 | #endif |
| @@ -1792,14 +1790,16 @@ xfs_parseargs( | |||
| 1792 | args->flags |= XFSMNT_SWALLOC; | 1790 | args->flags |= XFSMNT_SWALLOC; |
| 1793 | } else if (!strcmp(this_char, MNTOPT_SUNIT)) { | 1791 | } else if (!strcmp(this_char, MNTOPT_SUNIT)) { |
| 1794 | if (!value || !*value) { | 1792 | if (!value || !*value) { |
| 1795 | printk("XFS: %s option requires an argument\n", | 1793 | cmn_err(CE_WARN, |
| 1794 | "XFS: %s option requires an argument", | ||
| 1796 | this_char); | 1795 | this_char); |
| 1797 | return EINVAL; | 1796 | return EINVAL; |
| 1798 | } | 1797 | } |
| 1799 | dsunit = simple_strtoul(value, &eov, 10); | 1798 | dsunit = simple_strtoul(value, &eov, 10); |
| 1800 | } else if (!strcmp(this_char, MNTOPT_SWIDTH)) { | 1799 | } else if (!strcmp(this_char, MNTOPT_SWIDTH)) { |
| 1801 | if (!value || !*value) { | 1800 | if (!value || !*value) { |
| 1802 | printk("XFS: %s option requires an argument\n", | 1801 | cmn_err(CE_WARN, |
| 1802 | "XFS: %s option requires an argument", | ||
| 1803 | this_char); | 1803 | this_char); |
| 1804 | return EINVAL; | 1804 | return EINVAL; |
| 1805 | } | 1805 | } |
| @@ -1807,7 +1807,8 @@ xfs_parseargs( | |||
| 1807 | } else if (!strcmp(this_char, MNTOPT_64BITINODE)) { | 1807 | } else if (!strcmp(this_char, MNTOPT_64BITINODE)) { |
| 1808 | args->flags &= ~XFSMNT_32BITINODES; | 1808 | args->flags &= ~XFSMNT_32BITINODES; |
| 1809 | #if !XFS_BIG_INUMS | 1809 | #if !XFS_BIG_INUMS |
| 1810 | printk("XFS: %s option not allowed on this system\n", | 1810 | cmn_err(CE_WARN, |
| 1811 | "XFS: %s option not allowed on this system", | ||
| 1811 | this_char); | 1812 | this_char); |
| 1812 | return EINVAL; | 1813 | return EINVAL; |
| 1813 | #endif | 1814 | #endif |
| @@ -1831,36 +1832,41 @@ xfs_parseargs( | |||
| 1831 | args->flags &= ~XFSMNT_ATTR2; | 1832 | args->flags &= ~XFSMNT_ATTR2; |
| 1832 | } else if (!strcmp(this_char, "osyncisdsync")) { | 1833 | } else if (!strcmp(this_char, "osyncisdsync")) { |
| 1833 | /* no-op, this is now the default */ | 1834 | /* no-op, this is now the default */ |
| 1834 | printk("XFS: osyncisdsync is now the default, option is deprecated.\n"); | 1835 | cmn_err(CE_WARN, |
| 1836 | "XFS: osyncisdsync is now the default, option is deprecated."); | ||
| 1835 | } else if (!strcmp(this_char, "irixsgid")) { | 1837 | } else if (!strcmp(this_char, "irixsgid")) { |
| 1836 | printk("XFS: irixsgid is now a sysctl(2) variable, option is deprecated.\n"); | 1838 | cmn_err(CE_WARN, |
| 1839 | "XFS: irixsgid is now a sysctl(2) variable, option is deprecated."); | ||
| 1837 | } else { | 1840 | } else { |
| 1838 | printk("XFS: unknown mount option [%s].\n", this_char); | 1841 | cmn_err(CE_WARN, |
| 1842 | "XFS: unknown mount option [%s].", this_char); | ||
| 1839 | return EINVAL; | 1843 | return EINVAL; |
| 1840 | } | 1844 | } |
| 1841 | } | 1845 | } |
| 1842 | 1846 | ||
| 1843 | if (args->flags & XFSMNT_NORECOVERY) { | 1847 | if (args->flags & XFSMNT_NORECOVERY) { |
| 1844 | if ((vfsp->vfs_flag & VFS_RDONLY) == 0) { | 1848 | if ((vfsp->vfs_flag & VFS_RDONLY) == 0) { |
| 1845 | printk("XFS: no-recovery mounts must be read-only.\n"); | 1849 | cmn_err(CE_WARN, |
| 1850 | "XFS: no-recovery mounts must be read-only."); | ||
| 1846 | return EINVAL; | 1851 | return EINVAL; |
| 1847 | } | 1852 | } |
| 1848 | } | 1853 | } |
| 1849 | 1854 | ||
| 1850 | if ((args->flags & XFSMNT_NOALIGN) && (dsunit || dswidth)) { | 1855 | if ((args->flags & XFSMNT_NOALIGN) && (dsunit || dswidth)) { |
| 1851 | printk( | 1856 | cmn_err(CE_WARN, |
| 1852 | "XFS: sunit and swidth options incompatible with the noalign option\n"); | 1857 | "XFS: sunit and swidth options incompatible with the noalign option"); |
| 1853 | return EINVAL; | 1858 | return EINVAL; |
| 1854 | } | 1859 | } |
| 1855 | 1860 | ||
| 1856 | if ((dsunit && !dswidth) || (!dsunit && dswidth)) { | 1861 | if ((dsunit && !dswidth) || (!dsunit && dswidth)) { |
| 1857 | printk("XFS: sunit and swidth must be specified together\n"); | 1862 | cmn_err(CE_WARN, |
| 1863 | "XFS: sunit and swidth must be specified together"); | ||
| 1858 | return EINVAL; | 1864 | return EINVAL; |
| 1859 | } | 1865 | } |
| 1860 | 1866 | ||
| 1861 | if (dsunit && (dswidth % dsunit != 0)) { | 1867 | if (dsunit && (dswidth % dsunit != 0)) { |
| 1862 | printk( | 1868 | cmn_err(CE_WARN, |
| 1863 | "XFS: stripe width (%d) must be a multiple of the stripe unit (%d)\n", | 1869 | "XFS: stripe width (%d) must be a multiple of the stripe unit (%d)", |
| 1864 | dswidth, dsunit); | 1870 | dswidth, dsunit); |
| 1865 | return EINVAL; | 1871 | return EINVAL; |
| 1866 | } | 1872 | } |
| @@ -1907,7 +1913,7 @@ xfs_showargs( | |||
| 1907 | }; | 1913 | }; |
| 1908 | struct proc_xfs_info *xfs_infop; | 1914 | struct proc_xfs_info *xfs_infop; |
| 1909 | struct xfs_mount *mp = XFS_BHVTOM(bhv); | 1915 | struct xfs_mount *mp = XFS_BHVTOM(bhv); |
| 1910 | struct vfs *vfsp = XFS_MTOVFS(mp); | 1916 | struct bhv_vfs *vfsp = XFS_MTOVFS(mp); |
| 1911 | 1917 | ||
| 1912 | for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) { | 1918 | for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) { |
| 1913 | if (mp->m_flags & xfs_infop->flag) | 1919 | if (mp->m_flags & xfs_infop->flag) |
| @@ -1967,7 +1973,7 @@ xfs_freeze( | |||
| 1967 | } | 1973 | } |
| 1968 | 1974 | ||
| 1969 | 1975 | ||
| 1970 | vfsops_t xfs_vfsops = { | 1976 | bhv_vfsops_t xfs_vfsops = { |
| 1971 | BHV_IDENTITY_INIT(VFS_BHV_XFS,VFS_POSITION_XFS), | 1977 | BHV_IDENTITY_INIT(VFS_BHV_XFS,VFS_POSITION_XFS), |
| 1972 | .vfs_parseargs = xfs_parseargs, | 1978 | .vfs_parseargs = xfs_parseargs, |
| 1973 | .vfs_showargs = xfs_showargs, | 1979 | .vfs_showargs = xfs_showargs, |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 7027ae68ee38..00a6b7dc24a0 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2000-2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. |
| 3 | * All Rights Reserved. | 3 | * All Rights Reserved. |
| 4 | * | 4 | * |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| @@ -16,8 +16,6 @@ | |||
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | #include <linux/capability.h> | ||
| 20 | |||
| 21 | #include "xfs.h" | 19 | #include "xfs.h" |
| 22 | #include "xfs_fs.h" | 20 | #include "xfs_fs.h" |
| 23 | #include "xfs_types.h" | 21 | #include "xfs_types.h" |
| @@ -27,7 +25,6 @@ | |||
| 27 | #include "xfs_trans.h" | 25 | #include "xfs_trans.h" |
| 28 | #include "xfs_sb.h" | 26 | #include "xfs_sb.h" |
| 29 | #include "xfs_ag.h" | 27 | #include "xfs_ag.h" |
| 30 | #include "xfs_dir.h" | ||
| 31 | #include "xfs_dir2.h" | 28 | #include "xfs_dir2.h" |
| 32 | #include "xfs_dmapi.h" | 29 | #include "xfs_dmapi.h" |
| 33 | #include "xfs_mount.h" | 30 | #include "xfs_mount.h" |
| @@ -35,13 +32,11 @@ | |||
| 35 | #include "xfs_bmap_btree.h" | 32 | #include "xfs_bmap_btree.h" |
| 36 | #include "xfs_alloc_btree.h" | 33 | #include "xfs_alloc_btree.h" |
| 37 | #include "xfs_ialloc_btree.h" | 34 | #include "xfs_ialloc_btree.h" |
| 38 | #include "xfs_dir_sf.h" | ||
| 39 | #include "xfs_dir2_sf.h" | 35 | #include "xfs_dir2_sf.h" |
| 40 | #include "xfs_attr_sf.h" | 36 | #include "xfs_attr_sf.h" |
| 41 | #include "xfs_dinode.h" | 37 | #include "xfs_dinode.h" |
| 42 | #include "xfs_inode.h" | 38 | #include "xfs_inode.h" |
| 43 | #include "xfs_inode_item.h" | 39 | #include "xfs_inode_item.h" |
| 44 | #include "xfs_dir_leaf.h" | ||
| 45 | #include "xfs_itable.h" | 40 | #include "xfs_itable.h" |
| 46 | #include "xfs_btree.h" | 41 | #include "xfs_btree.h" |
| 47 | #include "xfs_ialloc.h" | 42 | #include "xfs_ialloc.h" |
| @@ -58,32 +53,14 @@ | |||
| 58 | #include "xfs_log_priv.h" | 53 | #include "xfs_log_priv.h" |
| 59 | #include "xfs_mac.h" | 54 | #include "xfs_mac.h" |
| 60 | 55 | ||
| 61 | |||
| 62 | /* | ||
| 63 | * The maximum pathlen is 1024 bytes. Since the minimum file system | ||
| 64 | * blocksize is 512 bytes, we can get a max of 2 extents back from | ||
| 65 | * bmapi. | ||
| 66 | */ | ||
| 67 | #define SYMLINK_MAPS 2 | ||
| 68 | |||
| 69 | /* | ||
| 70 | * For xfs, we check that the file isn't too big to be opened by this kernel. | ||
| 71 | * No other open action is required for regular files. Devices are handled | ||
| 72 | * through the specfs file system, pipes through fifofs. Device and | ||
| 73 | * fifo vnodes are "wrapped" by specfs and fifofs vnodes, respectively, | ||
| 74 | * when a new vnode is first looked up or created. | ||
| 75 | */ | ||
| 76 | STATIC int | 56 | STATIC int |
| 77 | xfs_open( | 57 | xfs_open( |
| 78 | bhv_desc_t *bdp, | 58 | bhv_desc_t *bdp, |
| 79 | cred_t *credp) | 59 | cred_t *credp) |
| 80 | { | 60 | { |
| 81 | int mode; | 61 | int mode; |
| 82 | vnode_t *vp; | 62 | bhv_vnode_t *vp = BHV_TO_VNODE(bdp); |
| 83 | xfs_inode_t *ip; | 63 | xfs_inode_t *ip = XFS_BHVTOI(bdp); |
| 84 | |||
| 85 | vp = BHV_TO_VNODE(bdp); | ||
| 86 | ip = XFS_BHVTOI(bdp); | ||
| 87 | 64 | ||
| 88 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | 65 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) |
| 89 | return XFS_ERROR(EIO); | 66 | return XFS_ERROR(EIO); |
| @@ -101,6 +78,35 @@ xfs_open( | |||
| 101 | return 0; | 78 | return 0; |
| 102 | } | 79 | } |
| 103 | 80 | ||
| 81 | STATIC int | ||
| 82 | xfs_close( | ||
| 83 | bhv_desc_t *bdp, | ||
| 84 | int flags, | ||
| 85 | lastclose_t lastclose, | ||
| 86 | cred_t *credp) | ||
| 87 | { | ||
| 88 | bhv_vnode_t *vp = BHV_TO_VNODE(bdp); | ||
| 89 | xfs_inode_t *ip = XFS_BHVTOI(bdp); | ||
| 90 | |||
| 91 | if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | ||
| 92 | return XFS_ERROR(EIO); | ||
| 93 | |||
| 94 | if (lastclose != L_TRUE || !VN_ISREG(vp)) | ||
| 95 | return 0; | ||
| 96 | |||
| 97 | /* | ||
| 98 | * If we previously truncated this file and removed old data in | ||
| 99 | * the process, we want to initiate "early" writeout on the last | ||
| 100 | * close. This is an attempt to combat the notorious NULL files | ||
| 101 | * problem which is particularly noticable from a truncate down, | ||
| 102 | * buffered (re-)write (delalloc), followed by a crash. What we | ||
| 103 | * are effectively doing here is significantly reducing the time | ||
| 104 | * window where we'd otherwise be exposed to that problem. | ||
| 105 | */ | ||
| 106 | if (VUNTRUNCATE(vp) && VN_DIRTY(vp) && ip->i_delayed_blks > 0) | ||
| 107 | return bhv_vop_flush_pages(vp, 0, -1, XFS_B_ASYNC, FI_NONE); | ||
| 108 | return 0; | ||
| 109 | } | ||
| 104 | 110 | ||
| 105 | /* | 111 | /* |
| 106 | * xfs_getattr | 112 | * xfs_getattr |
| @@ -108,13 +114,13 @@ xfs_open( | |||
| 108 | STATIC int | 114 | STATIC int |
| 109 | xfs_getattr( | 115 | xfs_getattr( |
| 110 | bhv_desc_t *bdp, | 116 | bhv_desc_t *bdp, |
| 111 | vattr_t *vap, | 117 | bhv_vattr_t *vap, |
| 112 | int flags, | 118 | int flags, |
| 113 | cred_t *credp) | 119 | cred_t *credp) |
| 114 | { | 120 | { |
| 115 | xfs_inode_t *ip; | 121 | xfs_inode_t *ip; |
| 116 | xfs_mount_t *mp; | 122 | xfs_mount_t *mp; |
| 117 | vnode_t *vp; | 123 | bhv_vnode_t *vp; |
| 118 | 124 | ||
| 119 | vp = BHV_TO_VNODE(bdp); | 125 | vp = BHV_TO_VNODE(bdp); |
| 120 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); | 126 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); |
| @@ -241,7 +247,7 @@ xfs_getattr( | |||
| 241 | int | 247 | int |
| 242 | xfs_setattr( | 248 | xfs_setattr( |
| 243 | bhv_desc_t *bdp, | 249 | bhv_desc_t *bdp, |
| 244 | vattr_t *vap, | 250 | bhv_vattr_t *vap, |
| 245 | int flags, | 251 | int flags, |
| 246 | cred_t *credp) | 252 | cred_t *credp) |
| 247 | { | 253 | { |
| @@ -255,7 +261,7 @@ xfs_setattr( | |||
| 255 | uid_t uid=0, iuid=0; | 261 | uid_t uid=0, iuid=0; |
| 256 | gid_t gid=0, igid=0; | 262 | gid_t gid=0, igid=0; |
| 257 | int timeflags = 0; | 263 | int timeflags = 0; |
| 258 | vnode_t *vp; | 264 | bhv_vnode_t *vp; |
| 259 | xfs_prid_t projid=0, iprojid=0; | 265 | xfs_prid_t projid=0, iprojid=0; |
| 260 | int mandlock_before, mandlock_after; | 266 | int mandlock_before, mandlock_after; |
| 261 | struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; | 267 | struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; |
| @@ -347,7 +353,6 @@ xfs_setattr( | |||
| 347 | */ | 353 | */ |
| 348 | tp = NULL; | 354 | tp = NULL; |
| 349 | lock_flags = XFS_ILOCK_EXCL; | 355 | lock_flags = XFS_ILOCK_EXCL; |
| 350 | ASSERT(flags & ATTR_NOLOCK ? flags & ATTR_DMI : 1); | ||
| 351 | if (flags & ATTR_NOLOCK) | 356 | if (flags & ATTR_NOLOCK) |
| 352 | need_iolock = 0; | 357 | need_iolock = 0; |
| 353 | if (!(mask & XFS_AT_SIZE)) { | 358 | if (!(mask & XFS_AT_SIZE)) { |
| @@ -666,9 +671,17 @@ xfs_setattr( | |||
| 666 | ((ip->i_d.di_nlink != 0 || | 671 | ((ip->i_d.di_nlink != 0 || |
| 667 | !(mp->m_flags & XFS_MOUNT_WSYNC)) | 672 | !(mp->m_flags & XFS_MOUNT_WSYNC)) |
| 668 | ? 1 : 0)); | 673 | ? 1 : 0)); |
| 669 | if (code) { | 674 | if (code) |
| 670 | goto abort_return; | 675 | goto abort_return; |
| 671 | } | 676 | /* |
| 677 | * Truncated "down", so we're removing references | ||
| 678 | * to old data here - if we now delay flushing for | ||
| 679 | * a long time, we expose ourselves unduly to the | ||
| 680 | * notorious NULL files problem. So, we mark this | ||
| 681 | * vnode and flush it when the file is closed, and | ||
| 682 | * do not wait the usual (long) time for writeout. | ||
| 683 | */ | ||
| 684 | VTRUNCATE(vp); | ||
| 672 | } | 685 | } |
| 673 | /* | 686 | /* |
| 674 | * Have to do this even if the file's size doesn't change. | 687 | * Have to do this even if the file's size doesn't change. |
| @@ -800,6 +813,8 @@ xfs_setattr( | |||
| 800 | di_flags |= XFS_DIFLAG_NODUMP; | 813 | di_flags |= XFS_DIFLAG_NODUMP; |
| 801 | if (vap->va_xflags & XFS_XFLAG_PROJINHERIT) | 814 | if (vap->va_xflags & XFS_XFLAG_PROJINHERIT) |
| 802 | di_flags |= XFS_DIFLAG_PROJINHERIT; | 815 | di_flags |= XFS_DIFLAG_PROJINHERIT; |
| 816 | if (vap->va_xflags & XFS_XFLAG_NODEFRAG) | ||
| 817 | di_flags |= XFS_DIFLAG_NODEFRAG; | ||
| 803 | if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { | 818 | if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { |
| 804 | if (vap->va_xflags & XFS_XFLAG_RTINHERIT) | 819 | if (vap->va_xflags & XFS_XFLAG_RTINHERIT) |
| 805 | di_flags |= XFS_DIFLAG_RTINHERIT; | 820 | di_flags |= XFS_DIFLAG_RTINHERIT; |
| @@ -869,7 +884,7 @@ xfs_setattr( | |||
| 869 | */ | 884 | */ |
| 870 | mandlock_after = MANDLOCK(vp, ip->i_d.di_mode); | 885 | mandlock_after = MANDLOCK(vp, ip->i_d.di_mode); |
| 871 | if (mandlock_before != mandlock_after) { | 886 | if (mandlock_before != mandlock_after) { |
| 872 | VOP_VNODE_CHANGE(vp, VCHANGE_FLAGS_ENF_LOCKING, | 887 | bhv_vop_vnode_change(vp, VCHANGE_FLAGS_ENF_LOCKING, |
| 873 | mandlock_after); | 888 | mandlock_after); |
| 874 | } | 889 | } |
| 875 | 890 | ||
| @@ -936,6 +951,13 @@ xfs_access( | |||
| 936 | 951 | ||
| 937 | 952 | ||
| 938 | /* | 953 | /* |
| 954 | * The maximum pathlen is 1024 bytes. Since the minimum file system | ||
| 955 | * blocksize is 512 bytes, we can get a max of 2 extents back from | ||
| 956 | * bmapi. | ||
| 957 | */ | ||
| 958 | #define SYMLINK_MAPS 2 | ||
| 959 | |||
| 960 | /* | ||
| 939 | * xfs_readlink | 961 | * xfs_readlink |
| 940 | * | 962 | * |
| 941 | */ | 963 | */ |
| @@ -950,7 +972,7 @@ xfs_readlink( | |||
| 950 | int count; | 972 | int count; |
| 951 | xfs_off_t offset; | 973 | xfs_off_t offset; |
| 952 | int pathlen; | 974 | int pathlen; |
| 953 | vnode_t *vp; | 975 | bhv_vnode_t *vp; |
| 954 | int error = 0; | 976 | int error = 0; |
| 955 | xfs_mount_t *mp; | 977 | xfs_mount_t *mp; |
| 956 | int nmaps; | 978 | int nmaps; |
| @@ -1000,7 +1022,7 @@ xfs_readlink( | |||
| 1000 | nmaps = SYMLINK_MAPS; | 1022 | nmaps = SYMLINK_MAPS; |
| 1001 | 1023 | ||
| 1002 | error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), | 1024 | error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), |
| 1003 | 0, NULL, 0, mval, &nmaps, NULL); | 1025 | 0, NULL, 0, mval, &nmaps, NULL, NULL); |
| 1004 | 1026 | ||
| 1005 | if (error) { | 1027 | if (error) { |
| 1006 | goto error_return; | 1028 | goto error_return; |
| @@ -1208,8 +1230,8 @@ xfs_inactive_free_eofblocks( | |||
| 1208 | 1230 | ||
| 1209 | nimaps = 1; | 1231 | nimaps = 1; |
| 1210 | xfs_ilock(ip, XFS_ILOCK_SHARED); | 1232 | xfs_ilock(ip, XFS_ILOCK_SHARED); |
| 1211 | error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0, | 1233 | error = XFS_BMAPI(mp, NULL, &ip->i_iocore, end_fsb, map_len, 0, |
| 1212 | NULL, 0, &imap, &nimaps, NULL); | 1234 | NULL, 0, &imap, &nimaps, NULL, NULL); |
| 1213 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 1235 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
| 1214 | 1236 | ||
| 1215 | if (!error && (nimaps != 0) && | 1237 | if (!error && (nimaps != 0) && |
| @@ -1338,7 +1360,7 @@ xfs_inactive_symlink_rmt( | |||
| 1338 | nmaps = ARRAY_SIZE(mval); | 1360 | nmaps = ARRAY_SIZE(mval); |
| 1339 | if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size), | 1361 | if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size), |
| 1340 | XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps, | 1362 | XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps, |
| 1341 | &free_list))) | 1363 | &free_list, NULL))) |
| 1342 | goto error0; | 1364 | goto error0; |
| 1343 | /* | 1365 | /* |
| 1344 | * Invalidate the block(s). | 1366 | * Invalidate the block(s). |
| @@ -1353,7 +1375,7 @@ xfs_inactive_symlink_rmt( | |||
| 1353 | * Unmap the dead block(s) to the free_list. | 1375 | * Unmap the dead block(s) to the free_list. |
| 1354 | */ | 1376 | */ |
| 1355 | if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps, | 1377 | if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps, |
| 1356 | &first_block, &free_list, &done))) | 1378 | &first_block, &free_list, NULL, &done))) |
| 1357 | goto error1; | 1379 | goto error1; |
| 1358 | ASSERT(done); | 1380 | ASSERT(done); |
| 1359 | /* | 1381 | /* |
| @@ -1469,9 +1491,6 @@ xfs_inactive_symlink_local( | |||
| 1469 | return 0; | 1491 | return 0; |
| 1470 | } | 1492 | } |
| 1471 | 1493 | ||
| 1472 | /* | ||
| 1473 | * | ||
| 1474 | */ | ||
| 1475 | STATIC int | 1494 | STATIC int |
| 1476 | xfs_inactive_attrs( | 1495 | xfs_inactive_attrs( |
| 1477 | xfs_inode_t *ip, | 1496 | xfs_inode_t *ip, |
| @@ -1524,16 +1543,16 @@ xfs_release( | |||
| 1524 | bhv_desc_t *bdp) | 1543 | bhv_desc_t *bdp) |
| 1525 | { | 1544 | { |
| 1526 | xfs_inode_t *ip; | 1545 | xfs_inode_t *ip; |
| 1527 | vnode_t *vp; | 1546 | bhv_vnode_t *vp; |
| 1528 | xfs_mount_t *mp; | 1547 | xfs_mount_t *mp; |
| 1529 | int error; | 1548 | int error; |
| 1530 | 1549 | ||
| 1531 | vp = BHV_TO_VNODE(bdp); | 1550 | vp = BHV_TO_VNODE(bdp); |
| 1532 | ip = XFS_BHVTOI(bdp); | 1551 | ip = XFS_BHVTOI(bdp); |
| 1552 | mp = ip->i_mount; | ||
| 1533 | 1553 | ||
| 1534 | if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0)) { | 1554 | if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0)) |
| 1535 | return 0; | 1555 | return 0; |
| 1536 | } | ||
| 1537 | 1556 | ||
| 1538 | /* If this is a read-only mount, don't do this (would generate I/O) */ | 1557 | /* If this is a read-only mount, don't do this (would generate I/O) */ |
| 1539 | if (vp->v_vfsp->vfs_flag & VFS_RDONLY) | 1558 | if (vp->v_vfsp->vfs_flag & VFS_RDONLY) |
| @@ -1545,8 +1564,6 @@ xfs_release( | |||
| 1545 | return 0; | 1564 | return 0; |
| 1546 | #endif | 1565 | #endif |
| 1547 | 1566 | ||
| 1548 | mp = ip->i_mount; | ||
| 1549 | |||
| 1550 | if (ip->i_d.di_nlink != 0) { | 1567 | if (ip->i_d.di_nlink != 0) { |
| 1551 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && | 1568 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && |
| 1552 | ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 || | 1569 | ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 || |
| @@ -1579,8 +1596,8 @@ xfs_inactive( | |||
| 1579 | cred_t *credp) | 1596 | cred_t *credp) |
| 1580 | { | 1597 | { |
| 1581 | xfs_inode_t *ip; | 1598 | xfs_inode_t *ip; |
| 1582 | vnode_t *vp; | 1599 | bhv_vnode_t *vp; |
| 1583 | xfs_bmap_free_t free_list; | 1600 | xfs_bmap_free_t free_list; |
| 1584 | xfs_fsblock_t first_block; | 1601 | xfs_fsblock_t first_block; |
| 1585 | int committed; | 1602 | int committed; |
| 1586 | xfs_trans_t *tp; | 1603 | xfs_trans_t *tp; |
| @@ -1760,7 +1777,7 @@ xfs_inactive( | |||
| 1760 | cmn_err(CE_NOTE, | 1777 | cmn_err(CE_NOTE, |
| 1761 | "xfs_inactive: xfs_ifree() returned an error = %d on %s", | 1778 | "xfs_inactive: xfs_ifree() returned an error = %d on %s", |
| 1762 | error, mp->m_fsname); | 1779 | error, mp->m_fsname); |
| 1763 | xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); | 1780 | xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); |
| 1764 | } | 1781 | } |
| 1765 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); | 1782 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); |
| 1766 | } else { | 1783 | } else { |
| @@ -1795,17 +1812,17 @@ xfs_inactive( | |||
| 1795 | STATIC int | 1812 | STATIC int |
| 1796 | xfs_lookup( | 1813 | xfs_lookup( |
| 1797 | bhv_desc_t *dir_bdp, | 1814 | bhv_desc_t *dir_bdp, |
| 1798 | vname_t *dentry, | 1815 | bhv_vname_t *dentry, |
| 1799 | vnode_t **vpp, | 1816 | bhv_vnode_t **vpp, |
| 1800 | int flags, | 1817 | int flags, |
| 1801 | vnode_t *rdir, | 1818 | bhv_vnode_t *rdir, |
| 1802 | cred_t *credp) | 1819 | cred_t *credp) |
| 1803 | { | 1820 | { |
| 1804 | xfs_inode_t *dp, *ip; | 1821 | xfs_inode_t *dp, *ip; |
| 1805 | xfs_ino_t e_inum; | 1822 | xfs_ino_t e_inum; |
| 1806 | int error; | 1823 | int error; |
| 1807 | uint lock_mode; | 1824 | uint lock_mode; |
| 1808 | vnode_t *dir_vp; | 1825 | bhv_vnode_t *dir_vp; |
| 1809 | 1826 | ||
| 1810 | dir_vp = BHV_TO_VNODE(dir_bdp); | 1827 | dir_vp = BHV_TO_VNODE(dir_bdp); |
| 1811 | vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address); | 1828 | vn_trace_entry(dir_vp, __FUNCTION__, (inst_t *)__return_address); |
| @@ -1832,15 +1849,15 @@ xfs_lookup( | |||
| 1832 | STATIC int | 1849 | STATIC int |
| 1833 | xfs_create( | 1850 | xfs_create( |
| 1834 | bhv_desc_t *dir_bdp, | 1851 | bhv_desc_t *dir_bdp, |
| 1835 | vname_t *dentry, | 1852 | bhv_vname_t *dentry, |
| 1836 | vattr_t *vap, | 1853 | bhv_vattr_t *vap, |
| 1837 | vnode_t **vpp, | 1854 | bhv_vnode_t **vpp, |
| 1838 | cred_t *credp) | 1855 | cred_t *credp) |
| 1839 | { | 1856 | { |
| 1840 | char *name = VNAME(dentry); | 1857 | char *name = VNAME(dentry); |
| 1841 | vnode_t *dir_vp; | 1858 | bhv_vnode_t *dir_vp; |
| 1842 | xfs_inode_t *dp, *ip; | 1859 | xfs_inode_t *dp, *ip; |
| 1843 | vnode_t *vp=NULL; | 1860 | bhv_vnode_t *vp = NULL; |
| 1844 | xfs_trans_t *tp; | 1861 | xfs_trans_t *tp; |
| 1845 | xfs_mount_t *mp; | 1862 | xfs_mount_t *mp; |
| 1846 | xfs_dev_t rdev; | 1863 | xfs_dev_t rdev; |
| @@ -1938,8 +1955,7 @@ xfs_create( | |||
| 1938 | if (error) | 1955 | if (error) |
| 1939 | goto error_return; | 1956 | goto error_return; |
| 1940 | 1957 | ||
| 1941 | if (resblks == 0 && | 1958 | if (resblks == 0 && (error = xfs_dir_canenter(tp, dp, name, namelen))) |
| 1942 | (error = XFS_DIR_CANENTER(mp, tp, dp, name, namelen))) | ||
| 1943 | goto error_return; | 1959 | goto error_return; |
| 1944 | rdev = (vap->va_mask & XFS_AT_RDEV) ? vap->va_rdev : 0; | 1960 | rdev = (vap->va_mask & XFS_AT_RDEV) ? vap->va_rdev : 0; |
| 1945 | error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 1, | 1961 | error = xfs_dir_ialloc(&tp, dp, vap->va_mode, 1, |
| @@ -1970,9 +1986,9 @@ xfs_create( | |||
| 1970 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); | 1986 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); |
| 1971 | dp_joined_to_trans = B_TRUE; | 1987 | dp_joined_to_trans = B_TRUE; |
| 1972 | 1988 | ||
| 1973 | error = XFS_DIR_CREATENAME(mp, tp, dp, name, namelen, ip->i_ino, | 1989 | error = xfs_dir_createname(tp, dp, name, namelen, ip->i_ino, |
| 1974 | &first_block, &free_list, | 1990 | &first_block, &free_list, resblks ? |
| 1975 | resblks ? resblks - XFS_IALLOC_SPACE_RES(mp) : 0); | 1991 | resblks - XFS_IALLOC_SPACE_RES(mp) : 0); |
| 1976 | if (error) { | 1992 | if (error) { |
| 1977 | ASSERT(error != ENOSPC); | 1993 | ASSERT(error != ENOSPC); |
| 1978 | goto abort_return; | 1994 | goto abort_return; |
| @@ -2026,7 +2042,7 @@ xfs_create( | |||
| 2026 | * Propagate the fact that the vnode changed after the | 2042 | * Propagate the fact that the vnode changed after the |
| 2027 | * xfs_inode locks have been released. | 2043 | * xfs_inode locks have been released. |
| 2028 | */ | 2044 | */ |
| 2029 | VOP_VNODE_CHANGE(vp, VCHANGE_FLAGS_TRUNCATED, 3); | 2045 | bhv_vop_vnode_change(vp, VCHANGE_FLAGS_TRUNCATED, 3); |
| 2030 | 2046 | ||
| 2031 | *vpp = vp; | 2047 | *vpp = vp; |
| 2032 | 2048 | ||
| @@ -2107,7 +2123,7 @@ int xfs_rm_attempts; | |||
| 2107 | STATIC int | 2123 | STATIC int |
| 2108 | xfs_lock_dir_and_entry( | 2124 | xfs_lock_dir_and_entry( |
| 2109 | xfs_inode_t *dp, | 2125 | xfs_inode_t *dp, |
| 2110 | vname_t *dentry, | 2126 | bhv_vname_t *dentry, |
| 2111 | xfs_inode_t *ip) /* inode of entry 'name' */ | 2127 | xfs_inode_t *ip) /* inode of entry 'name' */ |
| 2112 | { | 2128 | { |
| 2113 | int attempts; | 2129 | int attempts; |
| @@ -2321,10 +2337,10 @@ int remove_which_error_return = 0; | |||
| 2321 | STATIC int | 2337 | STATIC int |
| 2322 | xfs_remove( | 2338 | xfs_remove( |
| 2323 | bhv_desc_t *dir_bdp, | 2339 | bhv_desc_t *dir_bdp, |
| 2324 | vname_t *dentry, | 2340 | bhv_vname_t *dentry, |
| 2325 | cred_t *credp) | 2341 | cred_t *credp) |
| 2326 | { | 2342 | { |
| 2327 | vnode_t *dir_vp; | 2343 | bhv_vnode_t *dir_vp; |
| 2328 | char *name = VNAME(dentry); | 2344 | char *name = VNAME(dentry); |
| 2329 | xfs_inode_t *dp, *ip; | 2345 | xfs_inode_t *dp, *ip; |
| 2330 | xfs_trans_t *tp = NULL; | 2346 | xfs_trans_t *tp = NULL; |
| @@ -2448,8 +2464,8 @@ xfs_remove( | |||
| 2448 | * Entry must exist since we did a lookup in xfs_lock_dir_and_entry. | 2464 | * Entry must exist since we did a lookup in xfs_lock_dir_and_entry. |
| 2449 | */ | 2465 | */ |
| 2450 | XFS_BMAP_INIT(&free_list, &first_block); | 2466 | XFS_BMAP_INIT(&free_list, &first_block); |
| 2451 | error = XFS_DIR_REMOVENAME(mp, tp, dp, name, namelen, ip->i_ino, | 2467 | error = xfs_dir_removename(tp, dp, name, namelen, ip->i_ino, |
| 2452 | &first_block, &free_list, 0); | 2468 | &first_block, &free_list, 0); |
| 2453 | if (error) { | 2469 | if (error) { |
| 2454 | ASSERT(error != ENOENT); | 2470 | ASSERT(error != ENOENT); |
| 2455 | REMOVE_DEBUG_TRACE(__LINE__); | 2471 | REMOVE_DEBUG_TRACE(__LINE__); |
| @@ -2511,7 +2527,7 @@ xfs_remove( | |||
| 2511 | /* | 2527 | /* |
| 2512 | * Let interposed file systems know about removed links. | 2528 | * Let interposed file systems know about removed links. |
| 2513 | */ | 2529 | */ |
| 2514 | VOP_LINK_REMOVED(XFS_ITOV(ip), dir_vp, link_zero); | 2530 | bhv_vop_link_removed(XFS_ITOV(ip), dir_vp, link_zero); |
| 2515 | 2531 | ||
| 2516 | IRELE(ip); | 2532 | IRELE(ip); |
| 2517 | 2533 | ||
| @@ -2564,8 +2580,8 @@ xfs_remove( | |||
| 2564 | STATIC int | 2580 | STATIC int |
| 2565 | xfs_link( | 2581 | xfs_link( |
| 2566 | bhv_desc_t *target_dir_bdp, | 2582 | bhv_desc_t *target_dir_bdp, |
| 2567 | vnode_t *src_vp, | 2583 | bhv_vnode_t *src_vp, |
| 2568 | vname_t *dentry, | 2584 | bhv_vname_t *dentry, |
| 2569 | cred_t *credp) | 2585 | cred_t *credp) |
| 2570 | { | 2586 | { |
| 2571 | xfs_inode_t *tdp, *sip; | 2587 | xfs_inode_t *tdp, *sip; |
| @@ -2577,7 +2593,7 @@ xfs_link( | |||
| 2577 | xfs_fsblock_t first_block; | 2593 | xfs_fsblock_t first_block; |
| 2578 | int cancel_flags; | 2594 | int cancel_flags; |
| 2579 | int committed; | 2595 | int committed; |
| 2580 | vnode_t *target_dir_vp; | 2596 | bhv_vnode_t *target_dir_vp; |
| 2581 | int resblks; | 2597 | int resblks; |
| 2582 | char *target_name = VNAME(dentry); | 2598 | char *target_name = VNAME(dentry); |
| 2583 | int target_namelen; | 2599 | int target_namelen; |
| @@ -2668,13 +2684,12 @@ xfs_link( | |||
| 2668 | } | 2684 | } |
| 2669 | 2685 | ||
| 2670 | if (resblks == 0 && | 2686 | if (resblks == 0 && |
| 2671 | (error = XFS_DIR_CANENTER(mp, tp, tdp, target_name, | 2687 | (error = xfs_dir_canenter(tp, tdp, target_name, target_namelen))) |
| 2672 | target_namelen))) | ||
| 2673 | goto error_return; | 2688 | goto error_return; |
| 2674 | 2689 | ||
| 2675 | XFS_BMAP_INIT(&free_list, &first_block); | 2690 | XFS_BMAP_INIT(&free_list, &first_block); |
| 2676 | 2691 | ||
| 2677 | error = XFS_DIR_CREATENAME(mp, tp, tdp, target_name, target_namelen, | 2692 | error = xfs_dir_createname(tp, tdp, target_name, target_namelen, |
| 2678 | sip->i_ino, &first_block, &free_list, | 2693 | sip->i_ino, &first_block, &free_list, |
| 2679 | resblks); | 2694 | resblks); |
| 2680 | if (error) | 2695 | if (error) |
| @@ -2734,15 +2749,15 @@ std_return: | |||
| 2734 | STATIC int | 2749 | STATIC int |
| 2735 | xfs_mkdir( | 2750 | xfs_mkdir( |
| 2736 | bhv_desc_t *dir_bdp, | 2751 | bhv_desc_t *dir_bdp, |
| 2737 | vname_t *dentry, | 2752 | bhv_vname_t *dentry, |
| 2738 | vattr_t *vap, | 2753 | bhv_vattr_t *vap, |
| 2739 | vnode_t **vpp, | 2754 | bhv_vnode_t **vpp, |
| 2740 | cred_t *credp) | 2755 | cred_t *credp) |
| 2741 | { | 2756 | { |
| 2742 | char *dir_name = VNAME(dentry); | 2757 | char *dir_name = VNAME(dentry); |
| 2743 | xfs_inode_t *dp; | 2758 | xfs_inode_t *dp; |
| 2744 | xfs_inode_t *cdp; /* inode of created dir */ | 2759 | xfs_inode_t *cdp; /* inode of created dir */ |
| 2745 | vnode_t *cvp; /* vnode of created dir */ | 2760 | bhv_vnode_t *cvp; /* vnode of created dir */ |
| 2746 | xfs_trans_t *tp; | 2761 | xfs_trans_t *tp; |
| 2747 | xfs_mount_t *mp; | 2762 | xfs_mount_t *mp; |
| 2748 | int cancel_flags; | 2763 | int cancel_flags; |
| @@ -2750,7 +2765,7 @@ xfs_mkdir( | |||
| 2750 | int committed; | 2765 | int committed; |
| 2751 | xfs_bmap_free_t free_list; | 2766 | xfs_bmap_free_t free_list; |
| 2752 | xfs_fsblock_t first_block; | 2767 | xfs_fsblock_t first_block; |
| 2753 | vnode_t *dir_vp; | 2768 | bhv_vnode_t *dir_vp; |
| 2754 | boolean_t dp_joined_to_trans; | 2769 | boolean_t dp_joined_to_trans; |
| 2755 | boolean_t created = B_FALSE; | 2770 | boolean_t created = B_FALSE; |
| 2756 | int dm_event_sent = 0; | 2771 | int dm_event_sent = 0; |
| @@ -2840,7 +2855,7 @@ xfs_mkdir( | |||
| 2840 | goto error_return; | 2855 | goto error_return; |
| 2841 | 2856 | ||
| 2842 | if (resblks == 0 && | 2857 | if (resblks == 0 && |
| 2843 | (error = XFS_DIR_CANENTER(mp, tp, dp, dir_name, dir_namelen))) | 2858 | (error = xfs_dir_canenter(tp, dp, dir_name, dir_namelen))) |
| 2844 | goto error_return; | 2859 | goto error_return; |
| 2845 | /* | 2860 | /* |
| 2846 | * create the directory inode. | 2861 | * create the directory inode. |
| @@ -2867,9 +2882,9 @@ xfs_mkdir( | |||
| 2867 | 2882 | ||
| 2868 | XFS_BMAP_INIT(&free_list, &first_block); | 2883 | XFS_BMAP_INIT(&free_list, &first_block); |
| 2869 | 2884 | ||
| 2870 | error = XFS_DIR_CREATENAME(mp, tp, dp, dir_name, dir_namelen, | 2885 | error = xfs_dir_createname(tp, dp, dir_name, dir_namelen, cdp->i_ino, |
| 2871 | cdp->i_ino, &first_block, &free_list, | 2886 | &first_block, &free_list, resblks ? |
| 2872 | resblks ? resblks - XFS_IALLOC_SPACE_RES(mp) : 0); | 2887 | resblks - XFS_IALLOC_SPACE_RES(mp) : 0); |
| 2873 | if (error) { | 2888 | if (error) { |
| 2874 | ASSERT(error != ENOSPC); | 2889 | ASSERT(error != ENOSPC); |
| 2875 | goto error1; | 2890 | goto error1; |
| @@ -2883,16 +2898,14 @@ xfs_mkdir( | |||
| 2883 | */ | 2898 | */ |
| 2884 | dp->i_gen++; | 2899 | dp->i_gen++; |
| 2885 | 2900 | ||
| 2886 | error = XFS_DIR_INIT(mp, tp, cdp, dp); | 2901 | error = xfs_dir_init(tp, cdp, dp); |
| 2887 | if (error) { | 2902 | if (error) |
| 2888 | goto error2; | 2903 | goto error2; |
| 2889 | } | ||
| 2890 | 2904 | ||
| 2891 | cdp->i_gen = 1; | 2905 | cdp->i_gen = 1; |
| 2892 | error = xfs_bumplink(tp, dp); | 2906 | error = xfs_bumplink(tp, dp); |
| 2893 | if (error) { | 2907 | if (error) |
| 2894 | goto error2; | 2908 | goto error2; |
| 2895 | } | ||
| 2896 | 2909 | ||
| 2897 | cvp = XFS_ITOV(cdp); | 2910 | cvp = XFS_ITOV(cdp); |
| 2898 | 2911 | ||
| @@ -2969,7 +2982,7 @@ std_return: | |||
| 2969 | STATIC int | 2982 | STATIC int |
| 2970 | xfs_rmdir( | 2983 | xfs_rmdir( |
| 2971 | bhv_desc_t *dir_bdp, | 2984 | bhv_desc_t *dir_bdp, |
| 2972 | vname_t *dentry, | 2985 | bhv_vname_t *dentry, |
| 2973 | cred_t *credp) | 2986 | cred_t *credp) |
| 2974 | { | 2987 | { |
| 2975 | char *name = VNAME(dentry); | 2988 | char *name = VNAME(dentry); |
| @@ -2982,7 +2995,7 @@ xfs_rmdir( | |||
| 2982 | xfs_fsblock_t first_block; | 2995 | xfs_fsblock_t first_block; |
| 2983 | int cancel_flags; | 2996 | int cancel_flags; |
| 2984 | int committed; | 2997 | int committed; |
| 2985 | vnode_t *dir_vp; | 2998 | bhv_vnode_t *dir_vp; |
| 2986 | int dm_di_mode = 0; | 2999 | int dm_di_mode = 0; |
| 2987 | int last_cdp_link; | 3000 | int last_cdp_link; |
| 2988 | int namelen; | 3001 | int namelen; |
| @@ -3101,16 +3114,15 @@ xfs_rmdir( | |||
| 3101 | error = XFS_ERROR(ENOTEMPTY); | 3114 | error = XFS_ERROR(ENOTEMPTY); |
| 3102 | goto error_return; | 3115 | goto error_return; |
| 3103 | } | 3116 | } |
| 3104 | if (!XFS_DIR_ISEMPTY(mp, cdp)) { | 3117 | if (!xfs_dir_isempty(cdp)) { |
| 3105 | error = XFS_ERROR(ENOTEMPTY); | 3118 | error = XFS_ERROR(ENOTEMPTY); |
| 3106 | goto error_return; | 3119 | goto error_return; |
| 3107 | } | 3120 | } |
| 3108 | 3121 | ||
| 3109 | error = XFS_DIR_REMOVENAME(mp, tp, dp, name, namelen, cdp->i_ino, | 3122 | error = xfs_dir_removename(tp, dp, name, namelen, cdp->i_ino, |
| 3110 | &first_block, &free_list, resblks); | 3123 | &first_block, &free_list, resblks); |
| 3111 | if (error) { | 3124 | if (error) |
| 3112 | goto error1; | 3125 | goto error1; |
| 3113 | } | ||
| 3114 | 3126 | ||
| 3115 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 3127 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 3116 | 3128 | ||
| @@ -3181,7 +3193,7 @@ xfs_rmdir( | |||
| 3181 | /* | 3193 | /* |
| 3182 | * Let interposed file systems know about removed links. | 3194 | * Let interposed file systems know about removed links. |
| 3183 | */ | 3195 | */ |
| 3184 | VOP_LINK_REMOVED(XFS_ITOV(cdp), dir_vp, last_cdp_link); | 3196 | bhv_vop_link_removed(XFS_ITOV(cdp), dir_vp, last_cdp_link); |
| 3185 | 3197 | ||
| 3186 | IRELE(cdp); | 3198 | IRELE(cdp); |
| 3187 | 3199 | ||
| @@ -3209,8 +3221,6 @@ xfs_rmdir( | |||
| 3209 | 3221 | ||
| 3210 | 3222 | ||
| 3211 | /* | 3223 | /* |
| 3212 | * xfs_readdir | ||
| 3213 | * | ||
| 3214 | * Read dp's entries starting at uiop->uio_offset and translate them into | 3224 | * Read dp's entries starting at uiop->uio_offset and translate them into |
| 3215 | * bufsize bytes worth of struct dirents starting at bufbase. | 3225 | * bufsize bytes worth of struct dirents starting at bufbase. |
| 3216 | */ | 3226 | */ |
| @@ -3230,28 +3240,23 @@ xfs_readdir( | |||
| 3230 | (inst_t *)__return_address); | 3240 | (inst_t *)__return_address); |
| 3231 | dp = XFS_BHVTOI(dir_bdp); | 3241 | dp = XFS_BHVTOI(dir_bdp); |
| 3232 | 3242 | ||
| 3233 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) { | 3243 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) |
| 3234 | return XFS_ERROR(EIO); | 3244 | return XFS_ERROR(EIO); |
| 3235 | } | ||
| 3236 | 3245 | ||
| 3237 | lock_mode = xfs_ilock_map_shared(dp); | 3246 | lock_mode = xfs_ilock_map_shared(dp); |
| 3238 | error = XFS_DIR_GETDENTS(dp->i_mount, tp, dp, uiop, eofp); | 3247 | error = xfs_dir_getdents(tp, dp, uiop, eofp); |
| 3239 | xfs_iunlock_map_shared(dp, lock_mode); | 3248 | xfs_iunlock_map_shared(dp, lock_mode); |
| 3240 | return error; | 3249 | return error; |
| 3241 | } | 3250 | } |
| 3242 | 3251 | ||
| 3243 | 3252 | ||
| 3244 | /* | ||
| 3245 | * xfs_symlink | ||
| 3246 | * | ||
| 3247 | */ | ||
| 3248 | STATIC int | 3253 | STATIC int |
| 3249 | xfs_symlink( | 3254 | xfs_symlink( |
| 3250 | bhv_desc_t *dir_bdp, | 3255 | bhv_desc_t *dir_bdp, |
| 3251 | vname_t *dentry, | 3256 | bhv_vname_t *dentry, |
| 3252 | vattr_t *vap, | 3257 | bhv_vattr_t *vap, |
| 3253 | char *target_path, | 3258 | char *target_path, |
| 3254 | vnode_t **vpp, | 3259 | bhv_vnode_t **vpp, |
| 3255 | cred_t *credp) | 3260 | cred_t *credp) |
| 3256 | { | 3261 | { |
| 3257 | xfs_trans_t *tp; | 3262 | xfs_trans_t *tp; |
| @@ -3263,7 +3268,7 @@ xfs_symlink( | |||
| 3263 | xfs_bmap_free_t free_list; | 3268 | xfs_bmap_free_t free_list; |
| 3264 | xfs_fsblock_t first_block; | 3269 | xfs_fsblock_t first_block; |
| 3265 | boolean_t dp_joined_to_trans; | 3270 | boolean_t dp_joined_to_trans; |
| 3266 | vnode_t *dir_vp; | 3271 | bhv_vnode_t *dir_vp; |
| 3267 | uint cancel_flags; | 3272 | uint cancel_flags; |
| 3268 | int committed; | 3273 | int committed; |
| 3269 | xfs_fileoff_t first_fsb; | 3274 | xfs_fileoff_t first_fsb; |
| @@ -3308,7 +3313,7 @@ xfs_symlink( | |||
| 3308 | int len, total; | 3313 | int len, total; |
| 3309 | char *path; | 3314 | char *path; |
| 3310 | 3315 | ||
| 3311 | for(total = 0, path = target_path; total < pathlen;) { | 3316 | for (total = 0, path = target_path; total < pathlen;) { |
| 3312 | /* | 3317 | /* |
| 3313 | * Skip any slashes. | 3318 | * Skip any slashes. |
| 3314 | */ | 3319 | */ |
| @@ -3402,7 +3407,7 @@ xfs_symlink( | |||
| 3402 | * Check for ability to enter directory entry, if no space reserved. | 3407 | * Check for ability to enter directory entry, if no space reserved. |
| 3403 | */ | 3408 | */ |
| 3404 | if (resblks == 0 && | 3409 | if (resblks == 0 && |
| 3405 | (error = XFS_DIR_CANENTER(mp, tp, dp, link_name, link_namelen))) | 3410 | (error = xfs_dir_canenter(tp, dp, link_name, link_namelen))) |
| 3406 | goto error_return; | 3411 | goto error_return; |
| 3407 | /* | 3412 | /* |
| 3408 | * Initialize the bmap freelist prior to calling either | 3413 | * Initialize the bmap freelist prior to calling either |
| @@ -3457,7 +3462,7 @@ xfs_symlink( | |||
| 3457 | error = xfs_bmapi(tp, ip, first_fsb, fs_blocks, | 3462 | error = xfs_bmapi(tp, ip, first_fsb, fs_blocks, |
| 3458 | XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, | 3463 | XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, |
| 3459 | &first_block, resblks, mval, &nmaps, | 3464 | &first_block, resblks, mval, &nmaps, |
| 3460 | &free_list); | 3465 | &free_list, NULL); |
| 3461 | if (error) { | 3466 | if (error) { |
| 3462 | goto error1; | 3467 | goto error1; |
| 3463 | } | 3468 | } |
| @@ -3489,11 +3494,10 @@ xfs_symlink( | |||
| 3489 | /* | 3494 | /* |
| 3490 | * Create the directory entry for the symlink. | 3495 | * Create the directory entry for the symlink. |
| 3491 | */ | 3496 | */ |
| 3492 | error = XFS_DIR_CREATENAME(mp, tp, dp, link_name, link_namelen, | 3497 | error = xfs_dir_createname(tp, dp, link_name, link_namelen, ip->i_ino, |
| 3493 | ip->i_ino, &first_block, &free_list, resblks); | 3498 | &first_block, &free_list, resblks); |
| 3494 | if (error) { | 3499 | if (error) |
| 3495 | goto error1; | 3500 | goto error1; |
| 3496 | } | ||
| 3497 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 3501 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 3498 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | 3502 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); |
| 3499 | 3503 | ||
| @@ -3541,7 +3545,7 @@ std_return: | |||
| 3541 | } | 3545 | } |
| 3542 | 3546 | ||
| 3543 | if (!error) { | 3547 | if (!error) { |
| 3544 | vnode_t *vp; | 3548 | bhv_vnode_t *vp; |
| 3545 | 3549 | ||
| 3546 | ASSERT(ip); | 3550 | ASSERT(ip); |
| 3547 | vp = XFS_ITOV(ip); | 3551 | vp = XFS_ITOV(ip); |
| @@ -3606,10 +3610,10 @@ xfs_fid2( | |||
| 3606 | int | 3610 | int |
| 3607 | xfs_rwlock( | 3611 | xfs_rwlock( |
| 3608 | bhv_desc_t *bdp, | 3612 | bhv_desc_t *bdp, |
| 3609 | vrwlock_t locktype) | 3613 | bhv_vrwlock_t locktype) |
| 3610 | { | 3614 | { |
| 3611 | xfs_inode_t *ip; | 3615 | xfs_inode_t *ip; |
| 3612 | vnode_t *vp; | 3616 | bhv_vnode_t *vp; |
| 3613 | 3617 | ||
| 3614 | vp = BHV_TO_VNODE(bdp); | 3618 | vp = BHV_TO_VNODE(bdp); |
| 3615 | if (VN_ISDIR(vp)) | 3619 | if (VN_ISDIR(vp)) |
| @@ -3637,10 +3641,10 @@ xfs_rwlock( | |||
| 3637 | void | 3641 | void |
| 3638 | xfs_rwunlock( | 3642 | xfs_rwunlock( |
| 3639 | bhv_desc_t *bdp, | 3643 | bhv_desc_t *bdp, |
| 3640 | vrwlock_t locktype) | 3644 | bhv_vrwlock_t locktype) |
| 3641 | { | 3645 | { |
| 3642 | xfs_inode_t *ip; | 3646 | xfs_inode_t *ip; |
| 3643 | vnode_t *vp; | 3647 | bhv_vnode_t *vp; |
| 3644 | 3648 | ||
| 3645 | vp = BHV_TO_VNODE(bdp); | 3649 | vp = BHV_TO_VNODE(bdp); |
| 3646 | if (VN_ISDIR(vp)) | 3650 | if (VN_ISDIR(vp)) |
| @@ -3744,7 +3748,6 @@ xfs_inode_flush( | |||
| 3744 | return error; | 3748 | return error; |
| 3745 | } | 3749 | } |
| 3746 | 3750 | ||
| 3747 | |||
| 3748 | int | 3751 | int |
| 3749 | xfs_set_dmattrs ( | 3752 | xfs_set_dmattrs ( |
| 3750 | bhv_desc_t *bdp, | 3753 | bhv_desc_t *bdp, |
| @@ -3785,16 +3788,12 @@ xfs_set_dmattrs ( | |||
| 3785 | return error; | 3788 | return error; |
| 3786 | } | 3789 | } |
| 3787 | 3790 | ||
| 3788 | |||
| 3789 | /* | ||
| 3790 | * xfs_reclaim | ||
| 3791 | */ | ||
| 3792 | STATIC int | 3791 | STATIC int |
| 3793 | xfs_reclaim( | 3792 | xfs_reclaim( |
| 3794 | bhv_desc_t *bdp) | 3793 | bhv_desc_t *bdp) |
| 3795 | { | 3794 | { |
| 3796 | xfs_inode_t *ip; | 3795 | xfs_inode_t *ip; |
| 3797 | vnode_t *vp; | 3796 | bhv_vnode_t *vp; |
| 3798 | 3797 | ||
| 3799 | vp = BHV_TO_VNODE(bdp); | 3798 | vp = BHV_TO_VNODE(bdp); |
| 3800 | ip = XFS_BHVTOI(bdp); | 3799 | ip = XFS_BHVTOI(bdp); |
| @@ -3849,7 +3848,7 @@ xfs_finish_reclaim( | |||
| 3849 | int sync_mode) | 3848 | int sync_mode) |
| 3850 | { | 3849 | { |
| 3851 | xfs_ihash_t *ih = ip->i_hash; | 3850 | xfs_ihash_t *ih = ip->i_hash; |
| 3852 | vnode_t *vp = XFS_ITOV_NULL(ip); | 3851 | bhv_vnode_t *vp = XFS_ITOV_NULL(ip); |
| 3853 | int error; | 3852 | int error; |
| 3854 | 3853 | ||
| 3855 | if (vp && VN_BAD(vp)) | 3854 | if (vp && VN_BAD(vp)) |
| @@ -4116,10 +4115,10 @@ retry: | |||
| 4116 | * Issue the xfs_bmapi() call to allocate the blocks | 4115 | * Issue the xfs_bmapi() call to allocate the blocks |
| 4117 | */ | 4116 | */ |
| 4118 | XFS_BMAP_INIT(&free_list, &firstfsb); | 4117 | XFS_BMAP_INIT(&free_list, &firstfsb); |
| 4119 | error = xfs_bmapi(tp, ip, startoffset_fsb, | 4118 | error = XFS_BMAPI(mp, tp, &ip->i_iocore, startoffset_fsb, |
| 4120 | allocatesize_fsb, bmapi_flag, | 4119 | allocatesize_fsb, bmapi_flag, |
| 4121 | &firstfsb, 0, imapp, &nimaps, | 4120 | &firstfsb, 0, imapp, &nimaps, |
| 4122 | &free_list); | 4121 | &free_list, NULL); |
| 4123 | if (error) { | 4122 | if (error) { |
| 4124 | goto error0; | 4123 | goto error0; |
| 4125 | } | 4124 | } |
| @@ -4199,8 +4198,8 @@ xfs_zero_remaining_bytes( | |||
| 4199 | for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { | 4198 | for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { |
| 4200 | offset_fsb = XFS_B_TO_FSBT(mp, offset); | 4199 | offset_fsb = XFS_B_TO_FSBT(mp, offset); |
| 4201 | nimap = 1; | 4200 | nimap = 1; |
| 4202 | error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0, NULL, 0, &imap, | 4201 | error = XFS_BMAPI(mp, NULL, &ip->i_iocore, offset_fsb, 1, 0, |
| 4203 | &nimap, NULL); | 4202 | NULL, 0, &imap, &nimap, NULL, NULL); |
| 4204 | if (error || nimap < 1) | 4203 | if (error || nimap < 1) |
| 4205 | break; | 4204 | break; |
| 4206 | ASSERT(imap.br_blockcount >= 1); | 4205 | ASSERT(imap.br_blockcount >= 1); |
| @@ -4259,7 +4258,7 @@ xfs_free_file_space( | |||
| 4259 | xfs_off_t len, | 4258 | xfs_off_t len, |
| 4260 | int attr_flags) | 4259 | int attr_flags) |
| 4261 | { | 4260 | { |
| 4262 | vnode_t *vp; | 4261 | bhv_vnode_t *vp; |
| 4263 | int committed; | 4262 | int committed; |
| 4264 | int done; | 4263 | int done; |
| 4265 | xfs_off_t end_dmi_offset; | 4264 | xfs_off_t end_dmi_offset; |
| @@ -4308,7 +4307,6 @@ xfs_free_file_space( | |||
| 4308 | return error; | 4307 | return error; |
| 4309 | } | 4308 | } |
| 4310 | 4309 | ||
| 4311 | ASSERT(attr_flags & ATTR_NOLOCK ? attr_flags & ATTR_DMI : 1); | ||
| 4312 | if (attr_flags & ATTR_NOLOCK) | 4310 | if (attr_flags & ATTR_NOLOCK) |
| 4313 | need_iolock = 0; | 4311 | need_iolock = 0; |
| 4314 | if (need_iolock) { | 4312 | if (need_iolock) { |
| @@ -4326,7 +4324,7 @@ xfs_free_file_space( | |||
| 4326 | if (VN_CACHED(vp) != 0) { | 4324 | if (VN_CACHED(vp) != 0) { |
| 4327 | xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1, | 4325 | xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1, |
| 4328 | ctooff(offtoct(ioffset)), -1); | 4326 | ctooff(offtoct(ioffset)), -1); |
| 4329 | VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(ioffset)), | 4327 | bhv_vop_flushinval_pages(vp, ctooff(offtoct(ioffset)), |
| 4330 | -1, FI_REMAPF_LOCKED); | 4328 | -1, FI_REMAPF_LOCKED); |
| 4331 | } | 4329 | } |
| 4332 | 4330 | ||
| @@ -4338,8 +4336,8 @@ xfs_free_file_space( | |||
| 4338 | */ | 4336 | */ |
| 4339 | if (rt && !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { | 4337 | if (rt && !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { |
| 4340 | nimap = 1; | 4338 | nimap = 1; |
| 4341 | error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0, | 4339 | error = XFS_BMAPI(mp, NULL, &ip->i_iocore, startoffset_fsb, |
| 4342 | &imap, &nimap, NULL); | 4340 | 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); |
| 4343 | if (error) | 4341 | if (error) |
| 4344 | goto out_unlock_iolock; | 4342 | goto out_unlock_iolock; |
| 4345 | ASSERT(nimap == 0 || nimap == 1); | 4343 | ASSERT(nimap == 0 || nimap == 1); |
| @@ -4353,8 +4351,8 @@ xfs_free_file_space( | |||
| 4353 | startoffset_fsb += mp->m_sb.sb_rextsize - mod; | 4351 | startoffset_fsb += mp->m_sb.sb_rextsize - mod; |
| 4354 | } | 4352 | } |
| 4355 | nimap = 1; | 4353 | nimap = 1; |
| 4356 | error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, 1, 0, NULL, 0, | 4354 | error = XFS_BMAPI(mp, NULL, &ip->i_iocore, endoffset_fsb - 1, |
| 4357 | &imap, &nimap, NULL); | 4355 | 1, 0, NULL, 0, &imap, &nimap, NULL, NULL); |
| 4358 | if (error) | 4356 | if (error) |
| 4359 | goto out_unlock_iolock; | 4357 | goto out_unlock_iolock; |
| 4360 | ASSERT(nimap == 0 || nimap == 1); | 4358 | ASSERT(nimap == 0 || nimap == 1); |
| @@ -4426,9 +4424,9 @@ xfs_free_file_space( | |||
| 4426 | * issue the bunmapi() call to free the blocks | 4424 | * issue the bunmapi() call to free the blocks |
| 4427 | */ | 4425 | */ |
| 4428 | XFS_BMAP_INIT(&free_list, &firstfsb); | 4426 | XFS_BMAP_INIT(&free_list, &firstfsb); |
| 4429 | error = xfs_bunmapi(tp, ip, startoffset_fsb, | 4427 | error = XFS_BUNMAPI(mp, tp, &ip->i_iocore, startoffset_fsb, |
| 4430 | endoffset_fsb - startoffset_fsb, | 4428 | endoffset_fsb - startoffset_fsb, |
| 4431 | 0, 2, &firstfsb, &free_list, &done); | 4429 | 0, 2, &firstfsb, &free_list, NULL, &done); |
| 4432 | if (error) { | 4430 | if (error) { |
| 4433 | goto error0; | 4431 | goto error0; |
| 4434 | } | 4432 | } |
| @@ -4488,8 +4486,8 @@ xfs_change_file_space( | |||
| 4488 | xfs_off_t startoffset; | 4486 | xfs_off_t startoffset; |
| 4489 | xfs_off_t llen; | 4487 | xfs_off_t llen; |
| 4490 | xfs_trans_t *tp; | 4488 | xfs_trans_t *tp; |
| 4491 | vattr_t va; | 4489 | bhv_vattr_t va; |
| 4492 | vnode_t *vp; | 4490 | bhv_vnode_t *vp; |
| 4493 | 4491 | ||
| 4494 | vp = BHV_TO_VNODE(bdp); | 4492 | vp = BHV_TO_VNODE(bdp); |
| 4495 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); | 4493 | vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address); |
| @@ -4642,9 +4640,10 @@ xfs_change_file_space( | |||
| 4642 | return error; | 4640 | return error; |
| 4643 | } | 4641 | } |
| 4644 | 4642 | ||
| 4645 | vnodeops_t xfs_vnodeops = { | 4643 | bhv_vnodeops_t xfs_vnodeops = { |
| 4646 | BHV_IDENTITY_INIT(VN_BHV_XFS,VNODE_POSITION_XFS), | 4644 | BHV_IDENTITY_INIT(VN_BHV_XFS,VNODE_POSITION_XFS), |
| 4647 | .vop_open = xfs_open, | 4645 | .vop_open = xfs_open, |
| 4646 | .vop_close = xfs_close, | ||
| 4648 | .vop_read = xfs_read, | 4647 | .vop_read = xfs_read, |
| 4649 | #ifdef HAVE_SENDFILE | 4648 | #ifdef HAVE_SENDFILE |
| 4650 | .vop_sendfile = xfs_sendfile, | 4649 | .vop_sendfile = xfs_sendfile, |
diff --git a/include/asm-alpha/vga.h b/include/asm-alpha/vga.h index 8ca4f6b2da19..ed06f59b544d 100644 --- a/include/asm-alpha/vga.h +++ b/include/asm-alpha/vga.h | |||
| @@ -46,6 +46,6 @@ extern void scr_memcpyw(u16 *d, const u16 *s, unsigned int count); | |||
| 46 | #define vga_readb(a) readb((u8 __iomem *)(a)) | 46 | #define vga_readb(a) readb((u8 __iomem *)(a)) |
| 47 | #define vga_writeb(v,a) writeb(v, (u8 __iomem *)(a)) | 47 | #define vga_writeb(v,a) writeb(v, (u8 __iomem *)(a)) |
| 48 | 48 | ||
| 49 | #define VGA_MAP_MEM(x) ((unsigned long) ioremap(x, 0)) | 49 | #define VGA_MAP_MEM(x,s) ((unsigned long) ioremap(x, s)) |
| 50 | 50 | ||
| 51 | #endif | 51 | #endif |
diff --git a/include/asm-arm/vga.h b/include/asm-arm/vga.h index 926e5ee128e9..1e0b913c3d71 100644 --- a/include/asm-arm/vga.h +++ b/include/asm-arm/vga.h | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | #include <asm/hardware.h> | 4 | #include <asm/hardware.h> |
| 5 | #include <asm/io.h> | 5 | #include <asm/io.h> |
| 6 | 6 | ||
| 7 | #define VGA_MAP_MEM(x) (PCIMEM_BASE + (x)) | 7 | #define VGA_MAP_MEM(x,s) (PCIMEM_BASE + (x)) |
| 8 | 8 | ||
| 9 | #define vga_readb(x) (*((volatile unsigned char *)x)) | 9 | #define vga_readb(x) (*((volatile unsigned char *)x)) |
| 10 | #define vga_writeb(x,y) (*((volatile unsigned char *)y) = (x)) | 10 | #define vga_writeb(x,y) (*((volatile unsigned char *)y) = (x)) |
diff --git a/include/asm-i386/vga.h b/include/asm-i386/vga.h index ef0c0e50cc95..0ecf68ac03aa 100644 --- a/include/asm-i386/vga.h +++ b/include/asm-i386/vga.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | * access the videoram directly without any black magic. | 12 | * access the videoram directly without any black magic. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) | 15 | #define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) |
| 16 | 16 | ||
| 17 | #define vga_readb(x) (*(x)) | 17 | #define vga_readb(x) (*(x)) |
| 18 | #define vga_writeb(x,y) (*(y) = (x)) | 18 | #define vga_writeb(x,y) (*(y) = (x)) |
diff --git a/include/asm-ia64/vga.h b/include/asm-ia64/vga.h index 091177cda223..02184ecd8208 100644 --- a/include/asm-ia64/vga.h +++ b/include/asm-ia64/vga.h | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | extern unsigned long vga_console_iobase; | 17 | extern unsigned long vga_console_iobase; |
| 18 | extern unsigned long vga_console_membase; | 18 | extern unsigned long vga_console_membase; |
| 19 | 19 | ||
| 20 | #define VGA_MAP_MEM(x) ((unsigned long) ioremap_nocache(vga_console_membase + (x), 0)) | 20 | #define VGA_MAP_MEM(x,s) ((unsigned long) ioremap_nocache(vga_console_membase + (x), s)) |
| 21 | 21 | ||
| 22 | #define vga_readb(x) (*(x)) | 22 | #define vga_readb(x) (*(x)) |
| 23 | #define vga_writeb(x,y) (*(y) = (x)) | 23 | #define vga_writeb(x,y) (*(y) = (x)) |
diff --git a/include/asm-m32r/vga.h b/include/asm-m32r/vga.h index d0f4b6eed7a3..533163447cc9 100644 --- a/include/asm-m32r/vga.h +++ b/include/asm-m32r/vga.h | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | * access the videoram directly without any black magic. | 14 | * access the videoram directly without any black magic. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) | 17 | #define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) |
| 18 | 18 | ||
| 19 | #define vga_readb(x) (*(x)) | 19 | #define vga_readb(x) (*(x)) |
| 20 | #define vga_writeb(x,y) (*(y) = (x)) | 20 | #define vga_writeb(x,y) (*(y) = (x)) |
diff --git a/include/asm-mips/vga.h b/include/asm-mips/vga.h index 34755c0a6398..c1dd0b10bc27 100644 --- a/include/asm-mips/vga.h +++ b/include/asm-mips/vga.h | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | * access the videoram directly without any black magic. | 13 | * access the videoram directly without any black magic. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #define VGA_MAP_MEM(x) (0xb0000000L + (unsigned long)(x)) | 16 | #define VGA_MAP_MEM(x,s) (0xb0000000L + (unsigned long)(x)) |
| 17 | 17 | ||
| 18 | #define vga_readb(x) (*(x)) | 18 | #define vga_readb(x) (*(x)) |
| 19 | #define vga_writeb(x,y) (*(y) = (x)) | 19 | #define vga_writeb(x,y) (*(y) = (x)) |
diff --git a/include/asm-powerpc/vga.h b/include/asm-powerpc/vga.h index eadaf2f3d032..a2eac409c1ec 100644 --- a/include/asm-powerpc/vga.h +++ b/include/asm-powerpc/vga.h | |||
| @@ -41,9 +41,9 @@ static inline u16 scr_readw(volatile const u16 *addr) | |||
| 41 | extern unsigned long vgacon_remap_base; | 41 | extern unsigned long vgacon_remap_base; |
| 42 | 42 | ||
| 43 | #ifdef __powerpc64__ | 43 | #ifdef __powerpc64__ |
| 44 | #define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0)) | 44 | #define VGA_MAP_MEM(x,s) ((unsigned long) ioremap((x), s)) |
| 45 | #else | 45 | #else |
| 46 | #define VGA_MAP_MEM(x) (x + vgacon_remap_base) | 46 | #define VGA_MAP_MEM(x,s) (x + vgacon_remap_base) |
| 47 | #endif | 47 | #endif |
| 48 | 48 | ||
| 49 | #define vga_readb(x) (*(x)) | 49 | #define vga_readb(x) (*(x)) |
diff --git a/include/asm-sparc64/vga.h b/include/asm-sparc64/vga.h index 9c57eb363b40..c69d5b2ba19a 100644 --- a/include/asm-sparc64/vga.h +++ b/include/asm-sparc64/vga.h | |||
| @@ -28,6 +28,6 @@ static inline u16 scr_readw(const u16 *addr) | |||
| 28 | return *addr; | 28 | return *addr; |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | #define VGA_MAP_MEM(x) (x) | 31 | #define VGA_MAP_MEM(x,s) (x) |
| 32 | 32 | ||
| 33 | #endif | 33 | #endif |
diff --git a/include/asm-x86_64/vga.h b/include/asm-x86_64/vga.h index ef0c0e50cc95..0ecf68ac03aa 100644 --- a/include/asm-x86_64/vga.h +++ b/include/asm-x86_64/vga.h | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | * access the videoram directly without any black magic. | 12 | * access the videoram directly without any black magic. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) | 15 | #define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) |
| 16 | 16 | ||
| 17 | #define vga_readb(x) (*(x)) | 17 | #define vga_readb(x) (*(x)) |
| 18 | #define vga_writeb(x,y) (*(y) = (x)) | 18 | #define vga_writeb(x,y) (*(y) = (x)) |
diff --git a/include/asm-xtensa/vga.h b/include/asm-xtensa/vga.h index 23d82f6acb57..1fd8cab3a297 100644 --- a/include/asm-xtensa/vga.h +++ b/include/asm-xtensa/vga.h | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | #ifndef _XTENSA_VGA_H | 11 | #ifndef _XTENSA_VGA_H |
| 12 | #define _XTENSA_VGA_H | 12 | #define _XTENSA_VGA_H |
| 13 | 13 | ||
| 14 | #define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x) | 14 | #define VGA_MAP_MEM(x,s) (unsigned long)phys_to_virt(x) |
| 15 | 15 | ||
| 16 | #define vga_readb(x) (*(x)) | 16 | #define vga_readb(x) (*(x)) |
| 17 | #define vga_writeb(x,y) (*(y) = (x)) | 17 | #define vga_writeb(x,y) (*(y) = (x)) |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 836325ee0931..46d0e079735d 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
| @@ -217,7 +217,7 @@ extern struct dentry * d_alloc_anon(struct inode *); | |||
| 217 | extern struct dentry * d_splice_alias(struct inode *, struct dentry *); | 217 | extern struct dentry * d_splice_alias(struct inode *, struct dentry *); |
| 218 | extern void shrink_dcache_sb(struct super_block *); | 218 | extern void shrink_dcache_sb(struct super_block *); |
| 219 | extern void shrink_dcache_parent(struct dentry *); | 219 | extern void shrink_dcache_parent(struct dentry *); |
| 220 | extern void shrink_dcache_anon(struct hlist_head *); | 220 | extern void shrink_dcache_anon(struct super_block *); |
| 221 | extern int d_invalidate(struct dentry *); | 221 | extern int d_invalidate(struct dentry *); |
| 222 | 222 | ||
| 223 | /* only used at mount-time */ | 223 | /* only used at mount-time */ |
diff --git a/include/linux/device.h b/include/linux/device.h index b2e5da2b637b..1e5f30da98bc 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
| @@ -60,11 +60,6 @@ extern void bus_unregister(struct bus_type * bus); | |||
| 60 | 60 | ||
| 61 | extern void bus_rescan_devices(struct bus_type * bus); | 61 | extern void bus_rescan_devices(struct bus_type * bus); |
| 62 | 62 | ||
| 63 | extern struct bus_type * get_bus(struct bus_type * bus); | ||
| 64 | extern void put_bus(struct bus_type * bus); | ||
| 65 | |||
| 66 | extern struct bus_type * find_bus(char * name); | ||
| 67 | |||
| 68 | /* iterator helpers for buses */ | 63 | /* iterator helpers for buses */ |
| 69 | 64 | ||
| 70 | int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, | 65 | int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, |
| @@ -147,6 +142,7 @@ struct class { | |||
| 147 | 142 | ||
| 148 | struct subsystem subsys; | 143 | struct subsystem subsys; |
| 149 | struct list_head children; | 144 | struct list_head children; |
| 145 | struct list_head devices; | ||
| 150 | struct list_head interfaces; | 146 | struct list_head interfaces; |
| 151 | struct semaphore sem; /* locks both the children and interfaces lists */ | 147 | struct semaphore sem; /* locks both the children and interfaces lists */ |
| 152 | 148 | ||
| @@ -163,9 +159,6 @@ struct class { | |||
| 163 | extern int class_register(struct class *); | 159 | extern int class_register(struct class *); |
| 164 | extern void class_unregister(struct class *); | 160 | extern void class_unregister(struct class *); |
| 165 | 161 | ||
| 166 | extern struct class * class_get(struct class *); | ||
| 167 | extern void class_put(struct class *); | ||
| 168 | |||
| 169 | 162 | ||
| 170 | struct class_attribute { | 163 | struct class_attribute { |
| 171 | struct attribute attr; | 164 | struct attribute attr; |
| @@ -313,6 +306,7 @@ struct device { | |||
| 313 | struct kobject kobj; | 306 | struct kobject kobj; |
| 314 | char bus_id[BUS_ID_SIZE]; /* position on parent bus */ | 307 | char bus_id[BUS_ID_SIZE]; /* position on parent bus */ |
| 315 | struct device_attribute uevent_attr; | 308 | struct device_attribute uevent_attr; |
| 309 | struct device_attribute *devt_attr; | ||
| 316 | 310 | ||
| 317 | struct semaphore sem; /* semaphore to synchronize calls to | 311 | struct semaphore sem; /* semaphore to synchronize calls to |
| 318 | * its driver. | 312 | * its driver. |
| @@ -340,6 +334,11 @@ struct device { | |||
| 340 | struct dma_coherent_mem *dma_mem; /* internal for coherent mem | 334 | struct dma_coherent_mem *dma_mem; /* internal for coherent mem |
| 341 | override */ | 335 | override */ |
| 342 | 336 | ||
| 337 | /* class_device migration path */ | ||
| 338 | struct list_head node; | ||
| 339 | struct class *class; /* optional*/ | ||
| 340 | dev_t devt; /* dev_t, creates the sysfs "dev" */ | ||
| 341 | |||
| 343 | void (*release)(struct device * dev); | 342 | void (*release)(struct device * dev); |
| 344 | }; | 343 | }; |
| 345 | 344 | ||
| @@ -381,6 +380,13 @@ extern int device_attach(struct device * dev); | |||
| 381 | extern void driver_attach(struct device_driver * drv); | 380 | extern void driver_attach(struct device_driver * drv); |
| 382 | extern void device_reprobe(struct device *dev); | 381 | extern void device_reprobe(struct device *dev); |
| 383 | 382 | ||
| 383 | /* | ||
| 384 | * Easy functions for dynamically creating devices on the fly | ||
| 385 | */ | ||
| 386 | extern struct device *device_create(struct class *cls, struct device *parent, | ||
| 387 | dev_t devt, char *fmt, ...) | ||
| 388 | __attribute__((format(printf,4,5))); | ||
| 389 | extern void device_destroy(struct class *cls, dev_t devt); | ||
| 384 | 390 | ||
| 385 | /* | 391 | /* |
| 386 | * Platform "fixup" functions - allow the platform to have their say | 392 | * Platform "fixup" functions - allow the platform to have their say |
| @@ -410,8 +416,9 @@ extern int firmware_register(struct subsystem *); | |||
| 410 | extern void firmware_unregister(struct subsystem *); | 416 | extern void firmware_unregister(struct subsystem *); |
| 411 | 417 | ||
| 412 | /* debugging and troubleshooting/diagnostic helpers. */ | 418 | /* debugging and troubleshooting/diagnostic helpers. */ |
| 419 | extern const char *dev_driver_string(struct device *dev); | ||
| 413 | #define dev_printk(level, dev, format, arg...) \ | 420 | #define dev_printk(level, dev, format, arg...) \ |
| 414 | printk(level "%s %s: " format , (dev)->driver ? (dev)->driver->name : "" , (dev)->bus_id , ## arg) | 421 | printk(level "%s %s: " format , dev_driver_string(dev) , (dev)->bus_id , ## arg) |
| 415 | 422 | ||
| 416 | #ifdef DEBUG | 423 | #ifdef DEBUG |
| 417 | #define dev_dbg(dev, format, arg...) \ | 424 | #define dev_dbg(dev, format, arg...) \ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index ecc8c2c3d8ca..73c7d6f04b31 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -782,7 +782,6 @@ extern int setlease(struct file *, long, struct file_lock **); | |||
| 782 | extern int lease_modify(struct file_lock **, int); | 782 | extern int lease_modify(struct file_lock **, int); |
| 783 | extern int lock_may_read(struct inode *, loff_t start, unsigned long count); | 783 | extern int lock_may_read(struct inode *, loff_t start, unsigned long count); |
| 784 | extern int lock_may_write(struct inode *, loff_t start, unsigned long count); | 784 | extern int lock_may_write(struct inode *, loff_t start, unsigned long count); |
| 785 | extern void steal_locks(fl_owner_t from); | ||
| 786 | 785 | ||
| 787 | struct fasync_struct { | 786 | struct fasync_struct { |
| 788 | int magic; | 787 | int magic; |
diff --git a/include/linux/isa.h b/include/linux/isa.h new file mode 100644 index 000000000000..1b855335cb11 --- /dev/null +++ b/include/linux/isa.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | /* | ||
| 2 | * ISA bus. | ||
| 3 | */ | ||
| 4 | |||
| 5 | #ifndef __LINUX_ISA_H | ||
| 6 | #define __LINUX_ISA_H | ||
| 7 | |||
| 8 | #include <linux/device.h> | ||
| 9 | #include <linux/kernel.h> | ||
| 10 | |||
| 11 | struct isa_driver { | ||
| 12 | int (*match)(struct device *, unsigned int); | ||
| 13 | int (*probe)(struct device *, unsigned int); | ||
| 14 | int (*remove)(struct device *, unsigned int); | ||
| 15 | void (*shutdown)(struct device *, unsigned int); | ||
| 16 | int (*suspend)(struct device *, unsigned int, pm_message_t); | ||
| 17 | int (*resume)(struct device *, unsigned int); | ||
| 18 | |||
| 19 | struct device_driver driver; | ||
| 20 | struct device *devices; | ||
| 21 | }; | ||
| 22 | |||
| 23 | #define to_isa_driver(x) container_of((x), struct isa_driver, driver) | ||
| 24 | |||
| 25 | int isa_register_driver(struct isa_driver *, unsigned int); | ||
| 26 | void isa_unregister_driver(struct isa_driver *); | ||
| 27 | |||
| 28 | #endif /* __LINUX_ISA_H */ | ||
diff --git a/include/linux/key.h b/include/linux/key.h index cbf464ad9589..e81ebf910d0b 100644 --- a/include/linux/key.h +++ b/include/linux/key.h | |||
| @@ -205,6 +205,11 @@ struct key_type { | |||
| 205 | /* match a key against a description */ | 205 | /* match a key against a description */ |
| 206 | int (*match)(const struct key *key, const void *desc); | 206 | int (*match)(const struct key *key, const void *desc); |
| 207 | 207 | ||
| 208 | /* clear some of the data from a key on revokation (optional) | ||
| 209 | * - the key's semaphore will be write-locked by the caller | ||
| 210 | */ | ||
| 211 | void (*revoke)(struct key *key); | ||
| 212 | |||
| 208 | /* clear the data from a key (optional) */ | 213 | /* clear the data from a key (optional) */ |
| 209 | void (*destroy)(struct key *key); | 214 | void (*destroy)(struct key *key); |
| 210 | 215 | ||
| @@ -241,8 +246,9 @@ extern void unregister_key_type(struct key_type *ktype); | |||
| 241 | 246 | ||
| 242 | extern struct key *key_alloc(struct key_type *type, | 247 | extern struct key *key_alloc(struct key_type *type, |
| 243 | const char *desc, | 248 | const char *desc, |
| 244 | uid_t uid, gid_t gid, key_perm_t perm, | 249 | uid_t uid, gid_t gid, |
| 245 | int not_in_quota); | 250 | struct task_struct *ctx, |
| 251 | key_perm_t perm, int not_in_quota); | ||
| 246 | extern int key_payload_reserve(struct key *key, size_t datalen); | 252 | extern int key_payload_reserve(struct key *key, size_t datalen); |
| 247 | extern int key_instantiate_and_link(struct key *key, | 253 | extern int key_instantiate_and_link(struct key *key, |
| 248 | const void *data, | 254 | const void *data, |
| @@ -292,7 +298,9 @@ extern int key_unlink(struct key *keyring, | |||
| 292 | struct key *key); | 298 | struct key *key); |
| 293 | 299 | ||
| 294 | extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, | 300 | extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, |
| 295 | int not_in_quota, struct key *dest); | 301 | struct task_struct *ctx, |
| 302 | int not_in_quota, | ||
| 303 | struct key *dest); | ||
| 296 | 304 | ||
| 297 | extern int keyring_clear(struct key *keyring); | 305 | extern int keyring_clear(struct key *keyring); |
| 298 | 306 | ||
| @@ -313,7 +321,8 @@ extern void keyring_replace_payload(struct key *key, void *replacement); | |||
| 313 | * the userspace interface | 321 | * the userspace interface |
| 314 | */ | 322 | */ |
| 315 | extern struct key root_user_keyring, root_session_keyring; | 323 | extern struct key root_user_keyring, root_session_keyring; |
| 316 | extern int alloc_uid_keyring(struct user_struct *user); | 324 | extern int alloc_uid_keyring(struct user_struct *user, |
| 325 | struct task_struct *ctx); | ||
| 317 | extern void switch_uid_keyring(struct user_struct *new_user); | 326 | extern void switch_uid_keyring(struct user_struct *new_user); |
| 318 | extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk); | 327 | extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk); |
| 319 | extern int copy_thread_group_keys(struct task_struct *tsk); | 328 | extern int copy_thread_group_keys(struct task_struct *tsk); |
| @@ -342,7 +351,7 @@ extern void key_init(void); | |||
| 342 | #define make_key_ref(k) ({ NULL; }) | 351 | #define make_key_ref(k) ({ NULL; }) |
| 343 | #define key_ref_to_ptr(k) ({ NULL; }) | 352 | #define key_ref_to_ptr(k) ({ NULL; }) |
| 344 | #define is_key_possessed(k) 0 | 353 | #define is_key_possessed(k) 0 |
| 345 | #define alloc_uid_keyring(u) 0 | 354 | #define alloc_uid_keyring(u,c) 0 |
| 346 | #define switch_uid_keyring(u) do { } while(0) | 355 | #define switch_uid_keyring(u) do { } while(0) |
| 347 | #define __install_session_keyring(t, k) ({ NULL; }) | 356 | #define __install_session_keyring(t, k) ({ NULL; }) |
| 348 | #define copy_keys(f,t) 0 | 357 | #define copy_keys(f,t) 0 |
| @@ -355,6 +364,10 @@ extern void key_init(void); | |||
| 355 | #define key_fsgid_changed(t) do { } while(0) | 364 | #define key_fsgid_changed(t) do { } while(0) |
| 356 | #define key_init() do { } while(0) | 365 | #define key_init() do { } while(0) |
| 357 | 366 | ||
| 367 | /* Initial keyrings */ | ||
| 368 | extern struct key root_user_keyring; | ||
| 369 | extern struct key root_session_keyring; | ||
| 370 | |||
| 358 | #endif /* CONFIG_KEYS */ | 371 | #endif /* CONFIG_KEYS */ |
| 359 | #endif /* __KERNEL__ */ | 372 | #endif /* __KERNEL__ */ |
| 360 | #endif /* _LINUX_KEY_H */ | 373 | #endif /* _LINUX_KEY_H */ |
diff --git a/include/linux/kobject.h b/include/linux/kobject.h index c187c53cecd0..2d229327959e 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h | |||
| @@ -190,6 +190,8 @@ struct subsystem _varname##_subsys = { \ | |||
| 190 | 190 | ||
| 191 | /* The global /sys/kernel/ subsystem for people to chain off of */ | 191 | /* The global /sys/kernel/ subsystem for people to chain off of */ |
| 192 | extern struct subsystem kernel_subsys; | 192 | extern struct subsystem kernel_subsys; |
| 193 | /* The global /sys/hypervisor/ subsystem */ | ||
| 194 | extern struct subsystem hypervisor_subsys; | ||
| 193 | 195 | ||
| 194 | /** | 196 | /** |
| 195 | * Helpers for setting the kset of registered objects. | 197 | * Helpers for setting the kset of registered objects. |
diff --git a/include/linux/security.h b/include/linux/security.h index 4dfb1b84a9b3..47722d355532 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
| @@ -1313,7 +1313,7 @@ struct security_operations { | |||
| 1313 | 1313 | ||
| 1314 | /* key management security hooks */ | 1314 | /* key management security hooks */ |
| 1315 | #ifdef CONFIG_KEYS | 1315 | #ifdef CONFIG_KEYS |
| 1316 | int (*key_alloc)(struct key *key); | 1316 | int (*key_alloc)(struct key *key, struct task_struct *tsk); |
| 1317 | void (*key_free)(struct key *key); | 1317 | void (*key_free)(struct key *key); |
| 1318 | int (*key_permission)(key_ref_t key_ref, | 1318 | int (*key_permission)(key_ref_t key_ref, |
| 1319 | struct task_struct *context, | 1319 | struct task_struct *context, |
| @@ -3008,9 +3008,10 @@ static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid | |||
| 3008 | 3008 | ||
| 3009 | #ifdef CONFIG_KEYS | 3009 | #ifdef CONFIG_KEYS |
| 3010 | #ifdef CONFIG_SECURITY | 3010 | #ifdef CONFIG_SECURITY |
| 3011 | static inline int security_key_alloc(struct key *key) | 3011 | static inline int security_key_alloc(struct key *key, |
| 3012 | struct task_struct *tsk) | ||
| 3012 | { | 3013 | { |
| 3013 | return security_ops->key_alloc(key); | 3014 | return security_ops->key_alloc(key, tsk); |
| 3014 | } | 3015 | } |
| 3015 | 3016 | ||
| 3016 | static inline void security_key_free(struct key *key) | 3017 | static inline void security_key_free(struct key *key) |
| @@ -3027,7 +3028,8 @@ static inline int security_key_permission(key_ref_t key_ref, | |||
| 3027 | 3028 | ||
| 3028 | #else | 3029 | #else |
| 3029 | 3030 | ||
| 3030 | static inline int security_key_alloc(struct key *key) | 3031 | static inline int security_key_alloc(struct key *key, |
| 3032 | struct task_struct *tsk) | ||
| 3031 | { | 3033 | { |
| 3032 | return 0; | 3034 | return 0; |
| 3033 | } | 3035 | } |
diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h index 2a4b432e1176..166a2e58c287 100644 --- a/include/linux/sysdev.h +++ b/include/linux/sysdev.h | |||
| @@ -37,11 +37,27 @@ struct sysdev_class { | |||
| 37 | struct kset kset; | 37 | struct kset kset; |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | struct sysdev_class_attribute { | ||
| 41 | struct attribute attr; | ||
| 42 | ssize_t (*show)(struct sysdev_class *, char *); | ||
| 43 | ssize_t (*store)(struct sysdev_class *, const char *, size_t); | ||
| 44 | }; | ||
| 45 | |||
| 46 | #define SYSDEV_CLASS_ATTR(_name,_mode,_show,_store) \ | ||
| 47 | struct sysdev_class_attribute attr_##_name = { \ | ||
| 48 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
| 49 | .show = _show, \ | ||
| 50 | .store = _store, \ | ||
| 51 | }; | ||
| 52 | |||
| 40 | 53 | ||
| 41 | extern int sysdev_class_register(struct sysdev_class *); | 54 | extern int sysdev_class_register(struct sysdev_class *); |
| 42 | extern void sysdev_class_unregister(struct sysdev_class *); | 55 | extern void sysdev_class_unregister(struct sysdev_class *); |
| 43 | 56 | ||
| 44 | 57 | extern int sysdev_class_create_file(struct sysdev_class *, | |
| 58 | struct sysdev_class_attribute *); | ||
| 59 | extern void sysdev_class_remove_file(struct sysdev_class *, | ||
| 60 | struct sysdev_class_attribute *); | ||
| 45 | /** | 61 | /** |
| 46 | * Auxillary system device drivers. | 62 | * Auxillary system device drivers. |
| 47 | */ | 63 | */ |
diff --git a/include/linux/tty.h b/include/linux/tty.h index e898eeb94166..cb35ca50a0a6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
| @@ -290,7 +290,9 @@ extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc); | |||
| 290 | extern int tty_unregister_ldisc(int disc); | 290 | extern int tty_unregister_ldisc(int disc); |
| 291 | extern int tty_register_driver(struct tty_driver *driver); | 291 | extern int tty_register_driver(struct tty_driver *driver); |
| 292 | extern int tty_unregister_driver(struct tty_driver *driver); | 292 | extern int tty_unregister_driver(struct tty_driver *driver); |
| 293 | extern void tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev); | 293 | extern struct class_device *tty_register_device(struct tty_driver *driver, |
| 294 | unsigned index, | ||
| 295 | struct device *dev); | ||
| 294 | extern void tty_unregister_device(struct tty_driver *driver, unsigned index); | 296 | extern void tty_unregister_device(struct tty_driver *driver, unsigned index); |
| 295 | extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, | 297 | extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, |
| 296 | int buflen); | 298 | int buflen); |
diff --git a/include/linux/usb.h b/include/linux/usb.h index 1f492c0c7047..8dead32e7ebf 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
| @@ -40,6 +40,8 @@ struct usb_driver; | |||
| 40 | * Devices may also have class-specific or vendor-specific descriptors. | 40 | * Devices may also have class-specific or vendor-specific descriptors. |
| 41 | */ | 41 | */ |
| 42 | 42 | ||
| 43 | struct ep_device; | ||
| 44 | |||
| 43 | /** | 45 | /** |
| 44 | * struct usb_host_endpoint - host-side endpoint descriptor and queue | 46 | * struct usb_host_endpoint - host-side endpoint descriptor and queue |
| 45 | * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder | 47 | * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder |
| @@ -57,7 +59,7 @@ struct usb_host_endpoint { | |||
| 57 | struct usb_endpoint_descriptor desc; | 59 | struct usb_endpoint_descriptor desc; |
| 58 | struct list_head urb_list; | 60 | struct list_head urb_list; |
| 59 | void *hcpriv; | 61 | void *hcpriv; |
| 60 | struct kobject *kobj; /* For sysfs info */ | 62 | struct ep_device *ep_dev; /* For sysfs info */ |
| 61 | 63 | ||
| 62 | unsigned char *extra; /* Extra descriptors */ | 64 | unsigned char *extra; /* Extra descriptors */ |
| 63 | int extralen; | 65 | int extralen; |
| @@ -101,7 +103,8 @@ enum usb_interface_condition { | |||
| 101 | * @condition: binding state of the interface: not bound, binding | 103 | * @condition: binding state of the interface: not bound, binding |
| 102 | * (in probe()), bound to a driver, or unbinding (in disconnect()) | 104 | * (in probe()), bound to a driver, or unbinding (in disconnect()) |
| 103 | * @dev: driver model's view of this device | 105 | * @dev: driver model's view of this device |
| 104 | * @class_dev: driver model's class view of this device. | 106 | * @usb_dev: if an interface is bound to the USB major, this will point |
| 107 | * to the sysfs representation for that device. | ||
| 105 | * | 108 | * |
| 106 | * USB device drivers attach to interfaces on a physical device. Each | 109 | * USB device drivers attach to interfaces on a physical device. Each |
| 107 | * interface encapsulates a single high level function, such as feeding | 110 | * interface encapsulates a single high level function, such as feeding |
| @@ -141,7 +144,7 @@ struct usb_interface { | |||
| 141 | * bound to */ | 144 | * bound to */ |
| 142 | enum usb_interface_condition condition; /* state of binding */ | 145 | enum usb_interface_condition condition; /* state of binding */ |
| 143 | struct device dev; /* interface specific device info */ | 146 | struct device dev; /* interface specific device info */ |
| 144 | struct class_device *class_dev; | 147 | struct device *usb_dev; /* pointer to the usb class's device, if any */ |
| 145 | }; | 148 | }; |
| 146 | #define to_usb_interface(d) container_of(d, struct usb_interface, dev) | 149 | #define to_usb_interface(d) container_of(d, struct usb_interface, dev) |
| 147 | #define interface_to_usbdev(intf) \ | 150 | #define interface_to_usbdev(intf) \ |
| @@ -358,7 +361,7 @@ struct usb_device { | |||
| 358 | char *serial; /* iSerialNumber string, if present */ | 361 | char *serial; /* iSerialNumber string, if present */ |
| 359 | 362 | ||
| 360 | struct list_head filelist; | 363 | struct list_head filelist; |
| 361 | struct class_device *class_dev; | 364 | struct device *usbfs_dev; |
| 362 | struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ | 365 | struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ |
| 363 | 366 | ||
| 364 | /* | 367 | /* |
| @@ -386,6 +389,8 @@ extern int usb_lock_device_for_reset(struct usb_device *udev, | |||
| 386 | 389 | ||
| 387 | /* USB port reset for device reinitialization */ | 390 | /* USB port reset for device reinitialization */ |
| 388 | extern int usb_reset_device(struct usb_device *dev); | 391 | extern int usb_reset_device(struct usb_device *dev); |
| 392 | extern int usb_reset_composite_device(struct usb_device *dev, | ||
| 393 | struct usb_interface *iface); | ||
| 389 | 394 | ||
| 390 | extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); | 395 | extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); |
| 391 | 396 | ||
| @@ -554,6 +559,10 @@ struct usb_dynids { | |||
| 554 | * do (or don't) show up otherwise in the filesystem. | 559 | * do (or don't) show up otherwise in the filesystem. |
| 555 | * @suspend: Called when the device is going to be suspended by the system. | 560 | * @suspend: Called when the device is going to be suspended by the system. |
| 556 | * @resume: Called when the device is being resumed by the system. | 561 | * @resume: Called when the device is being resumed by the system. |
| 562 | * @pre_reset: Called by usb_reset_composite_device() when the device | ||
| 563 | * is about to be reset. | ||
| 564 | * @post_reset: Called by usb_reset_composite_device() after the device | ||
| 565 | * has been reset. | ||
| 557 | * @id_table: USB drivers use ID table to support hotplugging. | 566 | * @id_table: USB drivers use ID table to support hotplugging. |
| 558 | * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set | 567 | * Export this with MODULE_DEVICE_TABLE(usb,...). This must be set |
| 559 | * or your driver's probe function will never get called. | 568 | * or your driver's probe function will never get called. |
| @@ -592,6 +601,9 @@ struct usb_driver { | |||
| 592 | int (*suspend) (struct usb_interface *intf, pm_message_t message); | 601 | int (*suspend) (struct usb_interface *intf, pm_message_t message); |
| 593 | int (*resume) (struct usb_interface *intf); | 602 | int (*resume) (struct usb_interface *intf); |
| 594 | 603 | ||
| 604 | void (*pre_reset) (struct usb_interface *intf); | ||
| 605 | void (*post_reset) (struct usb_interface *intf); | ||
| 606 | |||
| 595 | const struct usb_device_id *id_table; | 607 | const struct usb_device_id *id_table; |
| 596 | 608 | ||
| 597 | struct usb_dynids dynids; | 609 | struct usb_dynids dynids; |
| @@ -1008,6 +1020,8 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, | |||
| 1008 | extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, | 1020 | extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, |
| 1009 | __u8 request, __u8 requesttype, __u16 value, __u16 index, | 1021 | __u8 request, __u8 requesttype, __u16 value, __u16 index, |
| 1010 | void *data, __u16 size, int timeout); | 1022 | void *data, __u16 size, int timeout); |
| 1023 | extern int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, | ||
| 1024 | void *data, int len, int *actual_length, int timeout); | ||
| 1011 | extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, | 1025 | extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, |
| 1012 | void *data, int len, int *actual_length, | 1026 | void *data, int len, int *actual_length, |
| 1013 | int timeout); | 1027 | int timeout); |
diff --git a/include/linux/usb_cdc.h b/include/linux/usb/cdc.h index ba617c372455..ba617c372455 100644 --- a/include/linux/usb_cdc.h +++ b/include/linux/usb/cdc.h | |||
diff --git a/include/linux/usb_input.h b/include/linux/usb/input.h index 716e0cc16043..716e0cc16043 100644 --- a/include/linux/usb_input.h +++ b/include/linux/usb/input.h | |||
diff --git a/include/linux/usb_isp116x.h b/include/linux/usb/isp116x.h index 436dd8a2b64a..436dd8a2b64a 100644 --- a/include/linux/usb_isp116x.h +++ b/include/linux/usb/isp116x.h | |||
diff --git a/include/linux/usb_sl811.h b/include/linux/usb/sl811.h index 4f2d012d7309..397ee3b3d7f3 100644 --- a/include/linux/usb_sl811.h +++ b/include/linux/usb/sl811.h | |||
| @@ -14,13 +14,13 @@ struct sl811_platform_data { | |||
| 14 | u8 power; | 14 | u8 power; |
| 15 | 15 | ||
| 16 | /* sl811 relies on an external source of VBUS current */ | 16 | /* sl811 relies on an external source of VBUS current */ |
| 17 | void (*port_power)(struct device *dev, int is_on); | 17 | void (*port_power)(struct device *dev, int is_on); |
| 18 | 18 | ||
| 19 | /* pulse sl811 nRST (probably with a GPIO) */ | 19 | /* pulse sl811 nRST (probably with a GPIO) */ |
| 20 | void (*reset)(struct device *dev); | 20 | void (*reset)(struct device *dev); |
| 21 | 21 | ||
| 22 | // some boards need something like these: | 22 | // some boards need something like these: |
| 23 | // int (*check_overcurrent)(struct device *dev); | 23 | // int (*check_overcurrent)(struct device *dev); |
| 24 | // void (*clock_enable)(struct device *dev, int is_on); | 24 | // void (*clock_enable)(struct device *dev, int is_on); |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
diff --git a/include/linux/zconf.h b/include/linux/zconf.h index f1cfd66b9554..0beb75e38caa 100644 --- a/include/linux/zconf.h +++ b/include/linux/zconf.h | |||
| @@ -35,6 +35,18 @@ | |||
| 35 | # define MAX_WBITS 15 /* 32K LZ77 window */ | 35 | # define MAX_WBITS 15 /* 32K LZ77 window */ |
| 36 | #endif | 36 | #endif |
| 37 | 37 | ||
| 38 | /* default windowBits for decompression. MAX_WBITS is for compression only */ | ||
| 39 | #ifndef DEF_WBITS | ||
| 40 | # define DEF_WBITS MAX_WBITS | ||
| 41 | #endif | ||
| 42 | |||
| 43 | /* default memLevel */ | ||
| 44 | #if MAX_MEM_LEVEL >= 8 | ||
| 45 | # define DEF_MEM_LEVEL 8 | ||
| 46 | #else | ||
| 47 | # define DEF_MEM_LEVEL MAX_MEM_LEVEL | ||
| 48 | #endif | ||
| 49 | |||
| 38 | /* Type declarations */ | 50 | /* Type declarations */ |
| 39 | 51 | ||
| 40 | typedef unsigned char Byte; /* 8 bits */ | 52 | typedef unsigned char Byte; /* 8 bits */ |
diff --git a/include/linux/zlib.h b/include/linux/zlib.h index 4fa32f0d4df8..9e3192a7dc6f 100644 --- a/include/linux/zlib.h +++ b/include/linux/zlib.h | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | /* zlib.h -- interface of the 'zlib' general purpose compression library | 1 | /* zlib.h -- interface of the 'zlib' general purpose compression library |
| 2 | version 1.1.3, July 9th, 1998 | ||
| 3 | 2 | ||
| 4 | Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler | 3 | Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler |
| 5 | 4 | ||
| 6 | This software is provided 'as-is', without any express or implied | 5 | This software is provided 'as-is', without any express or implied |
| 7 | warranty. In no event will the authors be held liable for any damages | 6 | warranty. In no event will the authors be held liable for any damages |
| @@ -24,7 +23,7 @@ | |||
| 24 | 23 | ||
| 25 | 24 | ||
| 26 | The data format used by the zlib library is described by RFCs (Request for | 25 | The data format used by the zlib library is described by RFCs (Request for |
| 27 | Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt | 26 | Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt |
| 28 | (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). | 27 | (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). |
| 29 | */ | 28 | */ |
| 30 | 29 | ||
| @@ -33,7 +32,22 @@ | |||
| 33 | 32 | ||
| 34 | #include <linux/zconf.h> | 33 | #include <linux/zconf.h> |
| 35 | 34 | ||
| 36 | #define ZLIB_VERSION "1.1.3" | 35 | /* zlib deflate based on ZLIB_VERSION "1.1.3" */ |
| 36 | /* zlib inflate based on ZLIB_VERSION "1.2.3" */ | ||
| 37 | |||
| 38 | /* | ||
| 39 | This is a modified version of zlib for use inside the Linux kernel. | ||
| 40 | The main changes are to perform all memory allocation in advance. | ||
| 41 | |||
| 42 | Inflation Changes: | ||
| 43 | * Z_PACKET_FLUSH is added and used by ppp_deflate. Before returning | ||
| 44 | this checks there is no more input data available and the next data | ||
| 45 | is a STORED block. It also resets the mode to be read for the next | ||
| 46 | data, all as per PPP requirements. | ||
| 47 | * Addition of zlib_inflateIncomp which copies incompressible data into | ||
| 48 | the history window and adjusts the accoutning without calling | ||
| 49 | zlib_inflate itself to inflate the data. | ||
| 50 | */ | ||
| 37 | 51 | ||
| 38 | /* | 52 | /* |
| 39 | The 'zlib' compression library provides in-memory compression and | 53 | The 'zlib' compression library provides in-memory compression and |
| @@ -48,9 +62,18 @@ | |||
| 48 | application must provide more input and/or consume the output | 62 | application must provide more input and/or consume the output |
| 49 | (providing more output space) before each call. | 63 | (providing more output space) before each call. |
| 50 | 64 | ||
| 65 | The compressed data format used by default by the in-memory functions is | ||
| 66 | the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped | ||
| 67 | around a deflate stream, which is itself documented in RFC 1951. | ||
| 68 | |||
| 51 | The library also supports reading and writing files in gzip (.gz) format | 69 | The library also supports reading and writing files in gzip (.gz) format |
| 52 | with an interface similar to that of stdio. | 70 | with an interface similar to that of stdio. |
| 53 | 71 | ||
| 72 | The zlib format was designed to be compact and fast for use in memory | ||
| 73 | and on communications channels. The gzip format was designed for single- | ||
| 74 | file compression on file systems, has a larger header than zlib to maintain | ||
| 75 | directory information, and uses a different, slower check method than zlib. | ||
| 76 | |||
| 54 | The library does not install any signal handler. The decoder checks | 77 | The library does not install any signal handler. The decoder checks |
| 55 | the consistency of the compressed data, so the library should never | 78 | the consistency of the compressed data, so the library should never |
| 56 | crash even in case of corrupted input. | 79 | crash even in case of corrupted input. |
| @@ -119,7 +142,8 @@ typedef z_stream *z_streamp; | |||
| 119 | #define Z_SYNC_FLUSH 3 | 142 | #define Z_SYNC_FLUSH 3 |
| 120 | #define Z_FULL_FLUSH 4 | 143 | #define Z_FULL_FLUSH 4 |
| 121 | #define Z_FINISH 5 | 144 | #define Z_FINISH 5 |
| 122 | /* Allowed flush values; see deflate() below for details */ | 145 | #define Z_BLOCK 6 /* Only for inflate at present */ |
| 146 | /* Allowed flush values; see deflate() and inflate() below for details */ | ||
| 123 | 147 | ||
| 124 | #define Z_OK 0 | 148 | #define Z_OK 0 |
| 125 | #define Z_STREAM_END 1 | 149 | #define Z_STREAM_END 1 |
| @@ -155,13 +179,6 @@ typedef z_stream *z_streamp; | |||
| 155 | 179 | ||
| 156 | /* basic functions */ | 180 | /* basic functions */ |
| 157 | 181 | ||
| 158 | extern const char * zlib_zlibVersion (void); | ||
| 159 | /* The application can compare zlibVersion and ZLIB_VERSION for consistency. | ||
| 160 | If the first character differs, the library code actually used is | ||
| 161 | not compatible with the zlib.h header file used by the application. | ||
| 162 | This check is automatically made by deflateInit and inflateInit. | ||
| 163 | */ | ||
| 164 | |||
| 165 | extern int zlib_deflate_workspacesize (void); | 182 | extern int zlib_deflate_workspacesize (void); |
| 166 | /* | 183 | /* |
| 167 | Returns the number of bytes that needs to be allocated for a per- | 184 | Returns the number of bytes that needs to be allocated for a per- |
| @@ -315,9 +332,9 @@ extern int zlib_inflateInit (z_streamp strm); | |||
| 315 | extern int zlib_inflate (z_streamp strm, int flush); | 332 | extern int zlib_inflate (z_streamp strm, int flush); |
| 316 | /* | 333 | /* |
| 317 | inflate decompresses as much data as possible, and stops when the input | 334 | inflate decompresses as much data as possible, and stops when the input |
| 318 | buffer becomes empty or the output buffer becomes full. It may some | 335 | buffer becomes empty or the output buffer becomes full. It may introduce |
| 319 | introduce some output latency (reading input without producing any output) | 336 | some output latency (reading input without producing any output) except when |
| 320 | except when forced to flush. | 337 | forced to flush. |
| 321 | 338 | ||
| 322 | The detailed semantics are as follows. inflate performs one or both of the | 339 | The detailed semantics are as follows. inflate performs one or both of the |
| 323 | following actions: | 340 | following actions: |
| @@ -341,11 +358,26 @@ extern int zlib_inflate (z_streamp strm, int flush); | |||
| 341 | must be called again after making room in the output buffer because there | 358 | must be called again after making room in the output buffer because there |
| 342 | might be more output pending. | 359 | might be more output pending. |
| 343 | 360 | ||
| 344 | If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much | 361 | The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, |
| 345 | output as possible to the output buffer. The flushing behavior of inflate is | 362 | Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much |
| 346 | not specified for values of the flush parameter other than Z_SYNC_FLUSH | 363 | output as possible to the output buffer. Z_BLOCK requests that inflate() stop |
| 347 | and Z_FINISH, but the current implementation actually flushes as much output | 364 | if and when it gets to the next deflate block boundary. When decoding the |
| 348 | as possible anyway. | 365 | zlib or gzip format, this will cause inflate() to return immediately after |
| 366 | the header and before the first block. When doing a raw inflate, inflate() | ||
| 367 | will go ahead and process the first block, and will return when it gets to | ||
| 368 | the end of that block, or when it runs out of data. | ||
| 369 | |||
| 370 | The Z_BLOCK option assists in appending to or combining deflate streams. | ||
| 371 | Also to assist in this, on return inflate() will set strm->data_type to the | ||
| 372 | number of unused bits in the last byte taken from strm->next_in, plus 64 | ||
| 373 | if inflate() is currently decoding the last block in the deflate stream, | ||
| 374 | plus 128 if inflate() returned immediately after decoding an end-of-block | ||
| 375 | code or decoding the complete header up to just before the first byte of the | ||
| 376 | deflate stream. The end-of-block will not be indicated until all of the | ||
| 377 | uncompressed data from that block has been written to strm->next_out. The | ||
| 378 | number of unused bits may in general be greater than seven, except when | ||
| 379 | bit 7 of data_type is set, in which case the number of unused bits will be | ||
| 380 | less than eight. | ||
| 349 | 381 | ||
| 350 | inflate() should normally be called until it returns Z_STREAM_END or an | 382 | inflate() should normally be called until it returns Z_STREAM_END or an |
| 351 | error. However if all decompression is to be performed in a single step | 383 | error. However if all decompression is to be performed in a single step |
| @@ -355,29 +387,44 @@ extern int zlib_inflate (z_streamp strm, int flush); | |||
| 355 | uncompressed data. (The size of the uncompressed data may have been saved | 387 | uncompressed data. (The size of the uncompressed data may have been saved |
| 356 | by the compressor for this purpose.) The next operation on this stream must | 388 | by the compressor for this purpose.) The next operation on this stream must |
| 357 | be inflateEnd to deallocate the decompression state. The use of Z_FINISH | 389 | be inflateEnd to deallocate the decompression state. The use of Z_FINISH |
| 358 | is never required, but can be used to inform inflate that a faster routine | 390 | is never required, but can be used to inform inflate that a faster approach |
| 359 | may be used for the single inflate() call. | 391 | may be used for the single inflate() call. |
| 360 | 392 | ||
| 361 | If a preset dictionary is needed at this point (see inflateSetDictionary | 393 | In this implementation, inflate() always flushes as much output as |
| 362 | below), inflate sets strm-adler to the adler32 checksum of the | 394 | possible to the output buffer, and always uses the faster approach on the |
| 363 | dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise | 395 | first call. So the only effect of the flush parameter in this implementation |
| 364 | it sets strm->adler to the adler32 checksum of all output produced | 396 | is on the return value of inflate(), as noted below, or when it returns early |
| 365 | so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or | 397 | because Z_BLOCK is used. |
| 366 | an error code as described below. At the end of the stream, inflate() | 398 | |
| 367 | checks that its computed adler32 checksum is equal to that saved by the | 399 | If a preset dictionary is needed after this call (see inflateSetDictionary |
| 368 | compressor and returns Z_STREAM_END only if the checksum is correct. | 400 | below), inflate sets strm->adler to the adler32 checksum of the dictionary |
| 401 | chosen by the compressor and returns Z_NEED_DICT; otherwise it sets | ||
| 402 | strm->adler to the adler32 checksum of all output produced so far (that is, | ||
| 403 | total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described | ||
| 404 | below. At the end of the stream, inflate() checks that its computed adler32 | ||
| 405 | checksum is equal to that saved by the compressor and returns Z_STREAM_END | ||
| 406 | only if the checksum is correct. | ||
| 407 | |||
| 408 | inflate() will decompress and check either zlib-wrapped or gzip-wrapped | ||
| 409 | deflate data. The header type is detected automatically. Any information | ||
| 410 | contained in the gzip header is not retained, so applications that need that | ||
| 411 | information should instead use raw inflate, see inflateInit2() below, or | ||
| 412 | inflateBack() and perform their own processing of the gzip header and | ||
| 413 | trailer. | ||
| 369 | 414 | ||
| 370 | inflate() returns Z_OK if some progress has been made (more input processed | 415 | inflate() returns Z_OK if some progress has been made (more input processed |
| 371 | or more output produced), Z_STREAM_END if the end of the compressed data has | 416 | or more output produced), Z_STREAM_END if the end of the compressed data has |
| 372 | been reached and all uncompressed output has been produced, Z_NEED_DICT if a | 417 | been reached and all uncompressed output has been produced, Z_NEED_DICT if a |
| 373 | preset dictionary is needed at this point, Z_DATA_ERROR if the input data was | 418 | preset dictionary is needed at this point, Z_DATA_ERROR if the input data was |
| 374 | corrupted (input stream not conforming to the zlib format or incorrect | 419 | corrupted (input stream not conforming to the zlib format or incorrect check |
| 375 | adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent | 420 | value), Z_STREAM_ERROR if the stream structure was inconsistent (for example |
| 376 | (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not | 421 | if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, |
| 377 | enough memory, Z_BUF_ERROR if no progress is possible or if there was not | 422 | Z_BUF_ERROR if no progress is possible or if there was not enough room in the |
| 378 | enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR | 423 | output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and |
| 379 | case, the application may then call inflateSync to look for a good | 424 | inflate() can be called again with more input and more output space to |
| 380 | compression block. | 425 | continue decompressing. If Z_DATA_ERROR is returned, the application may then |
| 426 | call inflateSync() to look for a good compression block if a partial recovery | ||
| 427 | of the data is desired. | ||
| 381 | */ | 428 | */ |
| 382 | 429 | ||
| 383 | 430 | ||
| @@ -547,16 +594,36 @@ extern int inflateInit2 (z_streamp strm, int windowBits); | |||
| 547 | The windowBits parameter is the base two logarithm of the maximum window | 594 | The windowBits parameter is the base two logarithm of the maximum window |
| 548 | size (the size of the history buffer). It should be in the range 8..15 for | 595 | size (the size of the history buffer). It should be in the range 8..15 for |
| 549 | this version of the library. The default value is 15 if inflateInit is used | 596 | this version of the library. The default value is 15 if inflateInit is used |
| 550 | instead. If a compressed stream with a larger window size is given as | 597 | instead. windowBits must be greater than or equal to the windowBits value |
| 551 | input, inflate() will return with the error code Z_DATA_ERROR instead of | 598 | provided to deflateInit2() while compressing, or it must be equal to 15 if |
| 552 | trying to allocate a larger window. | 599 | deflateInit2() was not used. If a compressed stream with a larger window |
| 553 | 600 | size is given as input, inflate() will return with the error code | |
| 554 | inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough | 601 | Z_DATA_ERROR instead of trying to allocate a larger window. |
| 555 | memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative | 602 | |
| 556 | memLevel). msg is set to null if there is no error message. inflateInit2 | 603 | windowBits can also be -8..-15 for raw inflate. In this case, -windowBits |
| 557 | does not perform any decompression apart from reading the zlib header if | 604 | determines the window size. inflate() will then process raw deflate data, |
| 558 | present: this will be done by inflate(). (So next_in and avail_in may be | 605 | not looking for a zlib or gzip header, not generating a check value, and not |
| 559 | modified, but next_out and avail_out are unchanged.) | 606 | looking for any check values for comparison at the end of the stream. This |
| 607 | is for use with other formats that use the deflate compressed data format | ||
| 608 | such as zip. Those formats provide their own check values. If a custom | ||
| 609 | format is developed using the raw deflate format for compressed data, it is | ||
| 610 | recommended that a check value such as an adler32 or a crc32 be applied to | ||
| 611 | the uncompressed data as is done in the zlib, gzip, and zip formats. For | ||
| 612 | most applications, the zlib format should be used as is. Note that comments | ||
| 613 | above on the use in deflateInit2() applies to the magnitude of windowBits. | ||
| 614 | |||
| 615 | windowBits can also be greater than 15 for optional gzip decoding. Add | ||
| 616 | 32 to windowBits to enable zlib and gzip decoding with automatic header | ||
| 617 | detection, or add 16 to decode only the gzip format (the zlib format will | ||
| 618 | return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is | ||
| 619 | a crc32 instead of an adler32. | ||
| 620 | |||
| 621 | inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough | ||
| 622 | memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg | ||
| 623 | is set to null if there is no error message. inflateInit2 does not perform | ||
| 624 | any decompression apart from reading the zlib header if present: this will | ||
| 625 | be done by inflate(). (So next_in and avail_in may be modified, but next_out | ||
| 626 | and avail_out are unchanged.) | ||
| 560 | */ | 627 | */ |
| 561 | 628 | ||
| 562 | extern int zlib_inflateSetDictionary (z_streamp strm, | 629 | extern int zlib_inflateSetDictionary (z_streamp strm, |
| @@ -564,16 +631,19 @@ extern int zlib_inflateSetDictionary (z_streamp strm, | |||
| 564 | uInt dictLength); | 631 | uInt dictLength); |
| 565 | /* | 632 | /* |
| 566 | Initializes the decompression dictionary from the given uncompressed byte | 633 | Initializes the decompression dictionary from the given uncompressed byte |
| 567 | sequence. This function must be called immediately after a call of inflate | 634 | sequence. This function must be called immediately after a call of inflate, |
| 568 | if this call returned Z_NEED_DICT. The dictionary chosen by the compressor | 635 | if that call returned Z_NEED_DICT. The dictionary chosen by the compressor |
| 569 | can be determined from the Adler32 value returned by this call of | 636 | can be determined from the adler32 value returned by that call of inflate. |
| 570 | inflate. The compressor and decompressor must use exactly the same | 637 | The compressor and decompressor must use exactly the same dictionary (see |
| 571 | dictionary (see deflateSetDictionary). | 638 | deflateSetDictionary). For raw inflate, this function can be called |
| 639 | immediately after inflateInit2() or inflateReset() and before any call of | ||
| 640 | inflate() to set the dictionary. The application must insure that the | ||
| 641 | dictionary that was used for compression is provided. | ||
| 572 | 642 | ||
| 573 | inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a | 643 | inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a |
| 574 | parameter is invalid (such as NULL dictionary) or the stream state is | 644 | parameter is invalid (such as NULL dictionary) or the stream state is |
| 575 | inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the | 645 | inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the |
| 576 | expected one (incorrect Adler32 value). inflateSetDictionary does not | 646 | expected one (incorrect adler32 value). inflateSetDictionary does not |
| 577 | perform any decompression: this will be done by subsequent calls of | 647 | perform any decompression: this will be done by subsequent calls of |
| 578 | inflate(). | 648 | inflate(). |
| 579 | */ | 649 | */ |
| @@ -614,40 +684,19 @@ extern int zlib_inflateIncomp (z_stream *strm); | |||
| 614 | containing the data at next_in (except that the data is not output). | 684 | containing the data at next_in (except that the data is not output). |
| 615 | */ | 685 | */ |
| 616 | 686 | ||
| 617 | /* various hacks, don't look :) */ | ||
| 618 | |||
| 619 | /* deflateInit and inflateInit are macros to allow checking the zlib version | ||
| 620 | * and the compiler's view of z_stream: | ||
| 621 | */ | ||
| 622 | extern int zlib_deflateInit_ (z_streamp strm, int level, | ||
| 623 | const char *version, int stream_size); | ||
| 624 | extern int zlib_inflateInit_ (z_streamp strm, | ||
| 625 | const char *version, int stream_size); | ||
| 626 | extern int zlib_deflateInit2_ (z_streamp strm, int level, int method, | ||
| 627 | int windowBits, int memLevel, | ||
| 628 | int strategy, const char *version, | ||
| 629 | int stream_size); | ||
| 630 | extern int zlib_inflateInit2_ (z_streamp strm, int windowBits, | ||
| 631 | const char *version, int stream_size); | ||
| 632 | #define zlib_deflateInit(strm, level) \ | 687 | #define zlib_deflateInit(strm, level) \ |
| 633 | zlib_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) | 688 | zlib_deflateInit2((strm), (level), Z_DEFLATED, MAX_WBITS, \ |
| 689 | DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY) | ||
| 634 | #define zlib_inflateInit(strm) \ | 690 | #define zlib_inflateInit(strm) \ |
| 635 | zlib_inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) | 691 | zlib_inflateInit2((strm), DEF_WBITS) |
| 636 | #define zlib_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ | ||
| 637 | zlib_deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ | ||
| 638 | (strategy), ZLIB_VERSION, sizeof(z_stream)) | ||
| 639 | #define zlib_inflateInit2(strm, windowBits) \ | ||
| 640 | zlib_inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) | ||
| 641 | 692 | ||
| 693 | extern int zlib_deflateInit2(z_streamp strm, int level, int method, | ||
| 694 | int windowBits, int memLevel, | ||
| 695 | int strategy); | ||
| 696 | extern int zlib_inflateInit2(z_streamp strm, int windowBits); | ||
| 642 | 697 | ||
| 643 | #if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) | 698 | #if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) |
| 644 | struct internal_state {int dummy;}; /* hack for buggy compilers */ | 699 | struct internal_state {int dummy;}; /* hack for buggy compilers */ |
| 645 | #endif | 700 | #endif |
| 646 | 701 | ||
| 647 | extern const char * zlib_zError (int err); | ||
| 648 | #if 0 | ||
| 649 | extern int zlib_inflateSyncPoint (z_streamp z); | ||
| 650 | #endif | ||
| 651 | extern const uLong * zlib_get_crc_table (void); | ||
| 652 | |||
| 653 | #endif /* _ZLIB_H */ | 702 | #endif /* _ZLIB_H */ |
diff --git a/include/linux/zutil.h b/include/linux/zutil.h index ee0c59cf2136..6adfa9a6ffe9 100644 --- a/include/linux/zutil.h +++ b/include/linux/zutil.h | |||
| @@ -23,18 +23,6 @@ typedef unsigned long ulg; | |||
| 23 | 23 | ||
| 24 | /* common constants */ | 24 | /* common constants */ |
| 25 | 25 | ||
| 26 | #ifndef DEF_WBITS | ||
| 27 | # define DEF_WBITS MAX_WBITS | ||
| 28 | #endif | ||
| 29 | /* default windowBits for decompression. MAX_WBITS is for compression only */ | ||
| 30 | |||
| 31 | #if MAX_MEM_LEVEL >= 8 | ||
| 32 | # define DEF_MEM_LEVEL 8 | ||
| 33 | #else | ||
| 34 | # define DEF_MEM_LEVEL MAX_MEM_LEVEL | ||
| 35 | #endif | ||
| 36 | /* default memLevel */ | ||
| 37 | |||
| 38 | #define STORED_BLOCK 0 | 26 | #define STORED_BLOCK 0 |
| 39 | #define STATIC_TREES 1 | 27 | #define STATIC_TREES 1 |
| 40 | #define DYN_TREES 2 | 28 | #define DYN_TREES 2 |
diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index b45a73712748..446afc3ea27f 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h | |||
| @@ -378,6 +378,7 @@ | |||
| 378 | #define AC97_HAS_NO_MIC (1<<15) /* no MIC volume */ | 378 | #define AC97_HAS_NO_MIC (1<<15) /* no MIC volume */ |
| 379 | #define AC97_HAS_NO_TONE (1<<16) /* no Tone volume */ | 379 | #define AC97_HAS_NO_TONE (1<<16) /* no Tone volume */ |
| 380 | #define AC97_HAS_NO_STD_PCM (1<<17) /* no standard AC97 PCM volume and mute */ | 380 | #define AC97_HAS_NO_STD_PCM (1<<17) /* no standard AC97 PCM volume and mute */ |
| 381 | #define AC97_HAS_NO_AUX (1<<18) /* no standard AC97 AUX volume and mute */ | ||
| 381 | 382 | ||
| 382 | /* rates indexes */ | 383 | /* rates indexes */ |
| 383 | #define AC97_RATES_FRONT_DAC 0 | 384 | #define AC97_RATES_FRONT_DAC 0 |
diff --git a/include/sound/asequencer.h b/include/sound/asequencer.h index 6691e4aa4ea7..3f2f4042a20d 100644 --- a/include/sound/asequencer.h +++ b/include/sound/asequencer.h | |||
| @@ -605,6 +605,10 @@ struct snd_seq_remove_events { | |||
| 605 | #define SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE (1<<11) /* Sampling device (support sample download) */ | 605 | #define SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE (1<<11) /* Sampling device (support sample download) */ |
| 606 | #define SNDRV_SEQ_PORT_TYPE_SAMPLE (1<<12) /* Sampling device (sample can be downloaded at any time) */ | 606 | #define SNDRV_SEQ_PORT_TYPE_SAMPLE (1<<12) /* Sampling device (sample can be downloaded at any time) */ |
| 607 | /*...*/ | 607 | /*...*/ |
| 608 | #define SNDRV_SEQ_PORT_TYPE_HARDWARE (1<<16) /* driver for a hardware device */ | ||
| 609 | #define SNDRV_SEQ_PORT_TYPE_SOFTWARE (1<<17) /* implemented in software */ | ||
| 610 | #define SNDRV_SEQ_PORT_TYPE_SYNTHESIZER (1<<18) /* generates sound */ | ||
| 611 | #define SNDRV_SEQ_PORT_TYPE_PORT (1<<19) /* connects to other device(s) */ | ||
| 608 | #define SNDRV_SEQ_PORT_TYPE_APPLICATION (1<<20) /* application (sequencer/editor) */ | 612 | #define SNDRV_SEQ_PORT_TYPE_APPLICATION (1<<20) /* application (sequencer/editor) */ |
| 609 | 613 | ||
| 610 | /* misc. conditioning flags */ | 614 | /* misc. conditioning flags */ |
diff --git a/include/sound/asound.h b/include/sound/asound.h index 9cc021c7ee11..41885f48ad91 100644 --- a/include/sound/asound.h +++ b/include/sound/asound.h | |||
| @@ -137,7 +137,7 @@ enum { | |||
| 137 | * * | 137 | * * |
| 138 | *****************************************************************************/ | 138 | *****************************************************************************/ |
| 139 | 139 | ||
| 140 | #define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7) | 140 | #define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 8) |
| 141 | 141 | ||
| 142 | typedef unsigned long snd_pcm_uframes_t; | 142 | typedef unsigned long snd_pcm_uframes_t; |
| 143 | typedef signed long snd_pcm_sframes_t; | 143 | typedef signed long snd_pcm_sframes_t; |
diff --git a/include/sound/core.h b/include/sound/core.h index 5135147f20e8..5d184be0ff72 100644 --- a/include/sound/core.h +++ b/include/sound/core.h | |||
| @@ -233,9 +233,8 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size | |||
| 233 | 233 | ||
| 234 | /* init.c */ | 234 | /* init.c */ |
| 235 | 235 | ||
| 236 | extern unsigned int snd_cards_lock; | ||
| 237 | extern struct snd_card *snd_cards[SNDRV_CARDS]; | 236 | extern struct snd_card *snd_cards[SNDRV_CARDS]; |
| 238 | extern rwlock_t snd_card_rwlock; | 237 | int snd_card_locked(int card); |
| 239 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | 238 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) |
| 240 | #define SND_MIXER_OSS_NOTIFY_REGISTER 0 | 239 | #define SND_MIXER_OSS_NOTIFY_REGISTER 0 |
| 241 | #define SND_MIXER_OSS_NOTIFY_DISCONNECT 1 | 240 | #define SND_MIXER_OSS_NOTIFY_DISCONNECT 1 |
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 186e00ad9e79..884bbf54cd36 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h | |||
| @@ -245,6 +245,7 @@ | |||
| 245 | #define A_IOCFG_GPOUT0 0x0044 /* analog/digital */ | 245 | #define A_IOCFG_GPOUT0 0x0044 /* analog/digital */ |
| 246 | #define A_IOCFG_DISABLE_ANALOG 0x0040 /* = 'enable' for Audigy2 (chiprev=4) */ | 246 | #define A_IOCFG_DISABLE_ANALOG 0x0040 /* = 'enable' for Audigy2 (chiprev=4) */ |
| 247 | #define A_IOCFG_ENABLE_DIGITAL 0x0004 | 247 | #define A_IOCFG_ENABLE_DIGITAL 0x0004 |
| 248 | #define A_IOCFG_ENABLE_DIGITAL_AUDIGY4 0x0080 | ||
| 248 | #define A_IOCFG_UNKNOWN_20 0x0020 | 249 | #define A_IOCFG_UNKNOWN_20 0x0020 |
| 249 | #define A_IOCFG_DISABLE_AC97_FRONT 0x0080 /* turn off ac97 front -> front (10k2.1) */ | 250 | #define A_IOCFG_DISABLE_AC97_FRONT 0x0080 /* turn off ac97 front -> front (10k2.1) */ |
| 250 | #define A_IOCFG_GPOUT1 0x0002 /* IR? drive's internal bypass (?) */ | 251 | #define A_IOCFG_GPOUT1 0x0002 /* IR? drive's internal bypass (?) */ |
| @@ -1065,6 +1066,7 @@ struct snd_emu_chip_details { | |||
| 1065 | unsigned char emu1212m; /* EMU 1212m card */ | 1066 | unsigned char emu1212m; /* EMU 1212m card */ |
| 1066 | unsigned char spi_dac; /* SPI interface for DAC */ | 1067 | unsigned char spi_dac; /* SPI interface for DAC */ |
| 1067 | unsigned char i2c_adc; /* I2C interface for ADC */ | 1068 | unsigned char i2c_adc; /* I2C interface for ADC */ |
| 1069 | unsigned char adc_1361t; /* Use Philips 1361T ADC */ | ||
| 1068 | const char *driver; | 1070 | const char *driver; |
| 1069 | const char *name; | 1071 | const char *name; |
| 1070 | const char *id; /* for backward compatibility - can be NULL if not needed */ | 1072 | const char *id; /* for backward compatibility - can be NULL if not needed */ |
diff --git a/include/sound/info.h b/include/sound/info.h index f23d8381c216..74f6996769c7 100644 --- a/include/sound/info.h +++ b/include/sound/info.h | |||
| @@ -27,9 +27,9 @@ | |||
| 27 | /* buffer for information */ | 27 | /* buffer for information */ |
| 28 | struct snd_info_buffer { | 28 | struct snd_info_buffer { |
| 29 | char *buffer; /* pointer to begin of buffer */ | 29 | char *buffer; /* pointer to begin of buffer */ |
| 30 | char *curr; /* current position in buffer */ | 30 | unsigned int curr; /* current position in buffer */ |
| 31 | unsigned long size; /* current size */ | 31 | unsigned int size; /* current size */ |
| 32 | unsigned long len; /* total length of buffer */ | 32 | unsigned int len; /* total length of buffer */ |
| 33 | int stop; /* stop flag */ | 33 | int stop; /* stop flag */ |
| 34 | int error; /* error code */ | 34 | int error; /* error code */ |
| 35 | }; | 35 | }; |
| @@ -40,8 +40,6 @@ struct snd_info_buffer { | |||
| 40 | struct snd_info_entry; | 40 | struct snd_info_entry; |
| 41 | 41 | ||
| 42 | struct snd_info_entry_text { | 42 | struct snd_info_entry_text { |
| 43 | unsigned long read_size; | ||
| 44 | unsigned long write_size; | ||
| 45 | void (*read) (struct snd_info_entry *entry, struct snd_info_buffer *buffer); | 43 | void (*read) (struct snd_info_entry *entry, struct snd_info_buffer *buffer); |
| 46 | void (*write) (struct snd_info_entry *entry, struct snd_info_buffer *buffer); | 44 | void (*write) (struct snd_info_entry *entry, struct snd_info_buffer *buffer); |
| 47 | }; | 45 | }; |
| @@ -132,11 +130,9 @@ int snd_card_proc_new(struct snd_card *card, const char *name, struct snd_info_e | |||
| 132 | 130 | ||
| 133 | static inline void snd_info_set_text_ops(struct snd_info_entry *entry, | 131 | static inline void snd_info_set_text_ops(struct snd_info_entry *entry, |
| 134 | void *private_data, | 132 | void *private_data, |
| 135 | long read_size, | ||
| 136 | void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) | 133 | void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) |
| 137 | { | 134 | { |
| 138 | entry->private_data = private_data; | 135 | entry->private_data = private_data; |
| 139 | entry->c.text.read_size = read_size; | ||
| 140 | entry->c.text.read = read; | 136 | entry->c.text.read = read; |
| 141 | } | 137 | } |
| 142 | 138 | ||
| @@ -167,7 +163,6 @@ static inline int snd_card_proc_new(struct snd_card *card, const char *name, | |||
| 167 | struct snd_info_entry **entryp) { return -EINVAL; } | 163 | struct snd_info_entry **entryp) { return -EINVAL; } |
| 168 | static inline void snd_info_set_text_ops(struct snd_info_entry *entry __attribute__((unused)), | 164 | static inline void snd_info_set_text_ops(struct snd_info_entry *entry __attribute__((unused)), |
| 169 | void *private_data, | 165 | void *private_data, |
| 170 | long read_size, | ||
| 171 | void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) {} | 166 | void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) {} |
| 172 | 167 | ||
| 173 | static inline int snd_info_check_reserved_words(const char *str) { return 1; } | 168 | static inline int snd_info_check_reserved_words(const char *str) { return 1; } |
diff --git a/include/sound/mpu401.h b/include/sound/mpu401.h index 8e97ace78f16..ac504321ea56 100644 --- a/include/sound/mpu401.h +++ b/include/sound/mpu401.h | |||
| @@ -45,6 +45,12 @@ | |||
| 45 | #define MPU401_HW_PC98II 18 /* Roland PC98II */ | 45 | #define MPU401_HW_PC98II 18 /* Roland PC98II */ |
| 46 | #define MPU401_HW_AUREAL 19 /* Aureal Vortex */ | 46 | #define MPU401_HW_AUREAL 19 /* Aureal Vortex */ |
| 47 | 47 | ||
| 48 | #define MPU401_INFO_INPUT (1 << 0) /* input stream */ | ||
| 49 | #define MPU401_INFO_OUTPUT (1 << 1) /* output stream */ | ||
| 50 | #define MPU401_INFO_INTEGRATED (1 << 2) /* integrated h/w port */ | ||
| 51 | #define MPU401_INFO_MMIO (1 << 3) /* MMIO access */ | ||
| 52 | #define MPU401_INFO_TX_IRQ (1 << 4) /* independent TX irq */ | ||
| 53 | |||
| 48 | #define MPU401_MODE_BIT_INPUT 0 | 54 | #define MPU401_MODE_BIT_INPUT 0 |
| 49 | #define MPU401_MODE_BIT_OUTPUT 1 | 55 | #define MPU401_MODE_BIT_OUTPUT 1 |
| 50 | #define MPU401_MODE_BIT_INPUT_TRIGGER 2 | 56 | #define MPU401_MODE_BIT_INPUT_TRIGGER 2 |
| @@ -62,6 +68,7 @@ struct snd_mpu401 { | |||
| 62 | struct snd_rawmidi *rmidi; | 68 | struct snd_rawmidi *rmidi; |
| 63 | 69 | ||
| 64 | unsigned short hardware; /* MPU401_HW_XXXX */ | 70 | unsigned short hardware; /* MPU401_HW_XXXX */ |
| 71 | unsigned int info_flags; /* MPU401_INFO_XXX */ | ||
| 65 | unsigned long port; /* base port of MPU-401 chip */ | 72 | unsigned long port; /* base port of MPU-401 chip */ |
| 66 | unsigned long cport; /* port + 1 (usually) */ | 73 | unsigned long cport; /* port + 1 (usually) */ |
| 67 | struct resource *res; /* port resource */ | 74 | struct resource *res; /* port resource */ |
| @@ -99,13 +106,16 @@ struct snd_mpu401 { | |||
| 99 | 106 | ||
| 100 | */ | 107 | */ |
| 101 | 108 | ||
| 102 | irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs); | 109 | irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, |
| 110 | struct pt_regs *regs); | ||
| 111 | irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id, | ||
| 112 | struct pt_regs *regs); | ||
| 103 | 113 | ||
| 104 | int snd_mpu401_uart_new(struct snd_card *card, | 114 | int snd_mpu401_uart_new(struct snd_card *card, |
| 105 | int device, | 115 | int device, |
| 106 | unsigned short hardware, | 116 | unsigned short hardware, |
| 107 | unsigned long port, | 117 | unsigned long port, |
| 108 | int integrated, | 118 | unsigned int info_flags, |
| 109 | int irq, | 119 | int irq, |
| 110 | int irq_flags, | 120 | int irq_flags, |
| 111 | struct snd_rawmidi ** rrawmidi); | 121 | struct snd_rawmidi ** rrawmidi); |
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 373425895faa..f84d84993a31 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
| @@ -300,7 +300,6 @@ struct snd_pcm_runtime { | |||
| 300 | /* -- mmap -- */ | 300 | /* -- mmap -- */ |
| 301 | volatile struct snd_pcm_mmap_status *status; | 301 | volatile struct snd_pcm_mmap_status *status; |
| 302 | volatile struct snd_pcm_mmap_control *control; | 302 | volatile struct snd_pcm_mmap_control *control; |
| 303 | atomic_t mmap_count; | ||
| 304 | 303 | ||
| 305 | /* -- locking / scheduling -- */ | 304 | /* -- locking / scheduling -- */ |
| 306 | wait_queue_head_t sleep; | 305 | wait_queue_head_t sleep; |
| @@ -368,7 +367,9 @@ struct snd_pcm_substream { | |||
| 368 | struct snd_pcm_group *group; /* pointer to current group */ | 367 | struct snd_pcm_group *group; /* pointer to current group */ |
| 369 | /* -- assigned files -- */ | 368 | /* -- assigned files -- */ |
| 370 | void *file; | 369 | void *file; |
| 371 | struct file *ffile; | 370 | int ref_count; |
| 371 | atomic_t mmap_count; | ||
| 372 | unsigned int f_flags; | ||
| 372 | void (*pcm_release)(struct snd_pcm_substream *); | 373 | void (*pcm_release)(struct snd_pcm_substream *); |
| 373 | #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) | 374 | #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) |
| 374 | /* -- OSS things -- */ | 375 | /* -- OSS things -- */ |
| @@ -387,7 +388,7 @@ struct snd_pcm_substream { | |||
| 387 | unsigned int hw_opened: 1; | 388 | unsigned int hw_opened: 1; |
| 388 | }; | 389 | }; |
| 389 | 390 | ||
| 390 | #define SUBSTREAM_BUSY(substream) ((substream)->file != NULL) | 391 | #define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0) |
| 391 | 392 | ||
| 392 | 393 | ||
| 393 | struct snd_pcm_str { | 394 | struct snd_pcm_str { |
| @@ -825,14 +826,6 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
| 825 | 826 | ||
| 826 | void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params); | 827 | void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params); |
| 827 | void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var); | 828 | void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, snd_pcm_hw_param_t var); |
| 828 | int snd_pcm_hw_param_near(struct snd_pcm_substream *substream, | ||
| 829 | struct snd_pcm_hw_params *params, | ||
| 830 | snd_pcm_hw_param_t var, | ||
| 831 | unsigned int val, int *dir); | ||
| 832 | int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm, | ||
| 833 | struct snd_pcm_hw_params *params, | ||
| 834 | snd_pcm_hw_param_t var, | ||
| 835 | unsigned int val, int dir); | ||
| 836 | int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); | 829 | int snd_pcm_hw_params_choose(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); |
| 837 | 830 | ||
| 838 | int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); | 831 | int snd_pcm_hw_refine(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params); |
| @@ -979,13 +972,13 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne | |||
| 979 | static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area) | 972 | static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area) |
| 980 | { | 973 | { |
| 981 | struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; | 974 | struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; |
| 982 | atomic_inc(&substream->runtime->mmap_count); | 975 | atomic_inc(&substream->mmap_count); |
| 983 | } | 976 | } |
| 984 | 977 | ||
| 985 | static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area) | 978 | static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area) |
| 986 | { | 979 | { |
| 987 | struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; | 980 | struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data; |
| 988 | atomic_dec(&substream->runtime->mmap_count); | 981 | atomic_dec(&substream->mmap_count); |
| 989 | } | 982 | } |
| 990 | 983 | ||
| 991 | /* mmap for io-memory area */ | 984 | /* mmap for io-memory area */ |
diff --git a/include/sound/pcm_params.h b/include/sound/pcm_params.h index fb18aef77341..85cf1cf4f31a 100644 --- a/include/sound/pcm_params.h +++ b/include/sound/pcm_params.h | |||
| @@ -22,29 +22,21 @@ | |||
| 22 | * | 22 | * |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | extern int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, | 25 | int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, |
| 26 | snd_pcm_hw_param_t var, const struct snd_mask *val); | 26 | struct snd_pcm_hw_params *params, |
| 27 | extern unsigned int snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params, | 27 | snd_pcm_hw_param_t var, int *dir); |
| 28 | snd_pcm_hw_param_t var, int *dir); | 28 | int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, |
| 29 | extern unsigned int snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params, | 29 | struct snd_pcm_hw_params *params, |
| 30 | snd_pcm_hw_param_t var, int *dir); | 30 | snd_pcm_hw_param_t var, int *dir); |
| 31 | extern int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params, | 31 | int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, |
| 32 | snd_pcm_hw_param_t var, unsigned int val, int dir); | 32 | snd_pcm_hw_param_t var, int *dir); |
| 33 | extern int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params, | ||
| 34 | snd_pcm_hw_param_t var); | ||
| 35 | extern int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, | ||
| 36 | snd_pcm_hw_param_t var, unsigned int val, int dir); | ||
| 37 | |||
| 38 | /* To share the same code we have alsa-lib */ | ||
| 39 | #define INLINE static inline | ||
| 40 | #define assert(a) (void)(a) | ||
| 41 | 33 | ||
| 42 | #define SNDRV_MASK_BITS 64 /* we use so far 64bits only */ | 34 | #define SNDRV_MASK_BITS 64 /* we use so far 64bits only */ |
| 43 | #define SNDRV_MASK_SIZE (SNDRV_MASK_BITS / 32) | 35 | #define SNDRV_MASK_SIZE (SNDRV_MASK_BITS / 32) |
| 44 | #define MASK_OFS(i) ((i) >> 5) | 36 | #define MASK_OFS(i) ((i) >> 5) |
| 45 | #define MASK_BIT(i) (1U << ((i) & 31)) | 37 | #define MASK_BIT(i) (1U << ((i) & 31)) |
| 46 | 38 | ||
| 47 | INLINE unsigned int ld2(u_int32_t v) | 39 | static inline unsigned int ld2(u_int32_t v) |
| 48 | { | 40 | { |
| 49 | unsigned r = 0; | 41 | unsigned r = 0; |
| 50 | 42 | ||
| @@ -69,22 +61,22 @@ INLINE unsigned int ld2(u_int32_t v) | |||
| 69 | return r; | 61 | return r; |
| 70 | } | 62 | } |
| 71 | 63 | ||
| 72 | INLINE size_t snd_mask_sizeof(void) | 64 | static inline size_t snd_mask_sizeof(void) |
| 73 | { | 65 | { |
| 74 | return sizeof(struct snd_mask); | 66 | return sizeof(struct snd_mask); |
| 75 | } | 67 | } |
| 76 | 68 | ||
| 77 | INLINE void snd_mask_none(struct snd_mask *mask) | 69 | static inline void snd_mask_none(struct snd_mask *mask) |
| 78 | { | 70 | { |
| 79 | memset(mask, 0, sizeof(*mask)); | 71 | memset(mask, 0, sizeof(*mask)); |
| 80 | } | 72 | } |
| 81 | 73 | ||
| 82 | INLINE void snd_mask_any(struct snd_mask *mask) | 74 | static inline void snd_mask_any(struct snd_mask *mask) |
| 83 | { | 75 | { |
| 84 | memset(mask, 0xff, SNDRV_MASK_SIZE * sizeof(u_int32_t)); | 76 | memset(mask, 0xff, SNDRV_MASK_SIZE * sizeof(u_int32_t)); |
| 85 | } | 77 | } |
| 86 | 78 | ||
| 87 | INLINE int snd_mask_empty(const struct snd_mask *mask) | 79 | static inline int snd_mask_empty(const struct snd_mask *mask) |
| 88 | { | 80 | { |
| 89 | int i; | 81 | int i; |
| 90 | for (i = 0; i < SNDRV_MASK_SIZE; i++) | 82 | for (i = 0; i < SNDRV_MASK_SIZE; i++) |
| @@ -93,10 +85,9 @@ INLINE int snd_mask_empty(const struct snd_mask *mask) | |||
| 93 | return 1; | 85 | return 1; |
| 94 | } | 86 | } |
| 95 | 87 | ||
| 96 | INLINE unsigned int snd_mask_min(const struct snd_mask *mask) | 88 | static inline unsigned int snd_mask_min(const struct snd_mask *mask) |
| 97 | { | 89 | { |
| 98 | int i; | 90 | int i; |
| 99 | assert(!snd_mask_empty(mask)); | ||
| 100 | for (i = 0; i < SNDRV_MASK_SIZE; i++) { | 91 | for (i = 0; i < SNDRV_MASK_SIZE; i++) { |
| 101 | if (mask->bits[i]) | 92 | if (mask->bits[i]) |
| 102 | return ffs(mask->bits[i]) - 1 + (i << 5); | 93 | return ffs(mask->bits[i]) - 1 + (i << 5); |
| @@ -104,10 +95,9 @@ INLINE unsigned int snd_mask_min(const struct snd_mask *mask) | |||
| 104 | return 0; | 95 | return 0; |
| 105 | } | 96 | } |
| 106 | 97 | ||
| 107 | INLINE unsigned int snd_mask_max(const struct snd_mask *mask) | 98 | static inline unsigned int snd_mask_max(const struct snd_mask *mask) |
| 108 | { | 99 | { |
| 109 | int i; | 100 | int i; |
| 110 | assert(!snd_mask_empty(mask)); | ||
| 111 | for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) { | 101 | for (i = SNDRV_MASK_SIZE - 1; i >= 0; i--) { |
| 112 | if (mask->bits[i]) | 102 | if (mask->bits[i]) |
| 113 | return ld2(mask->bits[i]) + (i << 5); | 103 | return ld2(mask->bits[i]) + (i << 5); |
| @@ -115,70 +105,68 @@ INLINE unsigned int snd_mask_max(const struct snd_mask *mask) | |||
| 115 | return 0; | 105 | return 0; |
| 116 | } | 106 | } |
| 117 | 107 | ||
| 118 | INLINE void snd_mask_set(struct snd_mask *mask, unsigned int val) | 108 | static inline void snd_mask_set(struct snd_mask *mask, unsigned int val) |
| 119 | { | 109 | { |
| 120 | assert(val <= SNDRV_MASK_BITS); | ||
| 121 | mask->bits[MASK_OFS(val)] |= MASK_BIT(val); | 110 | mask->bits[MASK_OFS(val)] |= MASK_BIT(val); |
| 122 | } | 111 | } |
| 123 | 112 | ||
| 124 | INLINE void snd_mask_reset(struct snd_mask *mask, unsigned int val) | 113 | static inline void snd_mask_reset(struct snd_mask *mask, unsigned int val) |
| 125 | { | 114 | { |
| 126 | assert(val <= SNDRV_MASK_BITS); | ||
| 127 | mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val); | 115 | mask->bits[MASK_OFS(val)] &= ~MASK_BIT(val); |
| 128 | } | 116 | } |
| 129 | 117 | ||
| 130 | INLINE void snd_mask_set_range(struct snd_mask *mask, unsigned int from, unsigned int to) | 118 | static inline void snd_mask_set_range(struct snd_mask *mask, |
| 119 | unsigned int from, unsigned int to) | ||
| 131 | { | 120 | { |
| 132 | unsigned int i; | 121 | unsigned int i; |
| 133 | assert(to <= SNDRV_MASK_BITS && from <= to); | ||
| 134 | for (i = from; i <= to; i++) | 122 | for (i = from; i <= to; i++) |
| 135 | mask->bits[MASK_OFS(i)] |= MASK_BIT(i); | 123 | mask->bits[MASK_OFS(i)] |= MASK_BIT(i); |
| 136 | } | 124 | } |
| 137 | 125 | ||
| 138 | INLINE void snd_mask_reset_range(struct snd_mask *mask, unsigned int from, unsigned int to) | 126 | static inline void snd_mask_reset_range(struct snd_mask *mask, |
| 127 | unsigned int from, unsigned int to) | ||
| 139 | { | 128 | { |
| 140 | unsigned int i; | 129 | unsigned int i; |
| 141 | assert(to <= SNDRV_MASK_BITS && from <= to); | ||
| 142 | for (i = from; i <= to; i++) | 130 | for (i = from; i <= to; i++) |
| 143 | mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i); | 131 | mask->bits[MASK_OFS(i)] &= ~MASK_BIT(i); |
| 144 | } | 132 | } |
| 145 | 133 | ||
| 146 | INLINE void snd_mask_leave(struct snd_mask *mask, unsigned int val) | 134 | static inline void snd_mask_leave(struct snd_mask *mask, unsigned int val) |
| 147 | { | 135 | { |
| 148 | unsigned int v; | 136 | unsigned int v; |
| 149 | assert(val <= SNDRV_MASK_BITS); | ||
| 150 | v = mask->bits[MASK_OFS(val)] & MASK_BIT(val); | 137 | v = mask->bits[MASK_OFS(val)] & MASK_BIT(val); |
| 151 | snd_mask_none(mask); | 138 | snd_mask_none(mask); |
| 152 | mask->bits[MASK_OFS(val)] = v; | 139 | mask->bits[MASK_OFS(val)] = v; |
| 153 | } | 140 | } |
| 154 | 141 | ||
| 155 | INLINE void snd_mask_intersect(struct snd_mask *mask, const struct snd_mask *v) | 142 | static inline void snd_mask_intersect(struct snd_mask *mask, |
| 143 | const struct snd_mask *v) | ||
| 156 | { | 144 | { |
| 157 | int i; | 145 | int i; |
| 158 | for (i = 0; i < SNDRV_MASK_SIZE; i++) | 146 | for (i = 0; i < SNDRV_MASK_SIZE; i++) |
| 159 | mask->bits[i] &= v->bits[i]; | 147 | mask->bits[i] &= v->bits[i]; |
| 160 | } | 148 | } |
| 161 | 149 | ||
| 162 | INLINE int snd_mask_eq(const struct snd_mask *mask, const struct snd_mask *v) | 150 | static inline int snd_mask_eq(const struct snd_mask *mask, |
| 151 | const struct snd_mask *v) | ||
| 163 | { | 152 | { |
| 164 | return ! memcmp(mask, v, SNDRV_MASK_SIZE * sizeof(u_int32_t)); | 153 | return ! memcmp(mask, v, SNDRV_MASK_SIZE * sizeof(u_int32_t)); |
| 165 | } | 154 | } |
| 166 | 155 | ||
| 167 | INLINE void snd_mask_copy(struct snd_mask *mask, const struct snd_mask *v) | 156 | static inline void snd_mask_copy(struct snd_mask *mask, |
| 157 | const struct snd_mask *v) | ||
| 168 | { | 158 | { |
| 169 | *mask = *v; | 159 | *mask = *v; |
| 170 | } | 160 | } |
| 171 | 161 | ||
| 172 | INLINE int snd_mask_test(const struct snd_mask *mask, unsigned int val) | 162 | static inline int snd_mask_test(const struct snd_mask *mask, unsigned int val) |
| 173 | { | 163 | { |
| 174 | assert(val <= SNDRV_MASK_BITS); | ||
| 175 | return mask->bits[MASK_OFS(val)] & MASK_BIT(val); | 164 | return mask->bits[MASK_OFS(val)] & MASK_BIT(val); |
| 176 | } | 165 | } |
| 177 | 166 | ||
| 178 | INLINE int snd_mask_single(const struct snd_mask *mask) | 167 | static inline int snd_mask_single(const struct snd_mask *mask) |
| 179 | { | 168 | { |
| 180 | int i, c = 0; | 169 | int i, c = 0; |
| 181 | assert(!snd_mask_empty(mask)); | ||
| 182 | for (i = 0; i < SNDRV_MASK_SIZE; i++) { | 170 | for (i = 0; i < SNDRV_MASK_SIZE; i++) { |
| 183 | if (! mask->bits[i]) | 171 | if (! mask->bits[i]) |
| 184 | continue; | 172 | continue; |
| @@ -191,10 +179,10 @@ INLINE int snd_mask_single(const struct snd_mask *mask) | |||
| 191 | return 1; | 179 | return 1; |
| 192 | } | 180 | } |
| 193 | 181 | ||
| 194 | INLINE int snd_mask_refine(struct snd_mask *mask, const struct snd_mask *v) | 182 | static inline int snd_mask_refine(struct snd_mask *mask, |
| 183 | const struct snd_mask *v) | ||
| 195 | { | 184 | { |
| 196 | struct snd_mask old; | 185 | struct snd_mask old; |
| 197 | assert(!snd_mask_empty(mask)); | ||
| 198 | snd_mask_copy(&old, mask); | 186 | snd_mask_copy(&old, mask); |
| 199 | snd_mask_intersect(mask, v); | 187 | snd_mask_intersect(mask, v); |
| 200 | if (snd_mask_empty(mask)) | 188 | if (snd_mask_empty(mask)) |
| @@ -202,27 +190,24 @@ INLINE int snd_mask_refine(struct snd_mask *mask, const struct snd_mask *v) | |||
| 202 | return !snd_mask_eq(mask, &old); | 190 | return !snd_mask_eq(mask, &old); |
| 203 | } | 191 | } |
| 204 | 192 | ||
| 205 | INLINE int snd_mask_refine_first(struct snd_mask *mask) | 193 | static inline int snd_mask_refine_first(struct snd_mask *mask) |
| 206 | { | 194 | { |
| 207 | assert(!snd_mask_empty(mask)); | ||
| 208 | if (snd_mask_single(mask)) | 195 | if (snd_mask_single(mask)) |
| 209 | return 0; | 196 | return 0; |
| 210 | snd_mask_leave(mask, snd_mask_min(mask)); | 197 | snd_mask_leave(mask, snd_mask_min(mask)); |
| 211 | return 1; | 198 | return 1; |
| 212 | } | 199 | } |
| 213 | 200 | ||
| 214 | INLINE int snd_mask_refine_last(struct snd_mask *mask) | 201 | static inline int snd_mask_refine_last(struct snd_mask *mask) |
| 215 | { | 202 | { |
| 216 | assert(!snd_mask_empty(mask)); | ||
| 217 | if (snd_mask_single(mask)) | 203 | if (snd_mask_single(mask)) |
| 218 | return 0; | 204 | return 0; |
| 219 | snd_mask_leave(mask, snd_mask_max(mask)); | 205 | snd_mask_leave(mask, snd_mask_max(mask)); |
| 220 | return 1; | 206 | return 1; |
| 221 | } | 207 | } |
| 222 | 208 | ||
| 223 | INLINE int snd_mask_refine_min(struct snd_mask *mask, unsigned int val) | 209 | static inline int snd_mask_refine_min(struct snd_mask *mask, unsigned int val) |
| 224 | { | 210 | { |
| 225 | assert(!snd_mask_empty(mask)); | ||
| 226 | if (snd_mask_min(mask) >= val) | 211 | if (snd_mask_min(mask) >= val) |
| 227 | return 0; | 212 | return 0; |
| 228 | snd_mask_reset_range(mask, 0, val - 1); | 213 | snd_mask_reset_range(mask, 0, val - 1); |
| @@ -231,9 +216,8 @@ INLINE int snd_mask_refine_min(struct snd_mask *mask, unsigned int val) | |||
| 231 | return 1; | 216 | return 1; |
| 232 | } | 217 | } |
| 233 | 218 | ||
| 234 | INLINE int snd_mask_refine_max(struct snd_mask *mask, unsigned int val) | 219 | static inline int snd_mask_refine_max(struct snd_mask *mask, unsigned int val) |
| 235 | { | 220 | { |
| 236 | assert(!snd_mask_empty(mask)); | ||
| 237 | if (snd_mask_max(mask) <= val) | 221 | if (snd_mask_max(mask) <= val) |
| 238 | return 0; | 222 | return 0; |
| 239 | snd_mask_reset_range(mask, val + 1, SNDRV_MASK_BITS); | 223 | snd_mask_reset_range(mask, val + 1, SNDRV_MASK_BITS); |
| @@ -242,10 +226,9 @@ INLINE int snd_mask_refine_max(struct snd_mask *mask, unsigned int val) | |||
| 242 | return 1; | 226 | return 1; |
| 243 | } | 227 | } |
| 244 | 228 | ||
| 245 | INLINE int snd_mask_refine_set(struct snd_mask *mask, unsigned int val) | 229 | static inline int snd_mask_refine_set(struct snd_mask *mask, unsigned int val) |
| 246 | { | 230 | { |
| 247 | int changed; | 231 | int changed; |
| 248 | assert(!snd_mask_empty(mask)); | ||
| 249 | changed = !snd_mask_single(mask); | 232 | changed = !snd_mask_single(mask); |
| 250 | snd_mask_leave(mask, val); | 233 | snd_mask_leave(mask, val); |
| 251 | if (snd_mask_empty(mask)) | 234 | if (snd_mask_empty(mask)) |
| @@ -253,13 +236,12 @@ INLINE int snd_mask_refine_set(struct snd_mask *mask, unsigned int val) | |||
| 253 | return changed; | 236 | return changed; |
| 254 | } | 237 | } |
| 255 | 238 | ||
| 256 | INLINE int snd_mask_value(const struct snd_mask *mask) | 239 | static inline int snd_mask_value(const struct snd_mask *mask) |
| 257 | { | 240 | { |
| 258 | assert(!snd_mask_empty(mask)); | ||
| 259 | return snd_mask_min(mask); | 241 | return snd_mask_min(mask); |
| 260 | } | 242 | } |
| 261 | 243 | ||
| 262 | INLINE void snd_interval_any(struct snd_interval *i) | 244 | static inline void snd_interval_any(struct snd_interval *i) |
| 263 | { | 245 | { |
| 264 | i->min = 0; | 246 | i->min = 0; |
| 265 | i->openmin = 0; | 247 | i->openmin = 0; |
| @@ -269,63 +251,59 @@ INLINE void snd_interval_any(struct snd_interval *i) | |||
| 269 | i->empty = 0; | 251 | i->empty = 0; |
| 270 | } | 252 | } |
| 271 | 253 | ||
| 272 | INLINE void snd_interval_none(struct snd_interval *i) | 254 | static inline void snd_interval_none(struct snd_interval *i) |
| 273 | { | 255 | { |
| 274 | i->empty = 1; | 256 | i->empty = 1; |
| 275 | } | 257 | } |
| 276 | 258 | ||
| 277 | INLINE int snd_interval_checkempty(const struct snd_interval *i) | 259 | static inline int snd_interval_checkempty(const struct snd_interval *i) |
| 278 | { | 260 | { |
| 279 | return (i->min > i->max || | 261 | return (i->min > i->max || |
| 280 | (i->min == i->max && (i->openmin || i->openmax))); | 262 | (i->min == i->max && (i->openmin || i->openmax))); |
| 281 | } | 263 | } |
| 282 | 264 | ||
| 283 | INLINE int snd_interval_empty(const struct snd_interval *i) | 265 | static inline int snd_interval_empty(const struct snd_interval *i) |
| 284 | { | 266 | { |
| 285 | return i->empty; | 267 | return i->empty; |
| 286 | } | 268 | } |
| 287 | 269 | ||
| 288 | INLINE int snd_interval_single(const struct snd_interval *i) | 270 | static inline int snd_interval_single(const struct snd_interval *i) |
| 289 | { | 271 | { |
| 290 | assert(!snd_interval_empty(i)); | ||
| 291 | return (i->min == i->max || | 272 | return (i->min == i->max || |
| 292 | (i->min + 1 == i->max && i->openmax)); | 273 | (i->min + 1 == i->max && i->openmax)); |
| 293 | } | 274 | } |
| 294 | 275 | ||
| 295 | INLINE int snd_interval_value(const struct snd_interval *i) | 276 | static inline int snd_interval_value(const struct snd_interval *i) |
| 296 | { | 277 | { |
| 297 | assert(snd_interval_single(i)); | ||
| 298 | return i->min; | 278 | return i->min; |
| 299 | } | 279 | } |
| 300 | 280 | ||
| 301 | INLINE int snd_interval_min(const struct snd_interval *i) | 281 | static inline int snd_interval_min(const struct snd_interval *i) |
| 302 | { | 282 | { |
| 303 | assert(!snd_interval_empty(i)); | ||
| 304 | return i->min; | 283 | return i->min; |
| 305 | } | 284 | } |
| 306 | 285 | ||
| 307 | INLINE int snd_interval_max(const struct snd_interval *i) | 286 | static inline int snd_interval_max(const struct snd_interval *i) |
| 308 | { | 287 | { |
| 309 | unsigned int v; | 288 | unsigned int v; |
| 310 | assert(!snd_interval_empty(i)); | ||
| 311 | v = i->max; | 289 | v = i->max; |
| 312 | if (i->openmax) | 290 | if (i->openmax) |
| 313 | v--; | 291 | v--; |
| 314 | return v; | 292 | return v; |
| 315 | } | 293 | } |
| 316 | 294 | ||
| 317 | INLINE int snd_interval_test(const struct snd_interval *i, unsigned int val) | 295 | static inline int snd_interval_test(const struct snd_interval *i, unsigned int val) |
| 318 | { | 296 | { |
| 319 | return !((i->min > val || (i->min == val && i->openmin) || | 297 | return !((i->min > val || (i->min == val && i->openmin) || |
| 320 | i->max < val || (i->max == val && i->openmax))); | 298 | i->max < val || (i->max == val && i->openmax))); |
| 321 | } | 299 | } |
| 322 | 300 | ||
| 323 | INLINE void snd_interval_copy(struct snd_interval *d, const struct snd_interval *s) | 301 | static inline void snd_interval_copy(struct snd_interval *d, const struct snd_interval *s) |
| 324 | { | 302 | { |
| 325 | *d = *s; | 303 | *d = *s; |
| 326 | } | 304 | } |
| 327 | 305 | ||
| 328 | INLINE int snd_interval_setinteger(struct snd_interval *i) | 306 | static inline int snd_interval_setinteger(struct snd_interval *i) |
| 329 | { | 307 | { |
| 330 | if (i->integer) | 308 | if (i->integer) |
| 331 | return 0; | 309 | return 0; |
| @@ -335,7 +313,7 @@ INLINE int snd_interval_setinteger(struct snd_interval *i) | |||
| 335 | return 1; | 313 | return 1; |
| 336 | } | 314 | } |
| 337 | 315 | ||
| 338 | INLINE int snd_interval_eq(const struct snd_interval *i1, const struct snd_interval *i2) | 316 | static inline int snd_interval_eq(const struct snd_interval *i1, const struct snd_interval *i2) |
| 339 | { | 317 | { |
| 340 | if (i1->empty) | 318 | if (i1->empty) |
| 341 | return i2->empty; | 319 | return i2->empty; |
| @@ -359,8 +337,5 @@ static inline unsigned int sub(unsigned int a, unsigned int b) | |||
| 359 | return 0; | 337 | return 0; |
| 360 | } | 338 | } |
| 361 | 339 | ||
| 362 | #undef INLINE | ||
| 363 | #undef assert | ||
| 364 | |||
| 365 | #endif /* __SOUND_PCM_PARAMS_H */ | 340 | #endif /* __SOUND_PCM_PARAMS_H */ |
| 366 | 341 | ||
diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index 584e73dd4793..7dbcd10fa215 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | 46 | ||
| 47 | struct snd_rawmidi; | 47 | struct snd_rawmidi; |
| 48 | struct snd_rawmidi_substream; | 48 | struct snd_rawmidi_substream; |
| 49 | struct snd_seq_port_info; | ||
| 49 | 50 | ||
| 50 | struct snd_rawmidi_ops { | 51 | struct snd_rawmidi_ops { |
| 51 | int (*open) (struct snd_rawmidi_substream * substream); | 52 | int (*open) (struct snd_rawmidi_substream * substream); |
| @@ -57,6 +58,8 @@ struct snd_rawmidi_ops { | |||
| 57 | struct snd_rawmidi_global_ops { | 58 | struct snd_rawmidi_global_ops { |
| 58 | int (*dev_register) (struct snd_rawmidi * rmidi); | 59 | int (*dev_register) (struct snd_rawmidi * rmidi); |
| 59 | int (*dev_unregister) (struct snd_rawmidi * rmidi); | 60 | int (*dev_unregister) (struct snd_rawmidi * rmidi); |
| 61 | void (*get_port_info)(struct snd_rawmidi *rmidi, int number, | ||
| 62 | struct snd_seq_port_info *info); | ||
| 60 | }; | 63 | }; |
| 61 | 64 | ||
| 62 | struct snd_rawmidi_runtime { | 65 | struct snd_rawmidi_runtime { |
diff --git a/include/sound/version.h b/include/sound/version.h index 4f0e65808cf1..2ee849d0e198 100644 --- a/include/sound/version.h +++ b/include/sound/version.h | |||
| @@ -1,3 +1,3 @@ | |||
| 1 | /* include/version.h. Generated by configure. */ | 1 | /* include/version.h. Generated by configure. */ |
| 2 | #define CONFIG_SND_VERSION "1.0.11rc4" | 2 | #define CONFIG_SND_VERSION "1.0.12rc1" |
| 3 | #define CONFIG_SND_DATE " (Wed Mar 22 10:27:24 2006 UTC)" | 3 | #define CONFIG_SND_DATE " (Thu Jun 22 13:55:50 2006 UTC)" |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 0a907f0dc56b..cdf0f07af92f 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
| 16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
| 17 | #include <linux/pm.h> | 17 | #include <linux/pm.h> |
| 18 | 18 | #include <linux/console.h> | |
| 19 | 19 | ||
| 20 | #include "power.h" | 20 | #include "power.h" |
| 21 | 21 | ||
diff --git a/kernel/sys.c b/kernel/sys.c index 0b6ec0e7936f..fc9ebbbaba0c 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
| @@ -1860,23 +1860,20 @@ out: | |||
| 1860 | * fields when reaping, so a sample either gets all the additions of a | 1860 | * fields when reaping, so a sample either gets all the additions of a |
| 1861 | * given child after it's reaped, or none so this sample is before reaping. | 1861 | * given child after it's reaped, or none so this sample is before reaping. |
| 1862 | * | 1862 | * |
| 1863 | * tasklist_lock locking optimisation: | 1863 | * Locking: |
| 1864 | * If we are current and single threaded, we do not need to take the tasklist | 1864 | * We need to take the siglock for CHILDEREN, SELF and BOTH |
| 1865 | * lock or the siglock. No one else can take our signal_struct away, | 1865 | * for the cases current multithreaded, non-current single threaded |
| 1866 | * no one else can reap the children to update signal->c* counters, and | 1866 | * non-current multithreaded. Thread traversal is now safe with |
| 1867 | * no one else can race with the signal-> fields. | 1867 | * the siglock held. |
| 1868 | * If we do not take the tasklist_lock, the signal-> fields could be read | 1868 | * Strictly speaking, we donot need to take the siglock if we are current and |
| 1869 | * out of order while another thread was just exiting. So we place a | 1869 | * single threaded, as no one else can take our signal_struct away, no one |
| 1870 | * read memory barrier when we avoid the lock. On the writer side, | 1870 | * else can reap the children to update signal->c* counters, and no one else |
| 1871 | * write memory barrier is implied in __exit_signal as __exit_signal releases | 1871 | * can race with the signal-> fields. If we do not take any lock, the |
| 1872 | * the siglock spinlock after updating the signal-> fields. | 1872 | * signal-> fields could be read out of order while another thread was just |
| 1873 | * | 1873 | * exiting. So we should place a read memory barrier when we avoid the lock. |
| 1874 | * We don't really need the siglock when we access the non c* fields | 1874 | * On the writer side, write memory barrier is implied in __exit_signal |
| 1875 | * of the signal_struct (for RUSAGE_SELF) even in multithreaded | 1875 | * as __exit_signal releases the siglock spinlock after updating the signal-> |
| 1876 | * case, since we take the tasklist lock for read and the non c* signal-> | 1876 | * fields. But we don't do this yet to keep things simple. |
| 1877 | * fields are updated only in __exit_signal, which is called with | ||
| 1878 | * tasklist_lock taken for write, hence these two threads cannot execute | ||
| 1879 | * concurrently. | ||
| 1880 | * | 1877 | * |
| 1881 | */ | 1878 | */ |
| 1882 | 1879 | ||
| @@ -1885,35 +1882,25 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
| 1885 | struct task_struct *t; | 1882 | struct task_struct *t; |
| 1886 | unsigned long flags; | 1883 | unsigned long flags; |
| 1887 | cputime_t utime, stime; | 1884 | cputime_t utime, stime; |
| 1888 | int need_lock = 0; | ||
| 1889 | 1885 | ||
| 1890 | memset((char *) r, 0, sizeof *r); | 1886 | memset((char *) r, 0, sizeof *r); |
| 1891 | utime = stime = cputime_zero; | 1887 | utime = stime = cputime_zero; |
| 1892 | 1888 | ||
| 1893 | if (p != current || !thread_group_empty(p)) | 1889 | rcu_read_lock(); |
| 1894 | need_lock = 1; | 1890 | if (!lock_task_sighand(p, &flags)) { |
| 1895 | 1891 | rcu_read_unlock(); | |
| 1896 | if (need_lock) { | 1892 | return; |
| 1897 | read_lock(&tasklist_lock); | 1893 | } |
| 1898 | if (unlikely(!p->signal)) { | ||
| 1899 | read_unlock(&tasklist_lock); | ||
| 1900 | return; | ||
| 1901 | } | ||
| 1902 | } else | ||
| 1903 | /* See locking comments above */ | ||
| 1904 | smp_rmb(); | ||
| 1905 | 1894 | ||
| 1906 | switch (who) { | 1895 | switch (who) { |
| 1907 | case RUSAGE_BOTH: | 1896 | case RUSAGE_BOTH: |
| 1908 | case RUSAGE_CHILDREN: | 1897 | case RUSAGE_CHILDREN: |
| 1909 | spin_lock_irqsave(&p->sighand->siglock, flags); | ||
| 1910 | utime = p->signal->cutime; | 1898 | utime = p->signal->cutime; |
| 1911 | stime = p->signal->cstime; | 1899 | stime = p->signal->cstime; |
| 1912 | r->ru_nvcsw = p->signal->cnvcsw; | 1900 | r->ru_nvcsw = p->signal->cnvcsw; |
| 1913 | r->ru_nivcsw = p->signal->cnivcsw; | 1901 | r->ru_nivcsw = p->signal->cnivcsw; |
| 1914 | r->ru_minflt = p->signal->cmin_flt; | 1902 | r->ru_minflt = p->signal->cmin_flt; |
| 1915 | r->ru_majflt = p->signal->cmaj_flt; | 1903 | r->ru_majflt = p->signal->cmaj_flt; |
| 1916 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | ||
| 1917 | 1904 | ||
| 1918 | if (who == RUSAGE_CHILDREN) | 1905 | if (who == RUSAGE_CHILDREN) |
| 1919 | break; | 1906 | break; |
| @@ -1941,8 +1928,9 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
| 1941 | BUG(); | 1928 | BUG(); |
| 1942 | } | 1929 | } |
| 1943 | 1930 | ||
| 1944 | if (need_lock) | 1931 | unlock_task_sighand(p, &flags); |
| 1945 | read_unlock(&tasklist_lock); | 1932 | rcu_read_unlock(); |
| 1933 | |||
| 1946 | cputime_to_timeval(utime, &r->ru_utime); | 1934 | cputime_to_timeval(utime, &r->ru_utime); |
| 1947 | cputime_to_timeval(stime, &r->ru_stime); | 1935 | cputime_to_timeval(stime, &r->ru_stime); |
| 1948 | } | 1936 | } |
diff --git a/kernel/user.c b/kernel/user.c index 4b1eb745afa1..6408c0424291 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
| @@ -148,7 +148,7 @@ struct user_struct * alloc_uid(uid_t uid) | |||
| 148 | new->mq_bytes = 0; | 148 | new->mq_bytes = 0; |
| 149 | new->locked_shm = 0; | 149 | new->locked_shm = 0; |
| 150 | 150 | ||
| 151 | if (alloc_uid_keyring(new) < 0) { | 151 | if (alloc_uid_keyring(new, current) < 0) { |
| 152 | kmem_cache_free(uid_cachep, new); | 152 | kmem_cache_free(uid_cachep, new); |
| 153 | return NULL; | 153 | return NULL; |
| 154 | } | 154 | } |
diff --git a/lib/kobject.c b/lib/kobject.c index 687ab418d292..8e7c71993487 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
| @@ -198,14 +198,14 @@ int kobject_add(struct kobject * kobj) | |||
| 198 | 198 | ||
| 199 | /* be noisy on error issues */ | 199 | /* be noisy on error issues */ |
| 200 | if (error == -EEXIST) | 200 | if (error == -EEXIST) |
| 201 | pr_debug("kobject_add failed for %s with -EEXIST, " | 201 | printk("kobject_add failed for %s with -EEXIST, " |
| 202 | "don't try to register things with the " | 202 | "don't try to register things with the " |
| 203 | "same name in the same directory.\n", | 203 | "same name in the same directory.\n", |
| 204 | kobject_name(kobj)); | 204 | kobject_name(kobj)); |
| 205 | else | 205 | else |
| 206 | pr_debug("kobject_add failed for %s (%d)\n", | 206 | printk("kobject_add failed for %s (%d)\n", |
| 207 | kobject_name(kobj), error); | 207 | kobject_name(kobj), error); |
| 208 | /* dump_stack(); */ | 208 | dump_stack(); |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | return error; | 211 | return error; |
diff --git a/lib/zlib_deflate/deflate.c b/lib/zlib_deflate/deflate.c index 1653dd9bb01a..c3e4a2baf835 100644 --- a/lib/zlib_deflate/deflate.c +++ b/lib/zlib_deflate/deflate.c | |||
| @@ -164,34 +164,17 @@ static const config configuration_table[10] = { | |||
| 164 | memset((char *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head)); | 164 | memset((char *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head)); |
| 165 | 165 | ||
| 166 | /* ========================================================================= */ | 166 | /* ========================================================================= */ |
| 167 | int zlib_deflateInit_( | 167 | int zlib_deflateInit2( |
| 168 | z_streamp strm, | ||
| 169 | int level, | ||
| 170 | const char *version, | ||
| 171 | int stream_size | ||
| 172 | ) | ||
| 173 | { | ||
| 174 | return zlib_deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, | ||
| 175 | DEF_MEM_LEVEL, | ||
| 176 | Z_DEFAULT_STRATEGY, version, stream_size); | ||
| 177 | /* To do: ignore strm->next_in if we use it as window */ | ||
| 178 | } | ||
| 179 | |||
| 180 | /* ========================================================================= */ | ||
| 181 | int zlib_deflateInit2_( | ||
| 182 | z_streamp strm, | 168 | z_streamp strm, |
| 183 | int level, | 169 | int level, |
| 184 | int method, | 170 | int method, |
| 185 | int windowBits, | 171 | int windowBits, |
| 186 | int memLevel, | 172 | int memLevel, |
| 187 | int strategy, | 173 | int strategy |
| 188 | const char *version, | ||
| 189 | int stream_size | ||
| 190 | ) | 174 | ) |
| 191 | { | 175 | { |
| 192 | deflate_state *s; | 176 | deflate_state *s; |
| 193 | int noheader = 0; | 177 | int noheader = 0; |
| 194 | static char* my_version = ZLIB_VERSION; | ||
| 195 | deflate_workspace *mem; | 178 | deflate_workspace *mem; |
| 196 | 179 | ||
| 197 | ush *overlay; | 180 | ush *overlay; |
| @@ -199,10 +182,6 @@ int zlib_deflateInit2_( | |||
| 199 | * output size for (length,distance) codes is <= 24 bits. | 182 | * output size for (length,distance) codes is <= 24 bits. |
| 200 | */ | 183 | */ |
| 201 | 184 | ||
| 202 | if (version == NULL || version[0] != my_version[0] || | ||
| 203 | stream_size != sizeof(z_stream)) { | ||
| 204 | return Z_VERSION_ERROR; | ||
| 205 | } | ||
| 206 | if (strm == NULL) return Z_STREAM_ERROR; | 185 | if (strm == NULL) return Z_STREAM_ERROR; |
| 207 | 186 | ||
| 208 | strm->msg = NULL; | 187 | strm->msg = NULL; |
diff --git a/lib/zlib_deflate/deflate_syms.c b/lib/zlib_deflate/deflate_syms.c index 767b573d1ef6..ccfe25f3920f 100644 --- a/lib/zlib_deflate/deflate_syms.c +++ b/lib/zlib_deflate/deflate_syms.c | |||
| @@ -12,8 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | EXPORT_SYMBOL(zlib_deflate_workspacesize); | 13 | EXPORT_SYMBOL(zlib_deflate_workspacesize); |
| 14 | EXPORT_SYMBOL(zlib_deflate); | 14 | EXPORT_SYMBOL(zlib_deflate); |
| 15 | EXPORT_SYMBOL(zlib_deflateInit_); | 15 | EXPORT_SYMBOL(zlib_deflateInit2); |
| 16 | EXPORT_SYMBOL(zlib_deflateInit2_); | ||
| 17 | EXPORT_SYMBOL(zlib_deflateEnd); | 16 | EXPORT_SYMBOL(zlib_deflateEnd); |
| 18 | EXPORT_SYMBOL(zlib_deflateReset); | 17 | EXPORT_SYMBOL(zlib_deflateReset); |
| 19 | MODULE_LICENSE("GPL"); | 18 | MODULE_LICENSE("GPL"); |
diff --git a/lib/zlib_inflate/Makefile b/lib/zlib_inflate/Makefile index 221c139e0df1..bf065482fa67 100644 --- a/lib/zlib_inflate/Makefile +++ b/lib/zlib_inflate/Makefile | |||
| @@ -15,5 +15,5 @@ | |||
| 15 | 15 | ||
| 16 | obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate.o | 16 | obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate.o |
| 17 | 17 | ||
| 18 | zlib_inflate-objs := infblock.o infcodes.o inffast.o inflate.o \ | 18 | zlib_inflate-objs := inffast.o inflate.o \ |
| 19 | inflate_sync.o inftrees.o infutil.o inflate_syms.o | 19 | inftrees.o inflate_syms.o |
diff --git a/lib/zlib_inflate/infblock.c b/lib/zlib_inflate/infblock.c deleted file mode 100644 index c16cdeff51aa..000000000000 --- a/lib/zlib_inflate/infblock.c +++ /dev/null | |||
| @@ -1,365 +0,0 @@ | |||
| 1 | /* infblock.c -- interpret and process block types to last block | ||
| 2 | * Copyright (C) 1995-1998 Mark Adler | ||
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/zutil.h> | ||
| 7 | #include "infblock.h" | ||
| 8 | #include "inftrees.h" | ||
| 9 | #include "infcodes.h" | ||
| 10 | #include "infutil.h" | ||
| 11 | |||
| 12 | struct inflate_codes_state; | ||
| 13 | |||
| 14 | /* simplify the use of the inflate_huft type with some defines */ | ||
| 15 | #define exop word.what.Exop | ||
| 16 | #define bits word.what.Bits | ||
| 17 | |||
| 18 | /* Table for deflate from PKZIP's appnote.txt. */ | ||
| 19 | static const uInt border[] = { /* Order of the bit length code lengths */ | ||
| 20 | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; | ||
| 21 | |||
| 22 | /* | ||
| 23 | Notes beyond the 1.93a appnote.txt: | ||
| 24 | |||
| 25 | 1. Distance pointers never point before the beginning of the output | ||
| 26 | stream. | ||
| 27 | 2. Distance pointers can point back across blocks, up to 32k away. | ||
| 28 | 3. There is an implied maximum of 7 bits for the bit length table and | ||
| 29 | 15 bits for the actual data. | ||
| 30 | 4. If only one code exists, then it is encoded using one bit. (Zero | ||
| 31 | would be more efficient, but perhaps a little confusing.) If two | ||
| 32 | codes exist, they are coded using one bit each (0 and 1). | ||
| 33 | 5. There is no way of sending zero distance codes--a dummy must be | ||
| 34 | sent if there are none. (History: a pre 2.0 version of PKZIP would | ||
| 35 | store blocks with no distance codes, but this was discovered to be | ||
| 36 | too harsh a criterion.) Valid only for 1.93a. 2.04c does allow | ||
| 37 | zero distance codes, which is sent as one code of zero bits in | ||
| 38 | length. | ||
| 39 | 6. There are up to 286 literal/length codes. Code 256 represents the | ||
| 40 | end-of-block. Note however that the static length tree defines | ||
| 41 | 288 codes just to fill out the Huffman codes. Codes 286 and 287 | ||
| 42 | cannot be used though, since there is no length base or extra bits | ||
| 43 | defined for them. Similarily, there are up to 30 distance codes. | ||
| 44 | However, static trees define 32 codes (all 5 bits) to fill out the | ||
| 45 | Huffman codes, but the last two had better not show up in the data. | ||
| 46 | 7. Unzip can check dynamic Huffman blocks for complete code sets. | ||
| 47 | The exception is that a single code would not be complete (see #4). | ||
| 48 | 8. The five bits following the block type is really the number of | ||
| 49 | literal codes sent minus 257. | ||
| 50 | 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits | ||
| 51 | (1+6+6). Therefore, to output three times the length, you output | ||
| 52 | three codes (1+1+1), whereas to output four times the same length, | ||
| 53 | you only need two codes (1+3). Hmm. | ||
| 54 | 10. In the tree reconstruction algorithm, Code = Code + Increment | ||
| 55 | only if BitLength(i) is not zero. (Pretty obvious.) | ||
| 56 | 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) | ||
| 57 | 12. Note: length code 284 can represent 227-258, but length code 285 | ||
| 58 | really is 258. The last length deserves its own, short code | ||
| 59 | since it gets used a lot in very redundant files. The length | ||
| 60 | 258 is special since 258 - 3 (the min match length) is 255. | ||
| 61 | 13. The literal/length and distance code bit lengths are read as a | ||
| 62 | single stream of lengths. It is possible (and advantageous) for | ||
| 63 | a repeat code (16, 17, or 18) to go across the boundary between | ||
| 64 | the two sets of lengths. | ||
| 65 | */ | ||
| 66 | |||
| 67 | |||
| 68 | void zlib_inflate_blocks_reset( | ||
| 69 | inflate_blocks_statef *s, | ||
| 70 | z_streamp z, | ||
| 71 | uLong *c | ||
| 72 | ) | ||
| 73 | { | ||
| 74 | if (c != NULL) | ||
| 75 | *c = s->check; | ||
| 76 | if (s->mode == CODES) | ||
| 77 | zlib_inflate_codes_free(s->sub.decode.codes, z); | ||
| 78 | s->mode = TYPE; | ||
| 79 | s->bitk = 0; | ||
| 80 | s->bitb = 0; | ||
| 81 | s->read = s->write = s->window; | ||
| 82 | if (s->checkfn != NULL) | ||
| 83 | z->adler = s->check = (*s->checkfn)(0L, NULL, 0); | ||
| 84 | } | ||
| 85 | |||
| 86 | inflate_blocks_statef *zlib_inflate_blocks_new( | ||
| 87 | z_streamp z, | ||
| 88 | check_func c, | ||
| 89 | uInt w | ||
| 90 | ) | ||
| 91 | { | ||
| 92 | inflate_blocks_statef *s; | ||
| 93 | |||
| 94 | s = &WS(z)->working_blocks_state; | ||
| 95 | s->hufts = WS(z)->working_hufts; | ||
| 96 | s->window = WS(z)->working_window; | ||
| 97 | s->end = s->window + w; | ||
| 98 | s->checkfn = c; | ||
| 99 | s->mode = TYPE; | ||
| 100 | zlib_inflate_blocks_reset(s, z, NULL); | ||
| 101 | return s; | ||
| 102 | } | ||
| 103 | |||
| 104 | |||
| 105 | int zlib_inflate_blocks( | ||
| 106 | inflate_blocks_statef *s, | ||
| 107 | z_streamp z, | ||
| 108 | int r | ||
| 109 | ) | ||
| 110 | { | ||
| 111 | uInt t; /* temporary storage */ | ||
| 112 | uLong b; /* bit buffer */ | ||
| 113 | uInt k; /* bits in bit buffer */ | ||
| 114 | Byte *p; /* input data pointer */ | ||
| 115 | uInt n; /* bytes available there */ | ||
| 116 | Byte *q; /* output window write pointer */ | ||
| 117 | uInt m; /* bytes to end of window or read pointer */ | ||
| 118 | |||
| 119 | /* copy input/output information to locals (UPDATE macro restores) */ | ||
| 120 | LOAD | ||
| 121 | |||
| 122 | /* process input based on current state */ | ||
| 123 | while (1) switch (s->mode) | ||
| 124 | { | ||
| 125 | case TYPE: | ||
| 126 | NEEDBITS(3) | ||
| 127 | t = (uInt)b & 7; | ||
| 128 | s->last = t & 1; | ||
| 129 | switch (t >> 1) | ||
| 130 | { | ||
| 131 | case 0: /* stored */ | ||
| 132 | DUMPBITS(3) | ||
| 133 | t = k & 7; /* go to byte boundary */ | ||
| 134 | DUMPBITS(t) | ||
| 135 | s->mode = LENS; /* get length of stored block */ | ||
| 136 | break; | ||
| 137 | case 1: /* fixed */ | ||
| 138 | { | ||
| 139 | uInt bl, bd; | ||
| 140 | inflate_huft *tl, *td; | ||
| 141 | |||
| 142 | zlib_inflate_trees_fixed(&bl, &bd, &tl, &td, s->hufts, z); | ||
| 143 | s->sub.decode.codes = zlib_inflate_codes_new(bl, bd, tl, td, z); | ||
| 144 | if (s->sub.decode.codes == NULL) | ||
| 145 | { | ||
| 146 | r = Z_MEM_ERROR; | ||
| 147 | LEAVE | ||
| 148 | } | ||
| 149 | } | ||
| 150 | DUMPBITS(3) | ||
| 151 | s->mode = CODES; | ||
| 152 | break; | ||
| 153 | case 2: /* dynamic */ | ||
| 154 | DUMPBITS(3) | ||
| 155 | s->mode = TABLE; | ||
| 156 | break; | ||
| 157 | case 3: /* illegal */ | ||
| 158 | DUMPBITS(3) | ||
| 159 | s->mode = B_BAD; | ||
| 160 | z->msg = (char*)"invalid block type"; | ||
| 161 | r = Z_DATA_ERROR; | ||
| 162 | LEAVE | ||
| 163 | } | ||
| 164 | break; | ||
| 165 | case LENS: | ||
| 166 | NEEDBITS(32) | ||
| 167 | if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) | ||
| 168 | { | ||
| 169 | s->mode = B_BAD; | ||
| 170 | z->msg = (char*)"invalid stored block lengths"; | ||
| 171 | r = Z_DATA_ERROR; | ||
| 172 | LEAVE | ||
| 173 | } | ||
| 174 | s->sub.left = (uInt)b & 0xffff; | ||
| 175 | b = k = 0; /* dump bits */ | ||
| 176 | s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); | ||
| 177 | break; | ||
| 178 | case STORED: | ||
| 179 | if (n == 0) | ||
| 180 | LEAVE | ||
| 181 | NEEDOUT | ||
| 182 | t = s->sub.left; | ||
| 183 | if (t > n) t = n; | ||
| 184 | if (t > m) t = m; | ||
| 185 | memcpy(q, p, t); | ||
| 186 | p += t; n -= t; | ||
| 187 | q += t; m -= t; | ||
| 188 | if ((s->sub.left -= t) != 0) | ||
| 189 | break; | ||
| 190 | s->mode = s->last ? DRY : TYPE; | ||
| 191 | break; | ||
| 192 | case TABLE: | ||
| 193 | NEEDBITS(14) | ||
| 194 | s->sub.trees.table = t = (uInt)b & 0x3fff; | ||
| 195 | #ifndef PKZIP_BUG_WORKAROUND | ||
| 196 | if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) | ||
| 197 | { | ||
| 198 | s->mode = B_BAD; | ||
| 199 | z->msg = (char*)"too many length or distance symbols"; | ||
| 200 | r = Z_DATA_ERROR; | ||
| 201 | LEAVE | ||
| 202 | } | ||
| 203 | #endif | ||
| 204 | { | ||
| 205 | s->sub.trees.blens = WS(z)->working_blens; | ||
| 206 | } | ||
| 207 | DUMPBITS(14) | ||
| 208 | s->sub.trees.index = 0; | ||
| 209 | s->mode = BTREE; | ||
| 210 | case BTREE: | ||
| 211 | while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) | ||
| 212 | { | ||
| 213 | NEEDBITS(3) | ||
| 214 | s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; | ||
| 215 | DUMPBITS(3) | ||
| 216 | } | ||
| 217 | while (s->sub.trees.index < 19) | ||
| 218 | s->sub.trees.blens[border[s->sub.trees.index++]] = 0; | ||
| 219 | s->sub.trees.bb = 7; | ||
| 220 | t = zlib_inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, | ||
| 221 | &s->sub.trees.tb, s->hufts, z); | ||
| 222 | if (t != Z_OK) | ||
| 223 | { | ||
| 224 | r = t; | ||
| 225 | if (r == Z_DATA_ERROR) | ||
| 226 | s->mode = B_BAD; | ||
| 227 | LEAVE | ||
| 228 | } | ||
| 229 | s->sub.trees.index = 0; | ||
| 230 | s->mode = DTREE; | ||
| 231 | case DTREE: | ||
| 232 | while (t = s->sub.trees.table, | ||
| 233 | s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) | ||
| 234 | { | ||
| 235 | inflate_huft *h; | ||
| 236 | uInt i, j, c; | ||
| 237 | |||
| 238 | t = s->sub.trees.bb; | ||
| 239 | NEEDBITS(t) | ||
| 240 | h = s->sub.trees.tb + ((uInt)b & zlib_inflate_mask[t]); | ||
| 241 | t = h->bits; | ||
| 242 | c = h->base; | ||
| 243 | if (c < 16) | ||
| 244 | { | ||
| 245 | DUMPBITS(t) | ||
| 246 | s->sub.trees.blens[s->sub.trees.index++] = c; | ||
| 247 | } | ||
| 248 | else /* c == 16..18 */ | ||
| 249 | { | ||
| 250 | i = c == 18 ? 7 : c - 14; | ||
| 251 | j = c == 18 ? 11 : 3; | ||
| 252 | NEEDBITS(t + i) | ||
| 253 | DUMPBITS(t) | ||
| 254 | j += (uInt)b & zlib_inflate_mask[i]; | ||
| 255 | DUMPBITS(i) | ||
| 256 | i = s->sub.trees.index; | ||
| 257 | t = s->sub.trees.table; | ||
| 258 | if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || | ||
| 259 | (c == 16 && i < 1)) | ||
| 260 | { | ||
| 261 | s->mode = B_BAD; | ||
| 262 | z->msg = (char*)"invalid bit length repeat"; | ||
| 263 | r = Z_DATA_ERROR; | ||
| 264 | LEAVE | ||
| 265 | } | ||
| 266 | c = c == 16 ? s->sub.trees.blens[i - 1] : 0; | ||
| 267 | do { | ||
| 268 | s->sub.trees.blens[i++] = c; | ||
| 269 | } while (--j); | ||
| 270 | s->sub.trees.index = i; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | s->sub.trees.tb = NULL; | ||
| 274 | { | ||
| 275 | uInt bl, bd; | ||
| 276 | inflate_huft *tl, *td; | ||
| 277 | inflate_codes_statef *c; | ||
| 278 | |||
| 279 | bl = 9; /* must be <= 9 for lookahead assumptions */ | ||
| 280 | bd = 6; /* must be <= 9 for lookahead assumptions */ | ||
| 281 | t = s->sub.trees.table; | ||
| 282 | t = zlib_inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), | ||
| 283 | s->sub.trees.blens, &bl, &bd, &tl, &td, | ||
| 284 | s->hufts, z); | ||
| 285 | if (t != Z_OK) | ||
| 286 | { | ||
| 287 | if (t == (uInt)Z_DATA_ERROR) | ||
| 288 | s->mode = B_BAD; | ||
| 289 | r = t; | ||
| 290 | LEAVE | ||
| 291 | } | ||
| 292 | if ((c = zlib_inflate_codes_new(bl, bd, tl, td, z)) == NULL) | ||
| 293 | { | ||
| 294 | r = Z_MEM_ERROR; | ||
| 295 | LEAVE | ||
| 296 | } | ||
| 297 | s->sub.decode.codes = c; | ||
| 298 | } | ||
| 299 | s->mode = CODES; | ||
| 300 | case CODES: | ||
| 301 | UPDATE | ||
| 302 | if ((r = zlib_inflate_codes(s, z, r)) != Z_STREAM_END) | ||
| 303 | return zlib_inflate_flush(s, z, r); | ||
| 304 | r = Z_OK; | ||
| 305 | zlib_inflate_codes_free(s->sub.decode.codes, z); | ||
| 306 | LOAD | ||
| 307 | if (!s->last) | ||
| 308 | { | ||
| 309 | s->mode = TYPE; | ||
| 310 | break; | ||
| 311 | } | ||
| 312 | s->mode = DRY; | ||
| 313 | case DRY: | ||
| 314 | FLUSH | ||
| 315 | if (s->read != s->write) | ||
| 316 | LEAVE | ||
| 317 | s->mode = B_DONE; | ||
| 318 | case B_DONE: | ||
| 319 | r = Z_STREAM_END; | ||
| 320 | LEAVE | ||
| 321 | case B_BAD: | ||
| 322 | r = Z_DATA_ERROR; | ||
| 323 | LEAVE | ||
| 324 | default: | ||
| 325 | r = Z_STREAM_ERROR; | ||
| 326 | LEAVE | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | |||
| 331 | int zlib_inflate_blocks_free( | ||
| 332 | inflate_blocks_statef *s, | ||
| 333 | z_streamp z | ||
| 334 | ) | ||
| 335 | { | ||
| 336 | zlib_inflate_blocks_reset(s, z, NULL); | ||
| 337 | return Z_OK; | ||
| 338 | } | ||
| 339 | |||
| 340 | |||
| 341 | #if 0 | ||
| 342 | void zlib_inflate_set_dictionary( | ||
| 343 | inflate_blocks_statef *s, | ||
| 344 | const Byte *d, | ||
| 345 | uInt n | ||
| 346 | ) | ||
| 347 | { | ||
| 348 | memcpy(s->window, d, n); | ||
| 349 | s->read = s->write = s->window + n; | ||
| 350 | } | ||
| 351 | #endif /* 0 */ | ||
| 352 | |||
| 353 | |||
| 354 | /* Returns true if inflate is currently at the end of a block generated | ||
| 355 | * by Z_SYNC_FLUSH or Z_FULL_FLUSH. | ||
| 356 | * IN assertion: s != NULL | ||
| 357 | */ | ||
| 358 | #if 0 | ||
| 359 | int zlib_inflate_blocks_sync_point( | ||
| 360 | inflate_blocks_statef *s | ||
| 361 | ) | ||
| 362 | { | ||
| 363 | return s->mode == LENS; | ||
| 364 | } | ||
| 365 | #endif /* 0 */ | ||
diff --git a/lib/zlib_inflate/infblock.h b/lib/zlib_inflate/infblock.h deleted file mode 100644 index ceee60b5107c..000000000000 --- a/lib/zlib_inflate/infblock.h +++ /dev/null | |||
| @@ -1,48 +0,0 @@ | |||
| 1 | /* infblock.h -- header to use infblock.c | ||
| 2 | * Copyright (C) 1995-1998 Mark Adler | ||
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | ||
| 4 | */ | ||
| 5 | |||
| 6 | /* WARNING: this file should *not* be used by applications. It is | ||
| 7 | part of the implementation of the compression library and is | ||
| 8 | subject to change. Applications should only use zlib.h. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _INFBLOCK_H | ||
| 12 | #define _INFBLOCK_H | ||
| 13 | |||
| 14 | struct inflate_blocks_state; | ||
| 15 | typedef struct inflate_blocks_state inflate_blocks_statef; | ||
| 16 | |||
| 17 | extern inflate_blocks_statef * zlib_inflate_blocks_new ( | ||
| 18 | z_streamp z, | ||
| 19 | check_func c, /* check function */ | ||
| 20 | uInt w); /* window size */ | ||
| 21 | |||
| 22 | extern int zlib_inflate_blocks ( | ||
| 23 | inflate_blocks_statef *, | ||
| 24 | z_streamp , | ||
| 25 | int); /* initial return code */ | ||
| 26 | |||
| 27 | extern void zlib_inflate_blocks_reset ( | ||
| 28 | inflate_blocks_statef *, | ||
| 29 | z_streamp , | ||
| 30 | uLong *); /* check value on output */ | ||
| 31 | |||
| 32 | extern int zlib_inflate_blocks_free ( | ||
| 33 | inflate_blocks_statef *, | ||
| 34 | z_streamp); | ||
| 35 | |||
| 36 | #if 0 | ||
| 37 | extern void zlib_inflate_set_dictionary ( | ||
| 38 | inflate_blocks_statef *s, | ||
| 39 | const Byte *d, /* dictionary */ | ||
| 40 | uInt n); /* dictionary length */ | ||
| 41 | #endif /* 0 */ | ||
| 42 | |||
| 43 | #if 0 | ||
| 44 | extern int zlib_inflate_blocks_sync_point ( | ||
| 45 | inflate_blocks_statef *s); | ||
| 46 | #endif /* 0 */ | ||
| 47 | |||
| 48 | #endif /* _INFBLOCK_H */ | ||
diff --git a/lib/zlib_inflate/infcodes.c b/lib/zlib_inflate/infcodes.c deleted file mode 100644 index 07cd7591cbb7..000000000000 --- a/lib/zlib_inflate/infcodes.c +++ /dev/null | |||
| @@ -1,202 +0,0 @@ | |||
| 1 | /* infcodes.c -- process literals and length/distance pairs | ||
| 2 | * Copyright (C) 1995-1998 Mark Adler | ||
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/zutil.h> | ||
| 7 | #include "inftrees.h" | ||
| 8 | #include "infblock.h" | ||
| 9 | #include "infcodes.h" | ||
| 10 | #include "infutil.h" | ||
| 11 | #include "inffast.h" | ||
| 12 | |||
| 13 | /* simplify the use of the inflate_huft type with some defines */ | ||
| 14 | #define exop word.what.Exop | ||
| 15 | #define bits word.what.Bits | ||
| 16 | |||
| 17 | inflate_codes_statef *zlib_inflate_codes_new( | ||
| 18 | uInt bl, | ||
| 19 | uInt bd, | ||
| 20 | inflate_huft *tl, | ||
| 21 | inflate_huft *td, /* need separate declaration for Borland C++ */ | ||
| 22 | z_streamp z | ||
| 23 | ) | ||
| 24 | { | ||
| 25 | inflate_codes_statef *c; | ||
| 26 | |||
| 27 | c = &WS(z)->working_state; | ||
| 28 | { | ||
| 29 | c->mode = START; | ||
| 30 | c->lbits = (Byte)bl; | ||
| 31 | c->dbits = (Byte)bd; | ||
| 32 | c->ltree = tl; | ||
| 33 | c->dtree = td; | ||
| 34 | } | ||
| 35 | return c; | ||
| 36 | } | ||
| 37 | |||
| 38 | |||
| 39 | int zlib_inflate_codes( | ||
| 40 | inflate_blocks_statef *s, | ||
| 41 | z_streamp z, | ||
| 42 | int r | ||
| 43 | ) | ||
| 44 | { | ||
| 45 | uInt j; /* temporary storage */ | ||
| 46 | inflate_huft *t; /* temporary pointer */ | ||
| 47 | uInt e; /* extra bits or operation */ | ||
| 48 | uLong b; /* bit buffer */ | ||
| 49 | uInt k; /* bits in bit buffer */ | ||
| 50 | Byte *p; /* input data pointer */ | ||
| 51 | uInt n; /* bytes available there */ | ||
| 52 | Byte *q; /* output window write pointer */ | ||
| 53 | uInt m; /* bytes to end of window or read pointer */ | ||
| 54 | Byte *f; /* pointer to copy strings from */ | ||
| 55 | inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ | ||
| 56 | |||
| 57 | /* copy input/output information to locals (UPDATE macro restores) */ | ||
| 58 | LOAD | ||
| 59 | |||
| 60 | /* process input and output based on current state */ | ||
| 61 | while (1) switch (c->mode) | ||
| 62 | { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ | ||
| 63 | case START: /* x: set up for LEN */ | ||
| 64 | #ifndef SLOW | ||
| 65 | if (m >= 258 && n >= 10) | ||
| 66 | { | ||
| 67 | UPDATE | ||
| 68 | r = zlib_inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); | ||
| 69 | LOAD | ||
| 70 | if (r != Z_OK) | ||
| 71 | { | ||
| 72 | c->mode = r == Z_STREAM_END ? WASH : BADCODE; | ||
| 73 | break; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | #endif /* !SLOW */ | ||
| 77 | c->sub.code.need = c->lbits; | ||
| 78 | c->sub.code.tree = c->ltree; | ||
| 79 | c->mode = LEN; | ||
| 80 | case LEN: /* i: get length/literal/eob next */ | ||
| 81 | j = c->sub.code.need; | ||
| 82 | NEEDBITS(j) | ||
| 83 | t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]); | ||
| 84 | DUMPBITS(t->bits) | ||
| 85 | e = (uInt)(t->exop); | ||
| 86 | if (e == 0) /* literal */ | ||
| 87 | { | ||
| 88 | c->sub.lit = t->base; | ||
| 89 | c->mode = LIT; | ||
| 90 | break; | ||
| 91 | } | ||
| 92 | if (e & 16) /* length */ | ||
| 93 | { | ||
| 94 | c->sub.copy.get = e & 15; | ||
| 95 | c->len = t->base; | ||
| 96 | c->mode = LENEXT; | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | if ((e & 64) == 0) /* next table */ | ||
| 100 | { | ||
| 101 | c->sub.code.need = e; | ||
| 102 | c->sub.code.tree = t + t->base; | ||
| 103 | break; | ||
| 104 | } | ||
| 105 | if (e & 32) /* end of block */ | ||
| 106 | { | ||
| 107 | c->mode = WASH; | ||
| 108 | break; | ||
| 109 | } | ||
| 110 | c->mode = BADCODE; /* invalid code */ | ||
| 111 | z->msg = (char*)"invalid literal/length code"; | ||
| 112 | r = Z_DATA_ERROR; | ||
| 113 | LEAVE | ||
| 114 | case LENEXT: /* i: getting length extra (have base) */ | ||
| 115 | j = c->sub.copy.get; | ||
| 116 | NEEDBITS(j) | ||
| 117 | c->len += (uInt)b & zlib_inflate_mask[j]; | ||
| 118 | DUMPBITS(j) | ||
| 119 | c->sub.code.need = c->dbits; | ||
| 120 | c->sub.code.tree = c->dtree; | ||
| 121 | c->mode = DIST; | ||
| 122 | case DIST: /* i: get distance next */ | ||
| 123 | j = c->sub.code.need; | ||
| 124 | NEEDBITS(j) | ||
| 125 | t = c->sub.code.tree + ((uInt)b & zlib_inflate_mask[j]); | ||
| 126 | DUMPBITS(t->bits) | ||
| 127 | e = (uInt)(t->exop); | ||
| 128 | if (e & 16) /* distance */ | ||
| 129 | { | ||
| 130 | c->sub.copy.get = e & 15; | ||
| 131 | c->sub.copy.dist = t->base; | ||
| 132 | c->mode = DISTEXT; | ||
| 133 | break; | ||
| 134 | } | ||
| 135 | if ((e & 64) == 0) /* next table */ | ||
| 136 | { | ||
| 137 | c->sub.code.need = e; | ||
| 138 | c->sub.code.tree = t + t->base; | ||
| 139 | break; | ||
| 140 | } | ||
| 141 | c->mode = BADCODE; /* invalid code */ | ||
| 142 | z->msg = (char*)"invalid distance code"; | ||
| 143 | r = Z_DATA_ERROR; | ||
| 144 | LEAVE | ||
| 145 | case DISTEXT: /* i: getting distance extra */ | ||
| 146 | j = c->sub.copy.get; | ||
| 147 | NEEDBITS(j) | ||
| 148 | c->sub.copy.dist += (uInt)b & zlib_inflate_mask[j]; | ||
| 149 | DUMPBITS(j) | ||
| 150 | c->mode = COPY; | ||
| 151 | case COPY: /* o: copying bytes in window, waiting for space */ | ||
| 152 | f = q - c->sub.copy.dist; | ||
| 153 | while (f < s->window) /* modulo window size-"while" instead */ | ||
| 154 | f += s->end - s->window; /* of "if" handles invalid distances */ | ||
| 155 | while (c->len) | ||
| 156 | { | ||
| 157 | NEEDOUT | ||
| 158 | OUTBYTE(*f++) | ||
| 159 | if (f == s->end) | ||
| 160 | f = s->window; | ||
| 161 | c->len--; | ||
| 162 | } | ||
| 163 | c->mode = START; | ||
| 164 | break; | ||
| 165 | case LIT: /* o: got literal, waiting for output space */ | ||
| 166 | NEEDOUT | ||
| 167 | OUTBYTE(c->sub.lit) | ||
| 168 | c->mode = START; | ||
| 169 | break; | ||
| 170 | case WASH: /* o: got eob, possibly more output */ | ||
| 171 | if (k > 7) /* return unused byte, if any */ | ||
| 172 | { | ||
| 173 | k -= 8; | ||
| 174 | n++; | ||
| 175 | p--; /* can always return one */ | ||
| 176 | } | ||
| 177 | FLUSH | ||
| 178 | if (s->read != s->write) | ||
| 179 | LEAVE | ||
| 180 | c->mode = END; | ||
| 181 | case END: | ||
| 182 | r = Z_STREAM_END; | ||
| 183 | LEAVE | ||
| 184 | case BADCODE: /* x: got error */ | ||
| 185 | r = Z_DATA_ERROR; | ||
| 186 | LEAVE | ||
| 187 | default: | ||
| 188 | r = Z_STREAM_ERROR; | ||
| 189 | LEAVE | ||
| 190 | } | ||
| 191 | #ifdef NEED_DUMMY_RETURN | ||
| 192 | return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ | ||
| 193 | #endif | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | void zlib_inflate_codes_free( | ||
| 198 | inflate_codes_statef *c, | ||
| 199 | z_streamp z | ||
| 200 | ) | ||
| 201 | { | ||
| 202 | } | ||
diff --git a/lib/zlib_inflate/infcodes.h b/lib/zlib_inflate/infcodes.h deleted file mode 100644 index 5cff417523b0..000000000000 --- a/lib/zlib_inflate/infcodes.h +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | /* infcodes.h -- header to use infcodes.c | ||
| 2 | * Copyright (C) 1995-1998 Mark Adler | ||
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | ||
| 4 | */ | ||
| 5 | |||
| 6 | /* WARNING: this file should *not* be used by applications. It is | ||
| 7 | part of the implementation of the compression library and is | ||
| 8 | subject to change. Applications should only use zlib.h. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _INFCODES_H | ||
| 12 | #define _INFCODES_H | ||
| 13 | |||
| 14 | #include "infblock.h" | ||
| 15 | |||
| 16 | struct inflate_codes_state; | ||
| 17 | typedef struct inflate_codes_state inflate_codes_statef; | ||
| 18 | |||
| 19 | extern inflate_codes_statef *zlib_inflate_codes_new ( | ||
| 20 | uInt, uInt, | ||
| 21 | inflate_huft *, inflate_huft *, | ||
| 22 | z_streamp ); | ||
| 23 | |||
| 24 | extern int zlib_inflate_codes ( | ||
| 25 | inflate_blocks_statef *, | ||
| 26 | z_streamp , | ||
| 27 | int); | ||
| 28 | |||
| 29 | extern void zlib_inflate_codes_free ( | ||
| 30 | inflate_codes_statef *, | ||
| 31 | z_streamp ); | ||
| 32 | |||
| 33 | #endif /* _INFCODES_H */ | ||
diff --git a/lib/zlib_inflate/inffast.c b/lib/zlib_inflate/inffast.c index 0bd7623fc85a..02a16eacb72d 100644 --- a/lib/zlib_inflate/inffast.c +++ b/lib/zlib_inflate/inffast.c | |||
| @@ -1,176 +1,312 @@ | |||
| 1 | /* inffast.c -- process literals and length/distance pairs fast | 1 | /* inffast.c -- fast decoding |
| 2 | * Copyright (C) 1995-1998 Mark Adler | 2 | * Copyright (C) 1995-2004 Mark Adler |
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | 3 | * For conditions of distribution and use, see copyright notice in zlib.h |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | #include <linux/zutil.h> | 6 | #include <linux/zutil.h> |
| 7 | #include "inftrees.h" | 7 | #include "inftrees.h" |
| 8 | #include "infblock.h" | 8 | #include "inflate.h" |
| 9 | #include "infcodes.h" | ||
| 10 | #include "infutil.h" | ||
| 11 | #include "inffast.h" | 9 | #include "inffast.h" |
| 12 | 10 | ||
| 13 | struct inflate_codes_state; | 11 | #ifndef ASMINF |
| 14 | 12 | ||
| 15 | /* simplify the use of the inflate_huft type with some defines */ | 13 | /* Allow machine dependent optimization for post-increment or pre-increment. |
| 16 | #define exop word.what.Exop | 14 | Based on testing to date, |
| 17 | #define bits word.what.Bits | 15 | Pre-increment preferred for: |
| 18 | 16 | - PowerPC G3 (Adler) | |
| 19 | /* macros for bit input with no checking and for returning unused bytes */ | 17 | - MIPS R5000 (Randers-Pehrson) |
| 20 | #define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}} | 18 | Post-increment preferred for: |
| 21 | #define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>3:c;n+=c;p-=c;k-=c<<3;} | 19 | - none |
| 22 | 20 | No measurable difference: | |
| 23 | /* Called with number of bytes left to write in window at least 258 | 21 | - Pentium III (Anderson) |
| 24 | (the maximum string length) and number of input bytes available | 22 | - M68060 (Nikl) |
| 25 | at least ten. The ten bytes are six bytes for the longest length/ | 23 | */ |
| 26 | distance pair plus four bytes for overloading the bit buffer. */ | 24 | #ifdef POSTINC |
| 27 | 25 | # define OFF 0 | |
| 28 | int zlib_inflate_fast( | 26 | # define PUP(a) *(a)++ |
| 29 | uInt bl, | 27 | #else |
| 30 | uInt bd, | 28 | # define OFF 1 |
| 31 | inflate_huft *tl, | 29 | # define PUP(a) *++(a) |
| 32 | inflate_huft *td, /* need separate declaration for Borland C++ */ | 30 | #endif |
| 33 | inflate_blocks_statef *s, | 31 | |
| 34 | z_streamp z | 32 | /* |
| 35 | ) | 33 | Decode literal, length, and distance codes and write out the resulting |
| 34 | literal and match bytes until either not enough input or output is | ||
| 35 | available, an end-of-block is encountered, or a data error is encountered. | ||
| 36 | When large enough input and output buffers are supplied to inflate(), for | ||
| 37 | example, a 16K input buffer and a 64K output buffer, more than 95% of the | ||
| 38 | inflate execution time is spent in this routine. | ||
| 39 | |||
| 40 | Entry assumptions: | ||
| 41 | |||
| 42 | state->mode == LEN | ||
| 43 | strm->avail_in >= 6 | ||
| 44 | strm->avail_out >= 258 | ||
| 45 | start >= strm->avail_out | ||
| 46 | state->bits < 8 | ||
| 47 | |||
| 48 | On return, state->mode is one of: | ||
| 49 | |||
| 50 | LEN -- ran out of enough output space or enough available input | ||
| 51 | TYPE -- reached end of block code, inflate() to interpret next block | ||
| 52 | BAD -- error in block data | ||
| 53 | |||
| 54 | Notes: | ||
| 55 | |||
| 56 | - The maximum input bits used by a length/distance pair is 15 bits for the | ||
| 57 | length code, 5 bits for the length extra, 15 bits for the distance code, | ||
| 58 | and 13 bits for the distance extra. This totals 48 bits, or six bytes. | ||
| 59 | Therefore if strm->avail_in >= 6, then there is enough input to avoid | ||
| 60 | checking for available input while decoding. | ||
| 61 | |||
| 62 | - The maximum bytes that a single length/distance pair can output is 258 | ||
| 63 | bytes, which is the maximum length that can be coded. inflate_fast() | ||
| 64 | requires strm->avail_out >= 258 for each loop to avoid checking for | ||
| 65 | output space. | ||
| 66 | */ | ||
| 67 | void inflate_fast(strm, start) | ||
| 68 | z_streamp strm; | ||
| 69 | unsigned start; /* inflate()'s starting value for strm->avail_out */ | ||
| 36 | { | 70 | { |
| 37 | inflate_huft *t; /* temporary pointer */ | 71 | struct inflate_state *state; |
| 38 | uInt e; /* extra bits or operation */ | 72 | unsigned char *in; /* local strm->next_in */ |
| 39 | uLong b; /* bit buffer */ | 73 | unsigned char *last; /* while in < last, enough input available */ |
| 40 | uInt k; /* bits in bit buffer */ | 74 | unsigned char *out; /* local strm->next_out */ |
| 41 | Byte *p; /* input data pointer */ | 75 | unsigned char *beg; /* inflate()'s initial strm->next_out */ |
| 42 | uInt n; /* bytes available there */ | 76 | unsigned char *end; /* while out < end, enough space available */ |
| 43 | Byte *q; /* output window write pointer */ | 77 | #ifdef INFLATE_STRICT |
| 44 | uInt m; /* bytes to end of window or read pointer */ | 78 | unsigned dmax; /* maximum distance from zlib header */ |
| 45 | uInt ml; /* mask for literal/length tree */ | 79 | #endif |
| 46 | uInt md; /* mask for distance tree */ | 80 | unsigned wsize; /* window size or zero if not using window */ |
| 47 | uInt c; /* bytes to copy */ | 81 | unsigned whave; /* valid bytes in the window */ |
| 48 | uInt d; /* distance back to copy from */ | 82 | unsigned write; /* window write index */ |
| 49 | Byte *r; /* copy source pointer */ | 83 | unsigned char *window; /* allocated sliding window, if wsize != 0 */ |
| 50 | 84 | unsigned long hold; /* local strm->hold */ | |
| 51 | /* load input, output, bit values */ | 85 | unsigned bits; /* local strm->bits */ |
| 52 | LOAD | 86 | code const *lcode; /* local strm->lencode */ |
| 53 | 87 | code const *dcode; /* local strm->distcode */ | |
| 54 | /* initialize masks */ | 88 | unsigned lmask; /* mask for first level of length codes */ |
| 55 | ml = zlib_inflate_mask[bl]; | 89 | unsigned dmask; /* mask for first level of distance codes */ |
| 56 | md = zlib_inflate_mask[bd]; | 90 | code this; /* retrieved table entry */ |
| 57 | 91 | unsigned op; /* code bits, operation, extra bits, or */ | |
| 58 | /* do until not enough input or output space for fast loop */ | 92 | /* window position, window bytes to copy */ |
| 59 | do { /* assume called with m >= 258 && n >= 10 */ | 93 | unsigned len; /* match length, unused bytes */ |
| 60 | /* get literal/length code */ | 94 | unsigned dist; /* match distance */ |
| 61 | GRABBITS(20) /* max bits for literal/length code */ | 95 | unsigned char *from; /* where to copy match from */ |
| 62 | if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) | 96 | |
| 63 | { | 97 | /* copy state to local variables */ |
| 64 | DUMPBITS(t->bits) | 98 | state = (struct inflate_state *)strm->state; |
| 65 | *q++ = (Byte)t->base; | 99 | in = strm->next_in - OFF; |
| 66 | m--; | 100 | last = in + (strm->avail_in - 5); |
| 67 | continue; | 101 | out = strm->next_out - OFF; |
| 68 | } | 102 | beg = out - (start - strm->avail_out); |
| 103 | end = out + (strm->avail_out - 257); | ||
| 104 | #ifdef INFLATE_STRICT | ||
| 105 | dmax = state->dmax; | ||
| 106 | #endif | ||
| 107 | wsize = state->wsize; | ||
| 108 | whave = state->whave; | ||
| 109 | write = state->write; | ||
| 110 | window = state->window; | ||
| 111 | hold = state->hold; | ||
| 112 | bits = state->bits; | ||
| 113 | lcode = state->lencode; | ||
| 114 | dcode = state->distcode; | ||
| 115 | lmask = (1U << state->lenbits) - 1; | ||
| 116 | dmask = (1U << state->distbits) - 1; | ||
| 117 | |||
| 118 | /* decode literals and length/distances until end-of-block or not enough | ||
| 119 | input data or output space */ | ||
| 69 | do { | 120 | do { |
| 70 | DUMPBITS(t->bits) | 121 | if (bits < 15) { |
| 71 | if (e & 16) | 122 | hold += (unsigned long)(PUP(in)) << bits; |
| 72 | { | 123 | bits += 8; |
| 73 | /* get extra bits for length */ | 124 | hold += (unsigned long)(PUP(in)) << bits; |
| 74 | e &= 15; | 125 | bits += 8; |
| 75 | c = t->base + ((uInt)b & zlib_inflate_mask[e]); | 126 | } |
| 76 | DUMPBITS(e) | 127 | this = lcode[hold & lmask]; |
| 77 | 128 | dolen: | |
| 78 | /* decode distance base of block to copy */ | 129 | op = (unsigned)(this.bits); |
| 79 | GRABBITS(15); /* max bits for distance code */ | 130 | hold >>= op; |
| 80 | e = (t = td + ((uInt)b & md))->exop; | 131 | bits -= op; |
| 81 | do { | 132 | op = (unsigned)(this.op); |
| 82 | DUMPBITS(t->bits) | 133 | if (op == 0) { /* literal */ |
| 83 | if (e & 16) | 134 | PUP(out) = (unsigned char)(this.val); |
| 84 | { | 135 | } |
| 85 | /* get extra bits to add to distance base */ | 136 | else if (op & 16) { /* length base */ |
| 86 | e &= 15; | 137 | len = (unsigned)(this.val); |
| 87 | GRABBITS(e) /* get extra bits (up to 13) */ | 138 | op &= 15; /* number of extra bits */ |
| 88 | d = t->base + ((uInt)b & zlib_inflate_mask[e]); | 139 | if (op) { |
| 89 | DUMPBITS(e) | 140 | if (bits < op) { |
| 90 | 141 | hold += (unsigned long)(PUP(in)) << bits; | |
| 91 | /* do the copy */ | 142 | bits += 8; |
| 92 | m -= c; | 143 | } |
| 93 | r = q - d; | 144 | len += (unsigned)hold & ((1U << op) - 1); |
| 94 | if (r < s->window) /* wrap if needed */ | 145 | hold >>= op; |
| 95 | { | 146 | bits -= op; |
| 96 | do { | 147 | } |
| 97 | r += s->end - s->window; /* force pointer in window */ | 148 | if (bits < 15) { |
| 98 | } while (r < s->window); /* covers invalid distances */ | 149 | hold += (unsigned long)(PUP(in)) << bits; |
| 99 | e = s->end - r; | 150 | bits += 8; |
| 100 | if (c > e) | 151 | hold += (unsigned long)(PUP(in)) << bits; |
| 101 | { | 152 | bits += 8; |
| 102 | c -= e; /* wrapped copy */ | 153 | } |
| 103 | do { | 154 | this = dcode[hold & dmask]; |
| 104 | *q++ = *r++; | 155 | dodist: |
| 105 | } while (--e); | 156 | op = (unsigned)(this.bits); |
| 106 | r = s->window; | 157 | hold >>= op; |
| 107 | do { | 158 | bits -= op; |
| 108 | *q++ = *r++; | 159 | op = (unsigned)(this.op); |
| 109 | } while (--c); | 160 | if (op & 16) { /* distance base */ |
| 110 | } | 161 | dist = (unsigned)(this.val); |
| 111 | else /* normal copy */ | 162 | op &= 15; /* number of extra bits */ |
| 112 | { | 163 | if (bits < op) { |
| 113 | *q++ = *r++; c--; | 164 | hold += (unsigned long)(PUP(in)) << bits; |
| 114 | *q++ = *r++; c--; | 165 | bits += 8; |
| 115 | do { | 166 | if (bits < op) { |
| 116 | *q++ = *r++; | 167 | hold += (unsigned long)(PUP(in)) << bits; |
| 117 | } while (--c); | 168 | bits += 8; |
| 118 | } | 169 | } |
| 170 | } | ||
| 171 | dist += (unsigned)hold & ((1U << op) - 1); | ||
| 172 | #ifdef INFLATE_STRICT | ||
| 173 | if (dist > dmax) { | ||
| 174 | strm->msg = (char *)"invalid distance too far back"; | ||
| 175 | state->mode = BAD; | ||
| 176 | break; | ||
| 177 | } | ||
| 178 | #endif | ||
| 179 | hold >>= op; | ||
| 180 | bits -= op; | ||
| 181 | op = (unsigned)(out - beg); /* max distance in output */ | ||
| 182 | if (dist > op) { /* see if copy from window */ | ||
| 183 | op = dist - op; /* distance back in window */ | ||
| 184 | if (op > whave) { | ||
| 185 | strm->msg = (char *)"invalid distance too far back"; | ||
| 186 | state->mode = BAD; | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | from = window - OFF; | ||
| 190 | if (write == 0) { /* very common case */ | ||
| 191 | from += wsize - op; | ||
| 192 | if (op < len) { /* some from window */ | ||
| 193 | len -= op; | ||
| 194 | do { | ||
| 195 | PUP(out) = PUP(from); | ||
| 196 | } while (--op); | ||
| 197 | from = out - dist; /* rest from output */ | ||
| 198 | } | ||
| 199 | } | ||
| 200 | else if (write < op) { /* wrap around window */ | ||
| 201 | from += wsize + write - op; | ||
| 202 | op -= write; | ||
| 203 | if (op < len) { /* some from end of window */ | ||
| 204 | len -= op; | ||
| 205 | do { | ||
| 206 | PUP(out) = PUP(from); | ||
| 207 | } while (--op); | ||
| 208 | from = window - OFF; | ||
| 209 | if (write < len) { /* some from start of window */ | ||
| 210 | op = write; | ||
| 211 | len -= op; | ||
| 212 | do { | ||
| 213 | PUP(out) = PUP(from); | ||
| 214 | } while (--op); | ||
| 215 | from = out - dist; /* rest from output */ | ||
| 216 | } | ||
| 217 | } | ||
| 218 | } | ||
| 219 | else { /* contiguous in window */ | ||
| 220 | from += write - op; | ||
| 221 | if (op < len) { /* some from window */ | ||
| 222 | len -= op; | ||
| 223 | do { | ||
| 224 | PUP(out) = PUP(from); | ||
| 225 | } while (--op); | ||
| 226 | from = out - dist; /* rest from output */ | ||
| 227 | } | ||
| 228 | } | ||
| 229 | while (len > 2) { | ||
| 230 | PUP(out) = PUP(from); | ||
| 231 | PUP(out) = PUP(from); | ||
| 232 | PUP(out) = PUP(from); | ||
| 233 | len -= 3; | ||
| 234 | } | ||
| 235 | if (len) { | ||
| 236 | PUP(out) = PUP(from); | ||
| 237 | if (len > 1) | ||
| 238 | PUP(out) = PUP(from); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | else { | ||
| 242 | from = out - dist; /* copy direct from output */ | ||
| 243 | do { /* minimum length is three */ | ||
| 244 | PUP(out) = PUP(from); | ||
| 245 | PUP(out) = PUP(from); | ||
| 246 | PUP(out) = PUP(from); | ||
| 247 | len -= 3; | ||
| 248 | } while (len > 2); | ||
| 249 | if (len) { | ||
| 250 | PUP(out) = PUP(from); | ||
| 251 | if (len > 1) | ||
| 252 | PUP(out) = PUP(from); | ||
| 253 | } | ||
| 254 | } | ||
| 255 | } | ||
| 256 | else if ((op & 64) == 0) { /* 2nd level distance code */ | ||
| 257 | this = dcode[this.val + (hold & ((1U << op) - 1))]; | ||
| 258 | goto dodist; | ||
| 119 | } | 259 | } |
| 120 | else /* normal copy */ | 260 | else { |
| 121 | { | 261 | strm->msg = (char *)"invalid distance code"; |
| 122 | *q++ = *r++; c--; | 262 | state->mode = BAD; |
| 123 | *q++ = *r++; c--; | 263 | break; |
| 124 | do { | ||
| 125 | *q++ = *r++; | ||
| 126 | } while (--c); | ||
| 127 | } | 264 | } |
| 265 | } | ||
| 266 | else if ((op & 64) == 0) { /* 2nd level length code */ | ||
| 267 | this = lcode[this.val + (hold & ((1U << op) - 1))]; | ||
| 268 | goto dolen; | ||
| 269 | } | ||
| 270 | else if (op & 32) { /* end-of-block */ | ||
| 271 | state->mode = TYPE; | ||
| 128 | break; | 272 | break; |
| 129 | } | ||
| 130 | else if ((e & 64) == 0) | ||
| 131 | { | ||
| 132 | t += t->base; | ||
| 133 | e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop; | ||
| 134 | } | ||
| 135 | else | ||
| 136 | { | ||
| 137 | z->msg = (char*)"invalid distance code"; | ||
| 138 | UNGRAB | ||
| 139 | UPDATE | ||
| 140 | return Z_DATA_ERROR; | ||
| 141 | } | ||
| 142 | } while (1); | ||
| 143 | break; | ||
| 144 | } | ||
| 145 | if ((e & 64) == 0) | ||
| 146 | { | ||
| 147 | t += t->base; | ||
| 148 | if ((e = (t += ((uInt)b & zlib_inflate_mask[e]))->exop) == 0) | ||
| 149 | { | ||
| 150 | DUMPBITS(t->bits) | ||
| 151 | *q++ = (Byte)t->base; | ||
| 152 | m--; | ||
| 153 | break; | ||
| 154 | } | 273 | } |
| 155 | } | 274 | else { |
| 156 | else if (e & 32) | 275 | strm->msg = (char *)"invalid literal/length code"; |
| 157 | { | 276 | state->mode = BAD; |
| 158 | UNGRAB | 277 | break; |
| 159 | UPDATE | 278 | } |
| 160 | return Z_STREAM_END; | 279 | } while (in < last && out < end); |
| 161 | } | 280 | |
| 162 | else | 281 | /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ |
| 163 | { | 282 | len = bits >> 3; |
| 164 | z->msg = (char*)"invalid literal/length code"; | 283 | in -= len; |
| 165 | UNGRAB | 284 | bits -= len << 3; |
| 166 | UPDATE | 285 | hold &= (1U << bits) - 1; |
| 167 | return Z_DATA_ERROR; | 286 | |
| 168 | } | 287 | /* update state and return */ |
| 169 | } while (1); | 288 | strm->next_in = in + OFF; |
| 170 | } while (m >= 258 && n >= 10); | 289 | strm->next_out = out + OFF; |
| 171 | 290 | strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); | |
| 172 | /* not enough input or output--restore pointers and return */ | 291 | strm->avail_out = (unsigned)(out < end ? |
| 173 | UNGRAB | 292 | 257 + (end - out) : 257 - (out - end)); |
| 174 | UPDATE | 293 | state->hold = hold; |
| 175 | return Z_OK; | 294 | state->bits = bits; |
| 295 | return; | ||
| 176 | } | 296 | } |
| 297 | |||
| 298 | /* | ||
| 299 | inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): | ||
| 300 | - Using bit fields for code structure | ||
| 301 | - Different op definition to avoid & for extra bits (do & for table bits) | ||
| 302 | - Three separate decoding do-loops for direct, window, and write == 0 | ||
| 303 | - Special case for distance > 1 copies to do overlapped load and store copy | ||
| 304 | - Explicit branch predictions (based on measured branch probabilities) | ||
| 305 | - Deferring match copy and interspersed it with decoding subsequent codes | ||
| 306 | - Swapping literal/length else | ||
| 307 | - Swapping window/direct else | ||
| 308 | - Larger unrolled copy loops (three is about right) | ||
| 309 | - Moving len -= 3 statement into middle of loop | ||
| 310 | */ | ||
| 311 | |||
| 312 | #endif /* !ASMINF */ | ||
diff --git a/lib/zlib_inflate/inffast.h b/lib/zlib_inflate/inffast.h index fc720f0fa7f5..40315d9fddc4 100644 --- a/lib/zlib_inflate/inffast.h +++ b/lib/zlib_inflate/inffast.h | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* inffast.h -- header to use inffast.c | 1 | /* inffast.h -- header to use inffast.c |
| 2 | * Copyright (C) 1995-1998 Mark Adler | 2 | * Copyright (C) 1995-2003 Mark Adler |
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | 3 | * For conditions of distribution and use, see copyright notice in zlib.h |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | /* WARNING: this file should *not* be used by applications. It is | 6 | /* WARNING: this file should *not* be used by applications. It is |
| @@ -8,10 +8,4 @@ | |||
| 8 | subject to change. Applications should only use zlib.h. | 8 | subject to change. Applications should only use zlib.h. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | extern int zlib_inflate_fast ( | 11 | void inflate_fast (z_streamp strm, unsigned start); |
| 12 | uInt, | ||
| 13 | uInt, | ||
| 14 | inflate_huft *, | ||
| 15 | inflate_huft *, | ||
| 16 | inflate_blocks_statef *, | ||
| 17 | z_streamp ); | ||
diff --git a/lib/zlib_inflate/inffixed.h b/lib/zlib_inflate/inffixed.h new file mode 100644 index 000000000000..75ed4b5978de --- /dev/null +++ b/lib/zlib_inflate/inffixed.h | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | /* inffixed.h -- table for decoding fixed codes | ||
| 2 | * Generated automatically by makefixed(). | ||
| 3 | */ | ||
| 4 | |||
| 5 | /* WARNING: this file should *not* be used by applications. It | ||
| 6 | is part of the implementation of the compression library and | ||
| 7 | is subject to change. Applications should only use zlib.h. | ||
| 8 | */ | ||
| 9 | |||
| 10 | static const code lenfix[512] = { | ||
| 11 | {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, | ||
| 12 | {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, | ||
| 13 | {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, | ||
| 14 | {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, | ||
| 15 | {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, | ||
| 16 | {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, | ||
| 17 | {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, | ||
| 18 | {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, | ||
| 19 | {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, | ||
| 20 | {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, | ||
| 21 | {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, | ||
| 22 | {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, | ||
| 23 | {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, | ||
| 24 | {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, | ||
| 25 | {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, | ||
| 26 | {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, | ||
| 27 | {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, | ||
| 28 | {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, | ||
| 29 | {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, | ||
| 30 | {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, | ||
| 31 | {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, | ||
| 32 | {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, | ||
| 33 | {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, | ||
| 34 | {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, | ||
| 35 | {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, | ||
| 36 | {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, | ||
| 37 | {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, | ||
| 38 | {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, | ||
| 39 | {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, | ||
| 40 | {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, | ||
| 41 | {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, | ||
| 42 | {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, | ||
| 43 | {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, | ||
| 44 | {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, | ||
| 45 | {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, | ||
| 46 | {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, | ||
| 47 | {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, | ||
| 48 | {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, | ||
| 49 | {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, | ||
| 50 | {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, | ||
| 51 | {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, | ||
| 52 | {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, | ||
| 53 | {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, | ||
| 54 | {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, | ||
| 55 | {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, | ||
| 56 | {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, | ||
| 57 | {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, | ||
| 58 | {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, | ||
| 59 | {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, | ||
| 60 | {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, | ||
| 61 | {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, | ||
| 62 | {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, | ||
| 63 | {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, | ||
| 64 | {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, | ||
| 65 | {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, | ||
| 66 | {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, | ||
| 67 | {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, | ||
| 68 | {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, | ||
| 69 | {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, | ||
| 70 | {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, | ||
| 71 | {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, | ||
| 72 | {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, | ||
| 73 | {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, | ||
| 74 | {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, | ||
| 75 | {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, | ||
| 76 | {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, | ||
| 77 | {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, | ||
| 78 | {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, | ||
| 79 | {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, | ||
| 80 | {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, | ||
| 81 | {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, | ||
| 82 | {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, | ||
| 83 | {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, | ||
| 84 | {0,9,255} | ||
| 85 | }; | ||
| 86 | |||
| 87 | static const code distfix[32] = { | ||
| 88 | {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, | ||
| 89 | {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, | ||
| 90 | {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, | ||
| 91 | {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, | ||
| 92 | {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, | ||
| 93 | {22,5,193},{64,5,0} | ||
| 94 | }; | ||
diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c index 31b9e9054bf7..7f922dccf1a5 100644 --- a/lib/zlib_inflate/inflate.c +++ b/lib/zlib_inflate/inflate.c | |||
| @@ -1,89 +1,148 @@ | |||
| 1 | /* inflate.c -- zlib interface to inflate modules | 1 | /* inflate.c -- zlib decompression |
| 2 | * Copyright (C) 1995-1998 Mark Adler | 2 | * Copyright (C) 1995-2005 Mark Adler |
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | 3 | * For conditions of distribution and use, see copyright notice in zlib.h |
| 4 | * | ||
| 5 | * Based on zlib 1.2.3 but modified for the Linux Kernel by | ||
| 6 | * Richard Purdie <richard@openedhand.com> | ||
| 7 | * | ||
| 8 | * Changes mainly for static instead of dynamic memory allocation | ||
| 9 | * | ||
| 4 | */ | 10 | */ |
| 5 | 11 | ||
| 6 | #include <linux/zutil.h> | 12 | #include <linux/zutil.h> |
| 7 | #include "infblock.h" | 13 | #include "inftrees.h" |
| 14 | #include "inflate.h" | ||
| 15 | #include "inffast.h" | ||
| 8 | #include "infutil.h" | 16 | #include "infutil.h" |
| 9 | 17 | ||
| 10 | int zlib_inflate_workspacesize(void) | 18 | int zlib_inflate_workspacesize(void) |
| 11 | { | 19 | { |
| 12 | return sizeof(struct inflate_workspace); | 20 | return sizeof(struct inflate_workspace); |
| 13 | } | 21 | } |
| 14 | 22 | ||
| 23 | int zlib_inflateReset(z_streamp strm) | ||
| 24 | { | ||
| 25 | struct inflate_state *state; | ||
| 26 | |||
| 27 | if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; | ||
| 28 | state = (struct inflate_state *)strm->state; | ||
| 29 | strm->total_in = strm->total_out = state->total = 0; | ||
| 30 | strm->msg = NULL; | ||
| 31 | strm->adler = 1; /* to support ill-conceived Java test suite */ | ||
| 32 | state->mode = HEAD; | ||
| 33 | state->last = 0; | ||
| 34 | state->havedict = 0; | ||
| 35 | state->dmax = 32768U; | ||
| 36 | state->hold = 0; | ||
| 37 | state->bits = 0; | ||
| 38 | state->lencode = state->distcode = state->next = state->codes; | ||
| 15 | 39 | ||
| 16 | int zlib_inflateReset( | 40 | /* Initialise Window */ |
| 17 | z_streamp z | 41 | state->wsize = 1U << state->wbits; |
| 18 | ) | 42 | state->write = 0; |
| 43 | state->whave = 0; | ||
| 44 | |||
| 45 | return Z_OK; | ||
| 46 | } | ||
| 47 | |||
| 48 | #if 0 | ||
| 49 | int zlib_inflatePrime(z_streamp strm, int bits, int value) | ||
| 19 | { | 50 | { |
| 20 | if (z == NULL || z->state == NULL || z->workspace == NULL) | 51 | struct inflate_state *state; |
| 21 | return Z_STREAM_ERROR; | 52 | |
| 22 | z->total_in = z->total_out = 0; | 53 | if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; |
| 23 | z->msg = NULL; | 54 | state = (struct inflate_state *)strm->state; |
| 24 | z->state->mode = z->state->nowrap ? BLOCKS : METHOD; | 55 | if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; |
| 25 | zlib_inflate_blocks_reset(z->state->blocks, z, NULL); | 56 | value &= (1L << bits) - 1; |
| 26 | return Z_OK; | 57 | state->hold += value << state->bits; |
| 58 | state->bits += bits; | ||
| 59 | return Z_OK; | ||
| 27 | } | 60 | } |
| 61 | #endif | ||
| 62 | |||
| 63 | int zlib_inflateInit2(z_streamp strm, int windowBits) | ||
| 64 | { | ||
| 65 | struct inflate_state *state; | ||
| 66 | |||
| 67 | if (strm == NULL) return Z_STREAM_ERROR; | ||
| 68 | strm->msg = NULL; /* in case we return an error */ | ||
| 69 | |||
| 70 | state = &WS(strm)->inflate_state; | ||
| 71 | strm->state = (struct internal_state *)state; | ||
| 72 | |||
| 73 | if (windowBits < 0) { | ||
| 74 | state->wrap = 0; | ||
| 75 | windowBits = -windowBits; | ||
| 76 | } | ||
| 77 | else { | ||
| 78 | state->wrap = (windowBits >> 4) + 1; | ||
| 79 | } | ||
| 80 | if (windowBits < 8 || windowBits > 15) { | ||
| 81 | return Z_STREAM_ERROR; | ||
| 82 | } | ||
| 83 | state->wbits = (unsigned)windowBits; | ||
| 84 | state->window = &WS(strm)->working_window[0]; | ||
| 28 | 85 | ||
| 86 | return zlib_inflateReset(strm); | ||
| 87 | } | ||
| 29 | 88 | ||
| 30 | int zlib_inflateEnd( | 89 | /* |
| 31 | z_streamp z | 90 | Return state with length and distance decoding tables and index sizes set to |
| 32 | ) | 91 | fixed code decoding. This returns fixed tables from inffixed.h. |
| 92 | */ | ||
| 93 | static void zlib_fixedtables(struct inflate_state *state) | ||
| 33 | { | 94 | { |
| 34 | if (z == NULL || z->state == NULL || z->workspace == NULL) | 95 | # include "inffixed.h" |
| 35 | return Z_STREAM_ERROR; | 96 | state->lencode = lenfix; |
| 36 | if (z->state->blocks != NULL) | 97 | state->lenbits = 9; |
| 37 | zlib_inflate_blocks_free(z->state->blocks, z); | 98 | state->distcode = distfix; |
| 38 | z->state = NULL; | 99 | state->distbits = 5; |
| 39 | return Z_OK; | ||
| 40 | } | 100 | } |
| 41 | 101 | ||
| 42 | 102 | ||
| 43 | int zlib_inflateInit2_( | 103 | /* |
| 44 | z_streamp z, | 104 | Update the window with the last wsize (normally 32K) bytes written before |
| 45 | int w, | 105 | returning. This is only called when a window is already in use, or when |
| 46 | const char *version, | 106 | output has been written during this inflate call, but the end of the deflate |
| 47 | int stream_size | 107 | stream has not been reached yet. It is also called to window dictionary data |
| 48 | ) | 108 | when a dictionary is loaded. |
| 109 | |||
| 110 | Providing output buffers larger than 32K to inflate() should provide a speed | ||
| 111 | advantage, since only the last 32K of output is copied to the sliding window | ||
| 112 | upon return from inflate(), and since all distances after the first 32K of | ||
| 113 | output will fall in the output data, making match copies simpler and faster. | ||
| 114 | The advantage may be dependent on the size of the processor's data caches. | ||
| 115 | */ | ||
| 116 | static void zlib_updatewindow(z_streamp strm, unsigned out) | ||
| 49 | { | 117 | { |
| 50 | if (version == NULL || version[0] != ZLIB_VERSION[0] || | 118 | struct inflate_state *state; |
| 51 | stream_size != sizeof(z_stream) || z->workspace == NULL) | 119 | unsigned copy, dist; |
| 52 | return Z_VERSION_ERROR; | 120 | |
| 53 | 121 | state = (struct inflate_state *)strm->state; | |
| 54 | /* initialize state */ | 122 | |
| 55 | z->msg = NULL; | 123 | /* copy state->wsize or less output bytes into the circular window */ |
| 56 | z->state = &WS(z)->internal_state; | 124 | copy = out - strm->avail_out; |
| 57 | z->state->blocks = NULL; | 125 | if (copy >= state->wsize) { |
| 58 | 126 | memcpy(state->window, strm->next_out - state->wsize, state->wsize); | |
| 59 | /* handle undocumented nowrap option (no zlib header or check) */ | 127 | state->write = 0; |
| 60 | z->state->nowrap = 0; | 128 | state->whave = state->wsize; |
| 61 | if (w < 0) | 129 | } |
| 62 | { | 130 | else { |
| 63 | w = - w; | 131 | dist = state->wsize - state->write; |
| 64 | z->state->nowrap = 1; | 132 | if (dist > copy) dist = copy; |
| 65 | } | 133 | memcpy(state->window + state->write, strm->next_out - copy, dist); |
| 66 | 134 | copy -= dist; | |
| 67 | /* set window size */ | 135 | if (copy) { |
| 68 | if (w < 8 || w > 15) | 136 | memcpy(state->window, strm->next_out - copy, copy); |
| 69 | { | 137 | state->write = copy; |
| 70 | zlib_inflateEnd(z); | 138 | state->whave = state->wsize; |
| 71 | return Z_STREAM_ERROR; | 139 | } |
| 72 | } | 140 | else { |
| 73 | z->state->wbits = (uInt)w; | 141 | state->write += dist; |
| 74 | 142 | if (state->write == state->wsize) state->write = 0; | |
| 75 | /* create inflate_blocks state */ | 143 | if (state->whave < state->wsize) state->whave += dist; |
| 76 | if ((z->state->blocks = | 144 | } |
| 77 | zlib_inflate_blocks_new(z, z->state->nowrap ? NULL : zlib_adler32, (uInt)1 << w)) | 145 | } |
| 78 | == NULL) | ||
| 79 | { | ||
| 80 | zlib_inflateEnd(z); | ||
| 81 | return Z_MEM_ERROR; | ||
| 82 | } | ||
| 83 | |||
| 84 | /* reset state */ | ||
| 85 | zlib_inflateReset(z); | ||
| 86 | return Z_OK; | ||
| 87 | } | 146 | } |
| 88 | 147 | ||
| 89 | 148 | ||
| @@ -91,157 +150,764 @@ int zlib_inflateInit2_( | |||
| 91 | * At the end of a Deflate-compressed PPP packet, we expect to have seen | 150 | * At the end of a Deflate-compressed PPP packet, we expect to have seen |
| 92 | * a `stored' block type value but not the (zero) length bytes. | 151 | * a `stored' block type value but not the (zero) length bytes. |
| 93 | */ | 152 | */ |
| 94 | static int zlib_inflate_packet_flush(inflate_blocks_statef *s) | 153 | /* |
| 154 | Returns true if inflate is currently at the end of a block generated by | ||
| 155 | Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP | ||
| 156 | implementation to provide an additional safety check. PPP uses | ||
| 157 | Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored | ||
| 158 | block. When decompressing, PPP checks that at the end of input packet, | ||
| 159 | inflate is waiting for these length bytes. | ||
| 160 | */ | ||
| 161 | static int zlib_inflateSyncPacket(z_streamp strm) | ||
| 95 | { | 162 | { |
| 96 | if (s->mode != LENS) | 163 | struct inflate_state *state; |
| 97 | return Z_DATA_ERROR; | 164 | |
| 98 | s->mode = TYPE; | 165 | if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; |
| 166 | state = (struct inflate_state *)strm->state; | ||
| 167 | |||
| 168 | if (state->mode == STORED && state->bits == 0) { | ||
| 169 | state->mode = TYPE; | ||
| 170 | return Z_OK; | ||
| 171 | } | ||
| 172 | return Z_DATA_ERROR; | ||
| 173 | } | ||
| 174 | |||
| 175 | /* Macros for inflate(): */ | ||
| 176 | |||
| 177 | /* check function to use adler32() for zlib or crc32() for gzip */ | ||
| 178 | #define UPDATE(check, buf, len) zlib_adler32(check, buf, len) | ||
| 179 | |||
| 180 | /* Load registers with state in inflate() for speed */ | ||
| 181 | #define LOAD() \ | ||
| 182 | do { \ | ||
| 183 | put = strm->next_out; \ | ||
| 184 | left = strm->avail_out; \ | ||
| 185 | next = strm->next_in; \ | ||
| 186 | have = strm->avail_in; \ | ||
| 187 | hold = state->hold; \ | ||
| 188 | bits = state->bits; \ | ||
| 189 | } while (0) | ||
| 190 | |||
| 191 | /* Restore state from registers in inflate() */ | ||
| 192 | #define RESTORE() \ | ||
| 193 | do { \ | ||
| 194 | strm->next_out = put; \ | ||
| 195 | strm->avail_out = left; \ | ||
| 196 | strm->next_in = next; \ | ||
| 197 | strm->avail_in = have; \ | ||
| 198 | state->hold = hold; \ | ||
| 199 | state->bits = bits; \ | ||
| 200 | } while (0) | ||
| 201 | |||
| 202 | /* Clear the input bit accumulator */ | ||
| 203 | #define INITBITS() \ | ||
| 204 | do { \ | ||
| 205 | hold = 0; \ | ||
| 206 | bits = 0; \ | ||
| 207 | } while (0) | ||
| 208 | |||
| 209 | /* Get a byte of input into the bit accumulator, or return from inflate() | ||
| 210 | if there is no input available. */ | ||
| 211 | #define PULLBYTE() \ | ||
| 212 | do { \ | ||
| 213 | if (have == 0) goto inf_leave; \ | ||
| 214 | have--; \ | ||
| 215 | hold += (unsigned long)(*next++) << bits; \ | ||
| 216 | bits += 8; \ | ||
| 217 | } while (0) | ||
| 218 | |||
| 219 | /* Assure that there are at least n bits in the bit accumulator. If there is | ||
| 220 | not enough available input to do that, then return from inflate(). */ | ||
| 221 | #define NEEDBITS(n) \ | ||
| 222 | do { \ | ||
| 223 | while (bits < (unsigned)(n)) \ | ||
| 224 | PULLBYTE(); \ | ||
| 225 | } while (0) | ||
| 226 | |||
| 227 | /* Return the low n bits of the bit accumulator (n < 16) */ | ||
| 228 | #define BITS(n) \ | ||
| 229 | ((unsigned)hold & ((1U << (n)) - 1)) | ||
| 230 | |||
| 231 | /* Remove n bits from the bit accumulator */ | ||
| 232 | #define DROPBITS(n) \ | ||
| 233 | do { \ | ||
| 234 | hold >>= (n); \ | ||
| 235 | bits -= (unsigned)(n); \ | ||
| 236 | } while (0) | ||
| 237 | |||
| 238 | /* Remove zero to seven bits as needed to go to a byte boundary */ | ||
| 239 | #define BYTEBITS() \ | ||
| 240 | do { \ | ||
| 241 | hold >>= bits & 7; \ | ||
| 242 | bits -= bits & 7; \ | ||
| 243 | } while (0) | ||
| 244 | |||
| 245 | /* Reverse the bytes in a 32-bit value */ | ||
| 246 | #define REVERSE(q) \ | ||
| 247 | ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ | ||
| 248 | (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) | ||
| 249 | |||
| 250 | /* | ||
| 251 | inflate() uses a state machine to process as much input data and generate as | ||
| 252 | much output data as possible before returning. The state machine is | ||
| 253 | structured roughly as follows: | ||
| 254 | |||
| 255 | for (;;) switch (state) { | ||
| 256 | ... | ||
| 257 | case STATEn: | ||
| 258 | if (not enough input data or output space to make progress) | ||
| 259 | return; | ||
| 260 | ... make progress ... | ||
| 261 | state = STATEm; | ||
| 262 | break; | ||
| 263 | ... | ||
| 264 | } | ||
| 265 | |||
| 266 | so when inflate() is called again, the same case is attempted again, and | ||
| 267 | if the appropriate resources are provided, the machine proceeds to the | ||
| 268 | next state. The NEEDBITS() macro is usually the way the state evaluates | ||
| 269 | whether it can proceed or should return. NEEDBITS() does the return if | ||
| 270 | the requested bits are not available. The typical use of the BITS macros | ||
| 271 | is: | ||
| 272 | |||
| 273 | NEEDBITS(n); | ||
| 274 | ... do something with BITS(n) ... | ||
| 275 | DROPBITS(n); | ||
| 276 | |||
| 277 | where NEEDBITS(n) either returns from inflate() if there isn't enough | ||
| 278 | input left to load n bits into the accumulator, or it continues. BITS(n) | ||
| 279 | gives the low n bits in the accumulator. When done, DROPBITS(n) drops | ||
| 280 | the low n bits off the accumulator. INITBITS() clears the accumulator | ||
| 281 | and sets the number of available bits to zero. BYTEBITS() discards just | ||
| 282 | enough bits to put the accumulator on a byte boundary. After BYTEBITS() | ||
| 283 | and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. | ||
| 284 | |||
| 285 | NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return | ||
| 286 | if there is no input available. The decoding of variable length codes uses | ||
| 287 | PULLBYTE() directly in order to pull just enough bytes to decode the next | ||
| 288 | code, and no more. | ||
| 289 | |||
| 290 | Some states loop until they get enough input, making sure that enough | ||
| 291 | state information is maintained to continue the loop where it left off | ||
| 292 | if NEEDBITS() returns in the loop. For example, want, need, and keep | ||
| 293 | would all have to actually be part of the saved state in case NEEDBITS() | ||
| 294 | returns: | ||
| 295 | |||
| 296 | case STATEw: | ||
| 297 | while (want < need) { | ||
| 298 | NEEDBITS(n); | ||
| 299 | keep[want++] = BITS(n); | ||
| 300 | DROPBITS(n); | ||
| 301 | } | ||
| 302 | state = STATEx; | ||
| 303 | case STATEx: | ||
| 304 | |||
| 305 | As shown above, if the next state is also the next case, then the break | ||
| 306 | is omitted. | ||
| 307 | |||
| 308 | A state may also return if there is not enough output space available to | ||
| 309 | complete that state. Those states are copying stored data, writing a | ||
| 310 | literal byte, and copying a matching string. | ||
| 311 | |||
| 312 | When returning, a "goto inf_leave" is used to update the total counters, | ||
| 313 | update the check value, and determine whether any progress has been made | ||
| 314 | during that inflate() call in order to return the proper return code. | ||
| 315 | Progress is defined as a change in either strm->avail_in or strm->avail_out. | ||
| 316 | When there is a window, goto inf_leave will update the window with the last | ||
| 317 | output written. If a goto inf_leave occurs in the middle of decompression | ||
| 318 | and there is no window currently, goto inf_leave will create one and copy | ||
| 319 | output to the window for the next call of inflate(). | ||
| 320 | |||
| 321 | In this implementation, the flush parameter of inflate() only affects the | ||
| 322 | return code (per zlib.h). inflate() always writes as much as possible to | ||
| 323 | strm->next_out, given the space available and the provided input--the effect | ||
| 324 | documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers | ||
| 325 | the allocation of and copying into a sliding window until necessary, which | ||
| 326 | provides the effect documented in zlib.h for Z_FINISH when the entire input | ||
| 327 | stream available. So the only thing the flush parameter actually does is: | ||
| 328 | when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it | ||
| 329 | will return Z_BUF_ERROR if it has not reached the end of the stream. | ||
| 330 | */ | ||
| 331 | |||
| 332 | int zlib_inflate(z_streamp strm, int flush) | ||
| 333 | { | ||
| 334 | struct inflate_state *state; | ||
| 335 | unsigned char *next; /* next input */ | ||
| 336 | unsigned char *put; /* next output */ | ||
| 337 | unsigned have, left; /* available input and output */ | ||
| 338 | unsigned long hold; /* bit buffer */ | ||
| 339 | unsigned bits; /* bits in bit buffer */ | ||
| 340 | unsigned in, out; /* save starting available input and output */ | ||
| 341 | unsigned copy; /* number of stored or match bytes to copy */ | ||
| 342 | unsigned char *from; /* where to copy match bytes from */ | ||
| 343 | code this; /* current decoding table entry */ | ||
| 344 | code last; /* parent table entry */ | ||
| 345 | unsigned len; /* length to copy for repeats, bits to drop */ | ||
| 346 | int ret; /* return code */ | ||
| 347 | static const unsigned short order[19] = /* permutation of code lengths */ | ||
| 348 | {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; | ||
| 349 | |||
| 350 | if (strm == NULL || strm->state == NULL || strm->next_out == NULL || | ||
| 351 | (strm->next_in == NULL && strm->avail_in != 0)) | ||
| 352 | return Z_STREAM_ERROR; | ||
| 353 | |||
| 354 | state = (struct inflate_state *)strm->state; | ||
| 355 | |||
| 356 | if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ | ||
| 357 | LOAD(); | ||
| 358 | in = have; | ||
| 359 | out = left; | ||
| 360 | ret = Z_OK; | ||
| 361 | for (;;) | ||
| 362 | switch (state->mode) { | ||
| 363 | case HEAD: | ||
| 364 | if (state->wrap == 0) { | ||
| 365 | state->mode = TYPEDO; | ||
| 366 | break; | ||
| 367 | } | ||
| 368 | NEEDBITS(16); | ||
| 369 | if ( | ||
| 370 | ((BITS(8) << 8) + (hold >> 8)) % 31) { | ||
| 371 | strm->msg = (char *)"incorrect header check"; | ||
| 372 | state->mode = BAD; | ||
| 373 | break; | ||
| 374 | } | ||
| 375 | if (BITS(4) != Z_DEFLATED) { | ||
| 376 | strm->msg = (char *)"unknown compression method"; | ||
| 377 | state->mode = BAD; | ||
| 378 | break; | ||
| 379 | } | ||
| 380 | DROPBITS(4); | ||
| 381 | len = BITS(4) + 8; | ||
| 382 | if (len > state->wbits) { | ||
| 383 | strm->msg = (char *)"invalid window size"; | ||
| 384 | state->mode = BAD; | ||
| 385 | break; | ||
| 386 | } | ||
| 387 | state->dmax = 1U << len; | ||
| 388 | strm->adler = state->check = zlib_adler32(0L, NULL, 0); | ||
| 389 | state->mode = hold & 0x200 ? DICTID : TYPE; | ||
| 390 | INITBITS(); | ||
| 391 | break; | ||
| 392 | case DICTID: | ||
| 393 | NEEDBITS(32); | ||
| 394 | strm->adler = state->check = REVERSE(hold); | ||
| 395 | INITBITS(); | ||
| 396 | state->mode = DICT; | ||
| 397 | case DICT: | ||
| 398 | if (state->havedict == 0) { | ||
| 399 | RESTORE(); | ||
| 400 | return Z_NEED_DICT; | ||
| 401 | } | ||
| 402 | strm->adler = state->check = zlib_adler32(0L, NULL, 0); | ||
| 403 | state->mode = TYPE; | ||
| 404 | case TYPE: | ||
| 405 | if (flush == Z_BLOCK) goto inf_leave; | ||
| 406 | case TYPEDO: | ||
| 407 | if (state->last) { | ||
| 408 | BYTEBITS(); | ||
| 409 | state->mode = CHECK; | ||
| 410 | break; | ||
| 411 | } | ||
| 412 | NEEDBITS(3); | ||
| 413 | state->last = BITS(1); | ||
| 414 | DROPBITS(1); | ||
| 415 | switch (BITS(2)) { | ||
| 416 | case 0: /* stored block */ | ||
| 417 | state->mode = STORED; | ||
| 418 | break; | ||
| 419 | case 1: /* fixed block */ | ||
| 420 | zlib_fixedtables(state); | ||
| 421 | state->mode = LEN; /* decode codes */ | ||
| 422 | break; | ||
| 423 | case 2: /* dynamic block */ | ||
| 424 | state->mode = TABLE; | ||
| 425 | break; | ||
| 426 | case 3: | ||
| 427 | strm->msg = (char *)"invalid block type"; | ||
| 428 | state->mode = BAD; | ||
| 429 | } | ||
| 430 | DROPBITS(2); | ||
| 431 | break; | ||
| 432 | case STORED: | ||
| 433 | BYTEBITS(); /* go to byte boundary */ | ||
| 434 | NEEDBITS(32); | ||
| 435 | if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { | ||
| 436 | strm->msg = (char *)"invalid stored block lengths"; | ||
| 437 | state->mode = BAD; | ||
| 438 | break; | ||
| 439 | } | ||
| 440 | state->length = (unsigned)hold & 0xffff; | ||
| 441 | INITBITS(); | ||
| 442 | state->mode = COPY; | ||
| 443 | case COPY: | ||
| 444 | copy = state->length; | ||
| 445 | if (copy) { | ||
| 446 | if (copy > have) copy = have; | ||
| 447 | if (copy > left) copy = left; | ||
| 448 | if (copy == 0) goto inf_leave; | ||
| 449 | memcpy(put, next, copy); | ||
| 450 | have -= copy; | ||
| 451 | next += copy; | ||
| 452 | left -= copy; | ||
| 453 | put += copy; | ||
| 454 | state->length -= copy; | ||
| 455 | break; | ||
| 456 | } | ||
| 457 | state->mode = TYPE; | ||
| 458 | break; | ||
| 459 | case TABLE: | ||
| 460 | NEEDBITS(14); | ||
| 461 | state->nlen = BITS(5) + 257; | ||
| 462 | DROPBITS(5); | ||
| 463 | state->ndist = BITS(5) + 1; | ||
| 464 | DROPBITS(5); | ||
| 465 | state->ncode = BITS(4) + 4; | ||
| 466 | DROPBITS(4); | ||
| 467 | #ifndef PKZIP_BUG_WORKAROUND | ||
| 468 | if (state->nlen > 286 || state->ndist > 30) { | ||
| 469 | strm->msg = (char *)"too many length or distance symbols"; | ||
| 470 | state->mode = BAD; | ||
| 471 | break; | ||
| 472 | } | ||
| 473 | #endif | ||
| 474 | state->have = 0; | ||
| 475 | state->mode = LENLENS; | ||
| 476 | case LENLENS: | ||
| 477 | while (state->have < state->ncode) { | ||
| 478 | NEEDBITS(3); | ||
| 479 | state->lens[order[state->have++]] = (unsigned short)BITS(3); | ||
| 480 | DROPBITS(3); | ||
| 481 | } | ||
| 482 | while (state->have < 19) | ||
| 483 | state->lens[order[state->have++]] = 0; | ||
| 484 | state->next = state->codes; | ||
| 485 | state->lencode = (code const *)(state->next); | ||
| 486 | state->lenbits = 7; | ||
| 487 | ret = zlib_inflate_table(CODES, state->lens, 19, &(state->next), | ||
| 488 | &(state->lenbits), state->work); | ||
| 489 | if (ret) { | ||
| 490 | strm->msg = (char *)"invalid code lengths set"; | ||
| 491 | state->mode = BAD; | ||
| 492 | break; | ||
| 493 | } | ||
| 494 | state->have = 0; | ||
| 495 | state->mode = CODELENS; | ||
| 496 | case CODELENS: | ||
| 497 | while (state->have < state->nlen + state->ndist) { | ||
| 498 | for (;;) { | ||
| 499 | this = state->lencode[BITS(state->lenbits)]; | ||
| 500 | if ((unsigned)(this.bits) <= bits) break; | ||
| 501 | PULLBYTE(); | ||
| 502 | } | ||
| 503 | if (this.val < 16) { | ||
| 504 | NEEDBITS(this.bits); | ||
| 505 | DROPBITS(this.bits); | ||
| 506 | state->lens[state->have++] = this.val; | ||
| 507 | } | ||
| 508 | else { | ||
| 509 | if (this.val == 16) { | ||
| 510 | NEEDBITS(this.bits + 2); | ||
| 511 | DROPBITS(this.bits); | ||
| 512 | if (state->have == 0) { | ||
| 513 | strm->msg = (char *)"invalid bit length repeat"; | ||
| 514 | state->mode = BAD; | ||
| 515 | break; | ||
| 516 | } | ||
| 517 | len = state->lens[state->have - 1]; | ||
| 518 | copy = 3 + BITS(2); | ||
| 519 | DROPBITS(2); | ||
| 520 | } | ||
| 521 | else if (this.val == 17) { | ||
| 522 | NEEDBITS(this.bits + 3); | ||
| 523 | DROPBITS(this.bits); | ||
| 524 | len = 0; | ||
| 525 | copy = 3 + BITS(3); | ||
| 526 | DROPBITS(3); | ||
| 527 | } | ||
| 528 | else { | ||
| 529 | NEEDBITS(this.bits + 7); | ||
| 530 | DROPBITS(this.bits); | ||
| 531 | len = 0; | ||
| 532 | copy = 11 + BITS(7); | ||
| 533 | DROPBITS(7); | ||
| 534 | } | ||
| 535 | if (state->have + copy > state->nlen + state->ndist) { | ||
| 536 | strm->msg = (char *)"invalid bit length repeat"; | ||
| 537 | state->mode = BAD; | ||
| 538 | break; | ||
| 539 | } | ||
| 540 | while (copy--) | ||
| 541 | state->lens[state->have++] = (unsigned short)len; | ||
| 542 | } | ||
| 543 | } | ||
| 544 | |||
| 545 | /* handle error breaks in while */ | ||
| 546 | if (state->mode == BAD) break; | ||
| 547 | |||
| 548 | /* build code tables */ | ||
| 549 | state->next = state->codes; | ||
| 550 | state->lencode = (code const *)(state->next); | ||
| 551 | state->lenbits = 9; | ||
| 552 | ret = zlib_inflate_table(LENS, state->lens, state->nlen, &(state->next), | ||
| 553 | &(state->lenbits), state->work); | ||
| 554 | if (ret) { | ||
| 555 | strm->msg = (char *)"invalid literal/lengths set"; | ||
| 556 | state->mode = BAD; | ||
| 557 | break; | ||
| 558 | } | ||
| 559 | state->distcode = (code const *)(state->next); | ||
| 560 | state->distbits = 6; | ||
| 561 | ret = zlib_inflate_table(DISTS, state->lens + state->nlen, state->ndist, | ||
| 562 | &(state->next), &(state->distbits), state->work); | ||
| 563 | if (ret) { | ||
| 564 | strm->msg = (char *)"invalid distances set"; | ||
| 565 | state->mode = BAD; | ||
| 566 | break; | ||
| 567 | } | ||
| 568 | state->mode = LEN; | ||
| 569 | case LEN: | ||
| 570 | if (have >= 6 && left >= 258) { | ||
| 571 | RESTORE(); | ||
| 572 | inflate_fast(strm, out); | ||
| 573 | LOAD(); | ||
| 574 | break; | ||
| 575 | } | ||
| 576 | for (;;) { | ||
| 577 | this = state->lencode[BITS(state->lenbits)]; | ||
| 578 | if ((unsigned)(this.bits) <= bits) break; | ||
| 579 | PULLBYTE(); | ||
| 580 | } | ||
| 581 | if (this.op && (this.op & 0xf0) == 0) { | ||
| 582 | last = this; | ||
| 583 | for (;;) { | ||
| 584 | this = state->lencode[last.val + | ||
| 585 | (BITS(last.bits + last.op) >> last.bits)]; | ||
| 586 | if ((unsigned)(last.bits + this.bits) <= bits) break; | ||
| 587 | PULLBYTE(); | ||
| 588 | } | ||
| 589 | DROPBITS(last.bits); | ||
| 590 | } | ||
| 591 | DROPBITS(this.bits); | ||
| 592 | state->length = (unsigned)this.val; | ||
| 593 | if ((int)(this.op) == 0) { | ||
| 594 | state->mode = LIT; | ||
| 595 | break; | ||
| 596 | } | ||
| 597 | if (this.op & 32) { | ||
| 598 | state->mode = TYPE; | ||
| 599 | break; | ||
| 600 | } | ||
| 601 | if (this.op & 64) { | ||
| 602 | strm->msg = (char *)"invalid literal/length code"; | ||
| 603 | state->mode = BAD; | ||
| 604 | break; | ||
| 605 | } | ||
| 606 | state->extra = (unsigned)(this.op) & 15; | ||
| 607 | state->mode = LENEXT; | ||
| 608 | case LENEXT: | ||
| 609 | if (state->extra) { | ||
| 610 | NEEDBITS(state->extra); | ||
| 611 | state->length += BITS(state->extra); | ||
| 612 | DROPBITS(state->extra); | ||
| 613 | } | ||
| 614 | state->mode = DIST; | ||
| 615 | case DIST: | ||
| 616 | for (;;) { | ||
| 617 | this = state->distcode[BITS(state->distbits)]; | ||
| 618 | if ((unsigned)(this.bits) <= bits) break; | ||
| 619 | PULLBYTE(); | ||
| 620 | } | ||
| 621 | if ((this.op & 0xf0) == 0) { | ||
| 622 | last = this; | ||
| 623 | for (;;) { | ||
| 624 | this = state->distcode[last.val + | ||
| 625 | (BITS(last.bits + last.op) >> last.bits)]; | ||
| 626 | if ((unsigned)(last.bits + this.bits) <= bits) break; | ||
| 627 | PULLBYTE(); | ||
| 628 | } | ||
| 629 | DROPBITS(last.bits); | ||
| 630 | } | ||
| 631 | DROPBITS(this.bits); | ||
| 632 | if (this.op & 64) { | ||
| 633 | strm->msg = (char *)"invalid distance code"; | ||
| 634 | state->mode = BAD; | ||
| 635 | break; | ||
| 636 | } | ||
| 637 | state->offset = (unsigned)this.val; | ||
| 638 | state->extra = (unsigned)(this.op) & 15; | ||
| 639 | state->mode = DISTEXT; | ||
| 640 | case DISTEXT: | ||
| 641 | if (state->extra) { | ||
| 642 | NEEDBITS(state->extra); | ||
| 643 | state->offset += BITS(state->extra); | ||
| 644 | DROPBITS(state->extra); | ||
| 645 | } | ||
| 646 | #ifdef INFLATE_STRICT | ||
| 647 | if (state->offset > state->dmax) { | ||
| 648 | strm->msg = (char *)"invalid distance too far back"; | ||
| 649 | state->mode = BAD; | ||
| 650 | break; | ||
| 651 | } | ||
| 652 | #endif | ||
| 653 | if (state->offset > state->whave + out - left) { | ||
| 654 | strm->msg = (char *)"invalid distance too far back"; | ||
| 655 | state->mode = BAD; | ||
| 656 | break; | ||
| 657 | } | ||
| 658 | state->mode = MATCH; | ||
| 659 | case MATCH: | ||
| 660 | if (left == 0) goto inf_leave; | ||
| 661 | copy = out - left; | ||
| 662 | if (state->offset > copy) { /* copy from window */ | ||
| 663 | copy = state->offset - copy; | ||
| 664 | if (copy > state->write) { | ||
| 665 | copy -= state->write; | ||
| 666 | from = state->window + (state->wsize - copy); | ||
| 667 | } | ||
| 668 | else | ||
| 669 | from = state->window + (state->write - copy); | ||
| 670 | if (copy > state->length) copy = state->length; | ||
| 671 | } | ||
| 672 | else { /* copy from output */ | ||
| 673 | from = put - state->offset; | ||
| 674 | copy = state->length; | ||
| 675 | } | ||
| 676 | if (copy > left) copy = left; | ||
| 677 | left -= copy; | ||
| 678 | state->length -= copy; | ||
| 679 | do { | ||
| 680 | *put++ = *from++; | ||
| 681 | } while (--copy); | ||
| 682 | if (state->length == 0) state->mode = LEN; | ||
| 683 | break; | ||
| 684 | case LIT: | ||
| 685 | if (left == 0) goto inf_leave; | ||
| 686 | *put++ = (unsigned char)(state->length); | ||
| 687 | left--; | ||
| 688 | state->mode = LEN; | ||
| 689 | break; | ||
| 690 | case CHECK: | ||
| 691 | if (state->wrap) { | ||
| 692 | NEEDBITS(32); | ||
| 693 | out -= left; | ||
| 694 | strm->total_out += out; | ||
| 695 | state->total += out; | ||
| 696 | if (out) | ||
| 697 | strm->adler = state->check = | ||
| 698 | UPDATE(state->check, put - out, out); | ||
| 699 | out = left; | ||
| 700 | if (( | ||
| 701 | REVERSE(hold)) != state->check) { | ||
| 702 | strm->msg = (char *)"incorrect data check"; | ||
| 703 | state->mode = BAD; | ||
| 704 | break; | ||
| 705 | } | ||
| 706 | INITBITS(); | ||
| 707 | } | ||
| 708 | state->mode = DONE; | ||
| 709 | case DONE: | ||
| 710 | ret = Z_STREAM_END; | ||
| 711 | goto inf_leave; | ||
| 712 | case BAD: | ||
| 713 | ret = Z_DATA_ERROR; | ||
| 714 | goto inf_leave; | ||
| 715 | case MEM: | ||
| 716 | return Z_MEM_ERROR; | ||
| 717 | case SYNC: | ||
| 718 | default: | ||
| 719 | return Z_STREAM_ERROR; | ||
| 720 | } | ||
| 721 | |||
| 722 | /* | ||
| 723 | Return from inflate(), updating the total counts and the check value. | ||
| 724 | If there was no progress during the inflate() call, return a buffer | ||
| 725 | error. Call zlib_updatewindow() to create and/or update the window state. | ||
| 726 | */ | ||
| 727 | inf_leave: | ||
| 728 | RESTORE(); | ||
| 729 | if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) | ||
| 730 | zlib_updatewindow(strm, out); | ||
| 731 | |||
| 732 | in -= strm->avail_in; | ||
| 733 | out -= strm->avail_out; | ||
| 734 | strm->total_in += in; | ||
| 735 | strm->total_out += out; | ||
| 736 | state->total += out; | ||
| 737 | if (state->wrap && out) | ||
| 738 | strm->adler = state->check = | ||
| 739 | UPDATE(state->check, strm->next_out - out, out); | ||
| 740 | |||
| 741 | strm->data_type = state->bits + (state->last ? 64 : 0) + | ||
| 742 | (state->mode == TYPE ? 128 : 0); | ||
| 743 | if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) | ||
| 744 | ret = Z_BUF_ERROR; | ||
| 745 | |||
| 746 | if (flush == Z_PACKET_FLUSH && ret == Z_OK && | ||
| 747 | (strm->avail_out != 0 || strm->avail_in == 0)) | ||
| 748 | return zlib_inflateSyncPacket(strm); | ||
| 749 | return ret; | ||
| 750 | } | ||
| 751 | |||
| 752 | int zlib_inflateEnd(z_streamp strm) | ||
| 753 | { | ||
| 754 | if (strm == NULL || strm->state == NULL) | ||
| 755 | return Z_STREAM_ERROR; | ||
| 99 | return Z_OK; | 756 | return Z_OK; |
| 100 | } | 757 | } |
| 101 | 758 | ||
| 759 | #if 0 | ||
| 760 | int zlib_inflateSetDictionary(z_streamp strm, const Byte *dictionary, | ||
| 761 | uInt dictLength) | ||
| 762 | { | ||
| 763 | struct inflate_state *state; | ||
| 764 | unsigned long id; | ||
| 765 | |||
| 766 | /* check state */ | ||
| 767 | if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; | ||
| 768 | state = (struct inflate_state *)strm->state; | ||
| 769 | if (state->wrap != 0 && state->mode != DICT) | ||
| 770 | return Z_STREAM_ERROR; | ||
| 771 | |||
| 772 | /* check for correct dictionary id */ | ||
| 773 | if (state->mode == DICT) { | ||
| 774 | id = zlib_adler32(0L, NULL, 0); | ||
| 775 | id = zlib_adler32(id, dictionary, dictLength); | ||
| 776 | if (id != state->check) | ||
| 777 | return Z_DATA_ERROR; | ||
| 778 | } | ||
| 779 | |||
| 780 | /* copy dictionary to window */ | ||
| 781 | zlib_updatewindow(strm, strm->avail_out); | ||
| 102 | 782 | ||
| 103 | int zlib_inflateInit_( | 783 | if (dictLength > state->wsize) { |
| 104 | z_streamp z, | 784 | memcpy(state->window, dictionary + dictLength - state->wsize, |
| 105 | const char *version, | 785 | state->wsize); |
| 106 | int stream_size | 786 | state->whave = state->wsize; |
| 107 | ) | 787 | } |
| 788 | else { | ||
| 789 | memcpy(state->window + state->wsize - dictLength, dictionary, | ||
| 790 | dictLength); | ||
| 791 | state->whave = dictLength; | ||
| 792 | } | ||
| 793 | state->havedict = 1; | ||
| 794 | return Z_OK; | ||
| 795 | } | ||
| 796 | #endif | ||
| 797 | |||
| 798 | #if 0 | ||
| 799 | /* | ||
| 800 | Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found | ||
| 801 | or when out of input. When called, *have is the number of pattern bytes | ||
| 802 | found in order so far, in 0..3. On return *have is updated to the new | ||
| 803 | state. If on return *have equals four, then the pattern was found and the | ||
| 804 | return value is how many bytes were read including the last byte of the | ||
| 805 | pattern. If *have is less than four, then the pattern has not been found | ||
| 806 | yet and the return value is len. In the latter case, zlib_syncsearch() can be | ||
| 807 | called again with more data and the *have state. *have is initialized to | ||
| 808 | zero for the first call. | ||
| 809 | */ | ||
| 810 | static unsigned zlib_syncsearch(unsigned *have, unsigned char *buf, | ||
| 811 | unsigned len) | ||
| 108 | { | 812 | { |
| 109 | return zlib_inflateInit2_(z, DEF_WBITS, version, stream_size); | 813 | unsigned got; |
| 814 | unsigned next; | ||
| 815 | |||
| 816 | got = *have; | ||
| 817 | next = 0; | ||
| 818 | while (next < len && got < 4) { | ||
| 819 | if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) | ||
| 820 | got++; | ||
| 821 | else if (buf[next]) | ||
| 822 | got = 0; | ||
| 823 | else | ||
| 824 | got = 4 - got; | ||
| 825 | next++; | ||
| 826 | } | ||
| 827 | *have = got; | ||
| 828 | return next; | ||
| 110 | } | 829 | } |
| 830 | #endif | ||
| 111 | 831 | ||
| 112 | #undef NEEDBYTE | 832 | #if 0 |
| 113 | #undef NEXTBYTE | 833 | int zlib_inflateSync(z_streamp strm) |
| 114 | #define NEEDBYTE {if(z->avail_in==0)goto empty;r=trv;} | 834 | { |
| 115 | #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) | 835 | unsigned len; /* number of bytes to look at or looked at */ |
| 836 | unsigned long in, out; /* temporary to save total_in and total_out */ | ||
| 837 | unsigned char buf[4]; /* to restore bit buffer to byte string */ | ||
| 838 | struct inflate_state *state; | ||
| 839 | |||
| 840 | /* check parameters */ | ||
| 841 | if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; | ||
| 842 | state = (struct inflate_state *)strm->state; | ||
| 843 | if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; | ||
| 844 | |||
| 845 | /* if first time, start search in bit buffer */ | ||
| 846 | if (state->mode != SYNC) { | ||
| 847 | state->mode = SYNC; | ||
| 848 | state->hold <<= state->bits & 7; | ||
| 849 | state->bits -= state->bits & 7; | ||
| 850 | len = 0; | ||
| 851 | while (state->bits >= 8) { | ||
| 852 | buf[len++] = (unsigned char)(state->hold); | ||
| 853 | state->hold >>= 8; | ||
| 854 | state->bits -= 8; | ||
| 855 | } | ||
| 856 | state->have = 0; | ||
| 857 | zlib_syncsearch(&(state->have), buf, len); | ||
| 858 | } | ||
| 859 | |||
| 860 | /* search available input */ | ||
| 861 | len = zlib_syncsearch(&(state->have), strm->next_in, strm->avail_in); | ||
| 862 | strm->avail_in -= len; | ||
| 863 | strm->next_in += len; | ||
| 864 | strm->total_in += len; | ||
| 865 | |||
| 866 | /* return no joy or set up to restart inflate() on a new block */ | ||
| 867 | if (state->have != 4) return Z_DATA_ERROR; | ||
| 868 | in = strm->total_in; out = strm->total_out; | ||
| 869 | zlib_inflateReset(strm); | ||
| 870 | strm->total_in = in; strm->total_out = out; | ||
| 871 | state->mode = TYPE; | ||
| 872 | return Z_OK; | ||
| 873 | } | ||
| 874 | #endif | ||
| 116 | 875 | ||
| 117 | int zlib_inflate( | 876 | /* |
| 118 | z_streamp z, | 877 | * This subroutine adds the data at next_in/avail_in to the output history |
| 119 | int f | 878 | * without performing any output. The output buffer must be "caught up"; |
| 120 | ) | 879 | * i.e. no pending output but this should always be the case. The state must |
| 880 | * be waiting on the start of a block (i.e. mode == TYPE or HEAD). On exit, | ||
| 881 | * the output will also be caught up, and the checksum will have been updated | ||
| 882 | * if need be. | ||
| 883 | */ | ||
| 884 | int zlib_inflateIncomp(z_stream *z) | ||
| 121 | { | 885 | { |
| 122 | int r, trv; | 886 | struct inflate_state *state = (struct inflate_state *)z->state; |
| 123 | uInt b; | 887 | Byte *saved_no = z->next_out; |
| 124 | 888 | uInt saved_ao = z->avail_out; | |
| 125 | if (z == NULL || z->state == NULL || z->next_in == NULL) | 889 | |
| 126 | return Z_STREAM_ERROR; | 890 | if (state->mode != TYPE && state->mode != HEAD) |
| 127 | trv = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; | 891 | return Z_DATA_ERROR; |
| 128 | r = Z_BUF_ERROR; | 892 | |
| 129 | while (1) switch (z->state->mode) | 893 | /* Setup some variables to allow misuse of updateWindow */ |
| 130 | { | 894 | z->avail_out = 0; |
| 131 | case METHOD: | 895 | z->next_out = z->next_in + z->avail_in; |
| 132 | NEEDBYTE | 896 | |
| 133 | if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) | 897 | zlib_updatewindow(z, z->avail_in); |
| 134 | { | 898 | |
| 135 | z->state->mode = I_BAD; | 899 | /* Restore saved variables */ |
| 136 | z->msg = (char*)"unknown compression method"; | 900 | z->avail_out = saved_ao; |
| 137 | z->state->sub.marker = 5; /* can't try inflateSync */ | 901 | z->next_out = saved_no; |
| 138 | break; | 902 | |
| 139 | } | 903 | z->adler = state->check = |
| 140 | if ((z->state->sub.method >> 4) + 8 > z->state->wbits) | 904 | UPDATE(state->check, z->next_in, z->avail_in); |
| 141 | { | 905 | |
| 142 | z->state->mode = I_BAD; | 906 | z->total_out += z->avail_in; |
| 143 | z->msg = (char*)"invalid window size"; | 907 | z->total_in += z->avail_in; |
| 144 | z->state->sub.marker = 5; /* can't try inflateSync */ | 908 | z->next_in += z->avail_in; |
| 145 | break; | 909 | state->total += z->avail_in; |
| 146 | } | 910 | z->avail_in = 0; |
| 147 | z->state->mode = FLAG; | 911 | |
| 148 | case FLAG: | 912 | return Z_OK; |
| 149 | NEEDBYTE | ||
| 150 | b = NEXTBYTE; | ||
| 151 | if (((z->state->sub.method << 8) + b) % 31) | ||
| 152 | { | ||
| 153 | z->state->mode = I_BAD; | ||
| 154 | z->msg = (char*)"incorrect header check"; | ||
| 155 | z->state->sub.marker = 5; /* can't try inflateSync */ | ||
| 156 | break; | ||
| 157 | } | ||
| 158 | if (!(b & PRESET_DICT)) | ||
| 159 | { | ||
| 160 | z->state->mode = BLOCKS; | ||
| 161 | break; | ||
| 162 | } | ||
| 163 | z->state->mode = DICT4; | ||
| 164 | case DICT4: | ||
| 165 | NEEDBYTE | ||
| 166 | z->state->sub.check.need = (uLong)NEXTBYTE << 24; | ||
| 167 | z->state->mode = DICT3; | ||
| 168 | case DICT3: | ||
| 169 | NEEDBYTE | ||
| 170 | z->state->sub.check.need += (uLong)NEXTBYTE << 16; | ||
| 171 | z->state->mode = DICT2; | ||
| 172 | case DICT2: | ||
| 173 | NEEDBYTE | ||
| 174 | z->state->sub.check.need += (uLong)NEXTBYTE << 8; | ||
| 175 | z->state->mode = DICT1; | ||
| 176 | case DICT1: | ||
| 177 | NEEDBYTE | ||
| 178 | z->state->sub.check.need += (uLong)NEXTBYTE; | ||
| 179 | z->adler = z->state->sub.check.need; | ||
| 180 | z->state->mode = DICT0; | ||
| 181 | return Z_NEED_DICT; | ||
| 182 | case DICT0: | ||
| 183 | z->state->mode = I_BAD; | ||
| 184 | z->msg = (char*)"need dictionary"; | ||
| 185 | z->state->sub.marker = 0; /* can try inflateSync */ | ||
| 186 | return Z_STREAM_ERROR; | ||
| 187 | case BLOCKS: | ||
| 188 | r = zlib_inflate_blocks(z->state->blocks, z, r); | ||
| 189 | if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0) | ||
| 190 | r = zlib_inflate_packet_flush(z->state->blocks); | ||
| 191 | if (r == Z_DATA_ERROR) | ||
| 192 | { | ||
| 193 | z->state->mode = I_BAD; | ||
| 194 | z->state->sub.marker = 0; /* can try inflateSync */ | ||
| 195 | break; | ||
| 196 | } | ||
| 197 | if (r == Z_OK) | ||
| 198 | r = trv; | ||
| 199 | if (r != Z_STREAM_END) | ||
| 200 | return r; | ||
| 201 | r = trv; | ||
| 202 | zlib_inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); | ||
| 203 | if (z->state->nowrap) | ||
| 204 | { | ||
| 205 | z->state->mode = I_DONE; | ||
| 206 | break; | ||
| 207 | } | ||
| 208 | z->state->mode = CHECK4; | ||
| 209 | case CHECK4: | ||
| 210 | NEEDBYTE | ||
| 211 | z->state->sub.check.need = (uLong)NEXTBYTE << 24; | ||
| 212 | z->state->mode = CHECK3; | ||
| 213 | case CHECK3: | ||
| 214 | NEEDBYTE | ||
| 215 | z->state->sub.check.need += (uLong)NEXTBYTE << 16; | ||
| 216 | z->state->mode = CHECK2; | ||
| 217 | case CHECK2: | ||
| 218 | NEEDBYTE | ||
| 219 | z->state->sub.check.need += (uLong)NEXTBYTE << 8; | ||
| 220 | z->state->mode = CHECK1; | ||
| 221 | case CHECK1: | ||
| 222 | NEEDBYTE | ||
| 223 | z->state->sub.check.need += (uLong)NEXTBYTE; | ||
| 224 | |||
| 225 | if (z->state->sub.check.was != z->state->sub.check.need) | ||
| 226 | { | ||
| 227 | z->state->mode = I_BAD; | ||
| 228 | z->msg = (char*)"incorrect data check"; | ||
| 229 | z->state->sub.marker = 5; /* can't try inflateSync */ | ||
| 230 | break; | ||
| 231 | } | ||
| 232 | z->state->mode = I_DONE; | ||
| 233 | case I_DONE: | ||
| 234 | return Z_STREAM_END; | ||
| 235 | case I_BAD: | ||
| 236 | return Z_DATA_ERROR; | ||
| 237 | default: | ||
| 238 | return Z_STREAM_ERROR; | ||
| 239 | } | ||
| 240 | empty: | ||
| 241 | if (f != Z_PACKET_FLUSH) | ||
| 242 | return r; | ||
| 243 | z->state->mode = I_BAD; | ||
| 244 | z->msg = (char *)"need more for packet flush"; | ||
| 245 | z->state->sub.marker = 0; /* can try inflateSync */ | ||
| 246 | return Z_DATA_ERROR; | ||
| 247 | } | 913 | } |
diff --git a/lib/zlib_inflate/inflate.h b/lib/zlib_inflate/inflate.h new file mode 100644 index 000000000000..df8a6c92052d --- /dev/null +++ b/lib/zlib_inflate/inflate.h | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | /* inflate.h -- internal inflate state definition | ||
| 2 | * Copyright (C) 1995-2004 Mark Adler | ||
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | ||
| 4 | */ | ||
| 5 | |||
| 6 | /* WARNING: this file should *not* be used by applications. It is | ||
| 7 | part of the implementation of the compression library and is | ||
| 8 | subject to change. Applications should only use zlib.h. | ||
| 9 | */ | ||
| 10 | |||
| 11 | /* Possible inflate modes between inflate() calls */ | ||
| 12 | typedef enum { | ||
| 13 | HEAD, /* i: waiting for magic header */ | ||
| 14 | FLAGS, /* i: waiting for method and flags (gzip) */ | ||
| 15 | TIME, /* i: waiting for modification time (gzip) */ | ||
| 16 | OS, /* i: waiting for extra flags and operating system (gzip) */ | ||
| 17 | EXLEN, /* i: waiting for extra length (gzip) */ | ||
| 18 | EXTRA, /* i: waiting for extra bytes (gzip) */ | ||
| 19 | NAME, /* i: waiting for end of file name (gzip) */ | ||
| 20 | COMMENT, /* i: waiting for end of comment (gzip) */ | ||
| 21 | HCRC, /* i: waiting for header crc (gzip) */ | ||
| 22 | DICTID, /* i: waiting for dictionary check value */ | ||
| 23 | DICT, /* waiting for inflateSetDictionary() call */ | ||
| 24 | TYPE, /* i: waiting for type bits, including last-flag bit */ | ||
| 25 | TYPEDO, /* i: same, but skip check to exit inflate on new block */ | ||
| 26 | STORED, /* i: waiting for stored size (length and complement) */ | ||
| 27 | COPY, /* i/o: waiting for input or output to copy stored block */ | ||
| 28 | TABLE, /* i: waiting for dynamic block table lengths */ | ||
| 29 | LENLENS, /* i: waiting for code length code lengths */ | ||
| 30 | CODELENS, /* i: waiting for length/lit and distance code lengths */ | ||
| 31 | LEN, /* i: waiting for length/lit code */ | ||
| 32 | LENEXT, /* i: waiting for length extra bits */ | ||
| 33 | DIST, /* i: waiting for distance code */ | ||
| 34 | DISTEXT, /* i: waiting for distance extra bits */ | ||
| 35 | MATCH, /* o: waiting for output space to copy string */ | ||
| 36 | LIT, /* o: waiting for output space to write literal */ | ||
| 37 | CHECK, /* i: waiting for 32-bit check value */ | ||
| 38 | LENGTH, /* i: waiting for 32-bit length (gzip) */ | ||
| 39 | DONE, /* finished check, done -- remain here until reset */ | ||
| 40 | BAD, /* got a data error -- remain here until reset */ | ||
| 41 | MEM, /* got an inflate() memory error -- remain here until reset */ | ||
| 42 | SYNC /* looking for synchronization bytes to restart inflate() */ | ||
| 43 | } inflate_mode; | ||
| 44 | |||
| 45 | /* | ||
| 46 | State transitions between above modes - | ||
| 47 | |||
| 48 | (most modes can go to the BAD or MEM mode -- not shown for clarity) | ||
| 49 | |||
| 50 | Process header: | ||
| 51 | HEAD -> (gzip) or (zlib) | ||
| 52 | (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME | ||
| 53 | NAME -> COMMENT -> HCRC -> TYPE | ||
| 54 | (zlib) -> DICTID or TYPE | ||
| 55 | DICTID -> DICT -> TYPE | ||
| 56 | Read deflate blocks: | ||
| 57 | TYPE -> STORED or TABLE or LEN or CHECK | ||
| 58 | STORED -> COPY -> TYPE | ||
| 59 | TABLE -> LENLENS -> CODELENS -> LEN | ||
| 60 | Read deflate codes: | ||
| 61 | LEN -> LENEXT or LIT or TYPE | ||
| 62 | LENEXT -> DIST -> DISTEXT -> MATCH -> LEN | ||
| 63 | LIT -> LEN | ||
| 64 | Process trailer: | ||
| 65 | CHECK -> LENGTH -> DONE | ||
| 66 | */ | ||
| 67 | |||
| 68 | /* state maintained between inflate() calls. Approximately 7K bytes. */ | ||
| 69 | struct inflate_state { | ||
| 70 | inflate_mode mode; /* current inflate mode */ | ||
| 71 | int last; /* true if processing last block */ | ||
| 72 | int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ | ||
| 73 | int havedict; /* true if dictionary provided */ | ||
| 74 | int flags; /* gzip header method and flags (0 if zlib) */ | ||
| 75 | unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ | ||
| 76 | unsigned long check; /* protected copy of check value */ | ||
| 77 | unsigned long total; /* protected copy of output count */ | ||
| 78 | /* gz_headerp head; */ /* where to save gzip header information */ | ||
| 79 | /* sliding window */ | ||
| 80 | unsigned wbits; /* log base 2 of requested window size */ | ||
| 81 | unsigned wsize; /* window size or zero if not using window */ | ||
| 82 | unsigned whave; /* valid bytes in the window */ | ||
| 83 | unsigned write; /* window write index */ | ||
| 84 | unsigned char *window; /* allocated sliding window, if needed */ | ||
| 85 | /* bit accumulator */ | ||
| 86 | unsigned long hold; /* input bit accumulator */ | ||
| 87 | unsigned bits; /* number of bits in "in" */ | ||
| 88 | /* for string and stored block copying */ | ||
| 89 | unsigned length; /* literal or length of data to copy */ | ||
| 90 | unsigned offset; /* distance back to copy string from */ | ||
| 91 | /* for table and code decoding */ | ||
| 92 | unsigned extra; /* extra bits needed */ | ||
| 93 | /* fixed and dynamic code tables */ | ||
| 94 | code const *lencode; /* starting table for length/literal codes */ | ||
| 95 | code const *distcode; /* starting table for distance codes */ | ||
| 96 | unsigned lenbits; /* index bits for lencode */ | ||
| 97 | unsigned distbits; /* index bits for distcode */ | ||
| 98 | /* dynamic table building */ | ||
| 99 | unsigned ncode; /* number of code length code lengths */ | ||
| 100 | unsigned nlen; /* number of length code lengths */ | ||
| 101 | unsigned ndist; /* number of distance code lengths */ | ||
| 102 | unsigned have; /* number of code lengths in lens[] */ | ||
| 103 | code *next; /* next available space in codes[] */ | ||
| 104 | unsigned short lens[320]; /* temporary storage for code lengths */ | ||
| 105 | unsigned short work[288]; /* work area for code table building */ | ||
| 106 | code codes[ENOUGH]; /* space for code tables */ | ||
| 107 | }; | ||
diff --git a/lib/zlib_inflate/inflate_syms.c b/lib/zlib_inflate/inflate_syms.c index ef49738f57ec..2061d4f06765 100644 --- a/lib/zlib_inflate/inflate_syms.c +++ b/lib/zlib_inflate/inflate_syms.c | |||
| @@ -12,8 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | EXPORT_SYMBOL(zlib_inflate_workspacesize); | 13 | EXPORT_SYMBOL(zlib_inflate_workspacesize); |
| 14 | EXPORT_SYMBOL(zlib_inflate); | 14 | EXPORT_SYMBOL(zlib_inflate); |
| 15 | EXPORT_SYMBOL(zlib_inflateInit_); | 15 | EXPORT_SYMBOL(zlib_inflateInit2); |
| 16 | EXPORT_SYMBOL(zlib_inflateInit2_); | ||
| 17 | EXPORT_SYMBOL(zlib_inflateEnd); | 16 | EXPORT_SYMBOL(zlib_inflateEnd); |
| 18 | EXPORT_SYMBOL(zlib_inflateReset); | 17 | EXPORT_SYMBOL(zlib_inflateReset); |
| 19 | EXPORT_SYMBOL(zlib_inflateIncomp); | 18 | EXPORT_SYMBOL(zlib_inflateIncomp); |
diff --git a/lib/zlib_inflate/inflate_sync.c b/lib/zlib_inflate/inflate_sync.c deleted file mode 100644 index 61411ff89d61..000000000000 --- a/lib/zlib_inflate/inflate_sync.c +++ /dev/null | |||
| @@ -1,152 +0,0 @@ | |||
| 1 | /* inflate.c -- zlib interface to inflate modules | ||
| 2 | * Copyright (C) 1995-1998 Mark Adler | ||
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/zutil.h> | ||
| 7 | #include "infblock.h" | ||
| 8 | #include "infutil.h" | ||
| 9 | |||
| 10 | #if 0 | ||
| 11 | int zlib_inflateSync( | ||
| 12 | z_streamp z | ||
| 13 | ) | ||
| 14 | { | ||
| 15 | uInt n; /* number of bytes to look at */ | ||
| 16 | Byte *p; /* pointer to bytes */ | ||
| 17 | uInt m; /* number of marker bytes found in a row */ | ||
| 18 | uLong r, w; /* temporaries to save total_in and total_out */ | ||
| 19 | |||
| 20 | /* set up */ | ||
| 21 | if (z == NULL || z->state == NULL) | ||
| 22 | return Z_STREAM_ERROR; | ||
| 23 | if (z->state->mode != I_BAD) | ||
| 24 | { | ||
| 25 | z->state->mode = I_BAD; | ||
| 26 | z->state->sub.marker = 0; | ||
| 27 | } | ||
| 28 | if ((n = z->avail_in) == 0) | ||
| 29 | return Z_BUF_ERROR; | ||
| 30 | p = z->next_in; | ||
| 31 | m = z->state->sub.marker; | ||
| 32 | |||
| 33 | /* search */ | ||
| 34 | while (n && m < 4) | ||
| 35 | { | ||
| 36 | static const Byte mark[4] = {0, 0, 0xff, 0xff}; | ||
| 37 | if (*p == mark[m]) | ||
| 38 | m++; | ||
| 39 | else if (*p) | ||
| 40 | m = 0; | ||
| 41 | else | ||
| 42 | m = 4 - m; | ||
| 43 | p++, n--; | ||
| 44 | } | ||
| 45 | |||
| 46 | /* restore */ | ||
| 47 | z->total_in += p - z->next_in; | ||
| 48 | z->next_in = p; | ||
| 49 | z->avail_in = n; | ||
| 50 | z->state->sub.marker = m; | ||
| 51 | |||
| 52 | /* return no joy or set up to restart on a new block */ | ||
| 53 | if (m != 4) | ||
| 54 | return Z_DATA_ERROR; | ||
| 55 | r = z->total_in; w = z->total_out; | ||
| 56 | zlib_inflateReset(z); | ||
| 57 | z->total_in = r; z->total_out = w; | ||
| 58 | z->state->mode = BLOCKS; | ||
| 59 | return Z_OK; | ||
| 60 | } | ||
| 61 | #endif /* 0 */ | ||
| 62 | |||
| 63 | |||
| 64 | /* Returns true if inflate is currently at the end of a block generated | ||
| 65 | * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP | ||
| 66 | * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH | ||
| 67 | * but removes the length bytes of the resulting empty stored block. When | ||
| 68 | * decompressing, PPP checks that at the end of input packet, inflate is | ||
| 69 | * waiting for these length bytes. | ||
| 70 | */ | ||
| 71 | #if 0 | ||
| 72 | int zlib_inflateSyncPoint( | ||
| 73 | z_streamp z | ||
| 74 | ) | ||
| 75 | { | ||
| 76 | if (z == NULL || z->state == NULL || z->state->blocks == NULL) | ||
| 77 | return Z_STREAM_ERROR; | ||
| 78 | return zlib_inflate_blocks_sync_point(z->state->blocks); | ||
| 79 | } | ||
| 80 | #endif /* 0 */ | ||
| 81 | |||
| 82 | /* | ||
| 83 | * This subroutine adds the data at next_in/avail_in to the output history | ||
| 84 | * without performing any output. The output buffer must be "caught up"; | ||
| 85 | * i.e. no pending output (hence s->read equals s->write), and the state must | ||
| 86 | * be BLOCKS (i.e. we should be willing to see the start of a series of | ||
| 87 | * BLOCKS). On exit, the output will also be caught up, and the checksum | ||
| 88 | * will have been updated if need be. | ||
| 89 | */ | ||
| 90 | static int zlib_inflate_addhistory(inflate_blocks_statef *s, | ||
| 91 | z_stream *z) | ||
| 92 | { | ||
| 93 | uLong b; /* bit buffer */ /* NOT USED HERE */ | ||
| 94 | uInt k; /* bits in bit buffer */ /* NOT USED HERE */ | ||
| 95 | uInt t; /* temporary storage */ | ||
| 96 | Byte *p; /* input data pointer */ | ||
| 97 | uInt n; /* bytes available there */ | ||
| 98 | Byte *q; /* output window write pointer */ | ||
| 99 | uInt m; /* bytes to end of window or read pointer */ | ||
| 100 | |||
| 101 | if (s->read != s->write) | ||
| 102 | return Z_STREAM_ERROR; | ||
| 103 | if (s->mode != TYPE) | ||
| 104 | return Z_DATA_ERROR; | ||
| 105 | |||
| 106 | /* we're ready to rock */ | ||
| 107 | LOAD | ||
| 108 | /* while there is input ready, copy to output buffer, moving | ||
| 109 | * pointers as needed. | ||
| 110 | */ | ||
| 111 | while (n) { | ||
| 112 | t = n; /* how many to do */ | ||
| 113 | /* is there room until end of buffer? */ | ||
| 114 | if (t > m) t = m; | ||
| 115 | /* update check information */ | ||
| 116 | if (s->checkfn != NULL) | ||
| 117 | s->check = (*s->checkfn)(s->check, q, t); | ||
| 118 | memcpy(q, p, t); | ||
| 119 | q += t; | ||
| 120 | p += t; | ||
| 121 | n -= t; | ||
| 122 | z->total_out += t; | ||
| 123 | s->read = q; /* drag read pointer forward */ | ||
| 124 | /* WWRAP */ /* expand WWRAP macro by hand to handle s->read */ | ||
| 125 | if (q == s->end) { | ||
| 126 | s->read = q = s->window; | ||
| 127 | m = WAVAIL; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | UPDATE | ||
| 131 | return Z_OK; | ||
| 132 | } | ||
| 133 | |||
| 134 | |||
| 135 | /* | ||
| 136 | * This subroutine adds the data at next_in/avail_in to the output history | ||
| 137 | * without performing any output. The output buffer must be "caught up"; | ||
| 138 | * i.e. no pending output (hence s->read equals s->write), and the state must | ||
| 139 | * be BLOCKS (i.e. we should be willing to see the start of a series of | ||
| 140 | * BLOCKS). On exit, the output will also be caught up, and the checksum | ||
| 141 | * will have been updated if need be. | ||
| 142 | */ | ||
| 143 | |||
| 144 | int zlib_inflateIncomp( | ||
| 145 | z_stream *z | ||
| 146 | |||
| 147 | ) | ||
| 148 | { | ||
| 149 | if (z->state->mode != BLOCKS) | ||
| 150 | return Z_DATA_ERROR; | ||
| 151 | return zlib_inflate_addhistory(z->state->blocks, z); | ||
| 152 | } | ||
diff --git a/lib/zlib_inflate/inftrees.c b/lib/zlib_inflate/inftrees.c index 874950ec4858..62343c53bf7e 100644 --- a/lib/zlib_inflate/inftrees.c +++ b/lib/zlib_inflate/inftrees.c | |||
| @@ -1,412 +1,329 @@ | |||
| 1 | /* inftrees.c -- generate Huffman trees for efficient decoding | 1 | /* inftrees.c -- generate Huffman trees for efficient decoding |
| 2 | * Copyright (C) 1995-1998 Mark Adler | 2 | * Copyright (C) 1995-2005 Mark Adler |
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | 3 | * For conditions of distribution and use, see copyright notice in zlib.h |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | #include <linux/zutil.h> | 6 | #include <linux/zutil.h> |
| 7 | #include "inftrees.h" | 7 | #include "inftrees.h" |
| 8 | #include "infutil.h" | ||
| 9 | 8 | ||
| 10 | static const char inflate_copyright[] __attribute_used__ = | 9 | #define MAXBITS 15 |
| 11 | " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; | 10 | |
| 11 | const char inflate_copyright[] = | ||
| 12 | " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; | ||
| 12 | /* | 13 | /* |
| 13 | If you use the zlib library in a product, an acknowledgment is welcome | 14 | If you use the zlib library in a product, an acknowledgment is welcome |
| 14 | in the documentation of your product. If for some reason you cannot | 15 | in the documentation of your product. If for some reason you cannot |
| 15 | include such an acknowledgment, I would appreciate that you keep this | 16 | include such an acknowledgment, I would appreciate that you keep this |
| 16 | copyright string in the executable of your product. | 17 | copyright string in the executable of your product. |
| 17 | */ | 18 | */ |
| 18 | struct internal_state; | ||
| 19 | |||
| 20 | /* simplify the use of the inflate_huft type with some defines */ | ||
| 21 | #define exop word.what.Exop | ||
| 22 | #define bits word.what.Bits | ||
| 23 | |||
| 24 | |||
| 25 | static int huft_build ( | ||
| 26 | uInt *, /* code lengths in bits */ | ||
| 27 | uInt, /* number of codes */ | ||
| 28 | uInt, /* number of "simple" codes */ | ||
| 29 | const uInt *, /* list of base values for non-simple codes */ | ||
| 30 | const uInt *, /* list of extra bits for non-simple codes */ | ||
| 31 | inflate_huft **, /* result: starting table */ | ||
| 32 | uInt *, /* maximum lookup bits (returns actual) */ | ||
| 33 | inflate_huft *, /* space for trees */ | ||
| 34 | uInt *, /* hufts used in space */ | ||
| 35 | uInt * ); /* space for values */ | ||
| 36 | |||
| 37 | /* Tables for deflate from PKZIP's appnote.txt. */ | ||
| 38 | static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ | ||
| 39 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, | ||
| 40 | 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; | ||
| 41 | /* see note #13 above about 258 */ | ||
| 42 | static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ | ||
| 43 | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, | ||
| 44 | 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ | ||
| 45 | static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ | ||
| 46 | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, | ||
| 47 | 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, | ||
| 48 | 8193, 12289, 16385, 24577}; | ||
| 49 | static const uInt cpdext[30] = { /* Extra bits for distance codes */ | ||
| 50 | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, | ||
| 51 | 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, | ||
| 52 | 12, 12, 13, 13}; | ||
| 53 | 19 | ||
| 54 | /* | 20 | /* |
| 55 | Huffman code decoding is performed using a multi-level table lookup. | 21 | Build a set of tables to decode the provided canonical Huffman code. |
| 56 | The fastest way to decode is to simply build a lookup table whose | 22 | The code lengths are lens[0..codes-1]. The result starts at *table, |
| 57 | size is determined by the longest code. However, the time it takes | 23 | whose indices are 0..2^bits-1. work is a writable array of at least |
| 58 | to build this table can also be a factor if the data being decoded | 24 | lens shorts, which is used as a work area. type is the type of code |
| 59 | is not very long. The most common codes are necessarily the | 25 | to be generated, CODES, LENS, or DISTS. On return, zero is success, |
| 60 | shortest codes, so those codes dominate the decoding time, and hence | 26 | -1 is an invalid code, and +1 means that ENOUGH isn't enough. table |
| 61 | the speed. The idea is you can have a shorter table that decodes the | 27 | on return points to the next available entry's address. bits is the |
| 62 | shorter, more probable codes, and then point to subsidiary tables for | 28 | requested root table index bits, and on return it is the actual root |
| 63 | the longer codes. The time it costs to decode the longer codes is | 29 | table index bits. It will differ if the request is greater than the |
| 64 | then traded against the time it takes to make longer tables. | 30 | longest code or if it is less than the shortest code. |
| 65 | |||
| 66 | This results of this trade are in the variables lbits and dbits | ||
| 67 | below. lbits is the number of bits the first level table for literal/ | ||
| 68 | length codes can decode in one step, and dbits is the same thing for | ||
| 69 | the distance codes. Subsequent tables are also less than or equal to | ||
| 70 | those sizes. These values may be adjusted either when all of the | ||
| 71 | codes are shorter than that, in which case the longest code length in | ||
| 72 | bits is used, or when the shortest code is *longer* than the requested | ||
| 73 | table size, in which case the length of the shortest code in bits is | ||
| 74 | used. | ||
| 75 | |||
| 76 | There are two different values for the two tables, since they code a | ||
| 77 | different number of possibilities each. The literal/length table | ||
| 78 | codes 286 possible values, or in a flat code, a little over eight | ||
| 79 | bits. The distance table codes 30 possible values, or a little less | ||
| 80 | than five bits, flat. The optimum values for speed end up being | ||
| 81 | about one bit more than those, so lbits is 8+1 and dbits is 5+1. | ||
| 82 | The optimum values may differ though from machine to machine, and | ||
| 83 | possibly even between compilers. Your mileage may vary. | ||
| 84 | */ | 31 | */ |
| 85 | 32 | int zlib_inflate_table(type, lens, codes, table, bits, work) | |
| 86 | 33 | codetype type; | |
| 87 | /* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ | 34 | unsigned short *lens; |
| 88 | #define BMAX 15 /* maximum bit length of any code */ | 35 | unsigned codes; |
| 89 | 36 | code **table; | |
| 90 | static int huft_build( | 37 | unsigned *bits; |
| 91 | uInt *b, /* code lengths in bits (all assumed <= BMAX) */ | 38 | unsigned short *work; |
| 92 | uInt n, /* number of codes (assumed <= 288) */ | ||
| 93 | uInt s, /* number of simple-valued codes (0..s-1) */ | ||
| 94 | const uInt *d, /* list of base values for non-simple codes */ | ||
| 95 | const uInt *e, /* list of extra bits for non-simple codes */ | ||
| 96 | inflate_huft **t, /* result: starting table */ | ||
| 97 | uInt *m, /* maximum lookup bits, returns actual */ | ||
| 98 | inflate_huft *hp, /* space for trees */ | ||
| 99 | uInt *hn, /* hufts used in space */ | ||
| 100 | uInt *v /* working area: values in order of bit length */ | ||
| 101 | ) | ||
| 102 | /* Given a list of code lengths and a maximum table size, make a set of | ||
| 103 | tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR | ||
| 104 | if the given code set is incomplete (the tables are still built in this | ||
| 105 | case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of | ||
| 106 | lengths), or Z_MEM_ERROR if not enough memory. */ | ||
| 107 | { | 39 | { |
| 40 | unsigned len; /* a code's length in bits */ | ||
| 41 | unsigned sym; /* index of code symbols */ | ||
| 42 | unsigned min, max; /* minimum and maximum code lengths */ | ||
| 43 | unsigned root; /* number of index bits for root table */ | ||
| 44 | unsigned curr; /* number of index bits for current table */ | ||
| 45 | unsigned drop; /* code bits to drop for sub-table */ | ||
| 46 | int left; /* number of prefix codes available */ | ||
| 47 | unsigned used; /* code entries in table used */ | ||
| 48 | unsigned huff; /* Huffman code */ | ||
| 49 | unsigned incr; /* for incrementing code, index */ | ||
| 50 | unsigned fill; /* index for replicating entries */ | ||
| 51 | unsigned low; /* low bits for current root entry */ | ||
| 52 | unsigned mask; /* mask for low root bits */ | ||
| 53 | code this; /* table entry for duplication */ | ||
| 54 | code *next; /* next available space in table */ | ||
| 55 | const unsigned short *base; /* base value table to use */ | ||
| 56 | const unsigned short *extra; /* extra bits table to use */ | ||
| 57 | int end; /* use base and extra for symbol > end */ | ||
| 58 | unsigned short count[MAXBITS+1]; /* number of codes of each length */ | ||
| 59 | unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ | ||
| 60 | static const unsigned short lbase[31] = { /* Length codes 257..285 base */ | ||
| 61 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, | ||
| 62 | 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; | ||
| 63 | static const unsigned short lext[31] = { /* Length codes 257..285 extra */ | ||
| 64 | 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, | ||
| 65 | 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; | ||
| 66 | static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ | ||
| 67 | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, | ||
| 68 | 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, | ||
| 69 | 8193, 12289, 16385, 24577, 0, 0}; | ||
| 70 | static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ | ||
| 71 | 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, | ||
| 72 | 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, | ||
| 73 | 28, 28, 29, 29, 64, 64}; | ||
| 74 | |||
| 75 | /* | ||
| 76 | Process a set of code lengths to create a canonical Huffman code. The | ||
| 77 | code lengths are lens[0..codes-1]. Each length corresponds to the | ||
| 78 | symbols 0..codes-1. The Huffman code is generated by first sorting the | ||
| 79 | symbols by length from short to long, and retaining the symbol order | ||
| 80 | for codes with equal lengths. Then the code starts with all zero bits | ||
| 81 | for the first code of the shortest length, and the codes are integer | ||
| 82 | increments for the same length, and zeros are appended as the length | ||
| 83 | increases. For the deflate format, these bits are stored backwards | ||
| 84 | from their more natural integer increment ordering, and so when the | ||
| 85 | decoding tables are built in the large loop below, the integer codes | ||
| 86 | are incremented backwards. | ||
| 87 | |||
| 88 | This routine assumes, but does not check, that all of the entries in | ||
| 89 | lens[] are in the range 0..MAXBITS. The caller must assure this. | ||
| 90 | 1..MAXBITS is interpreted as that code length. zero means that that | ||
| 91 | symbol does not occur in this code. | ||
| 92 | |||
| 93 | The codes are sorted by computing a count of codes for each length, | ||
| 94 | creating from that a table of starting indices for each length in the | ||
| 95 | sorted table, and then entering the symbols in order in the sorted | ||
| 96 | table. The sorted table is work[], with that space being provided by | ||
| 97 | the caller. | ||
| 98 | |||
| 99 | The length counts are used for other purposes as well, i.e. finding | ||
| 100 | the minimum and maximum length codes, determining if there are any | ||
| 101 | codes at all, checking for a valid set of lengths, and looking ahead | ||
| 102 | at length counts to determine sub-table sizes when building the | ||
| 103 | decoding tables. | ||
| 104 | */ | ||
| 105 | |||
| 106 | /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ | ||
| 107 | for (len = 0; len <= MAXBITS; len++) | ||
| 108 | count[len] = 0; | ||
| 109 | for (sym = 0; sym < codes; sym++) | ||
| 110 | count[lens[sym]]++; | ||
| 111 | |||
| 112 | /* bound code lengths, force root to be within code lengths */ | ||
| 113 | root = *bits; | ||
| 114 | for (max = MAXBITS; max >= 1; max--) | ||
| 115 | if (count[max] != 0) break; | ||
| 116 | if (root > max) root = max; | ||
| 117 | if (max == 0) { /* no symbols to code at all */ | ||
| 118 | this.op = (unsigned char)64; /* invalid code marker */ | ||
| 119 | this.bits = (unsigned char)1; | ||
| 120 | this.val = (unsigned short)0; | ||
| 121 | *(*table)++ = this; /* make a table to force an error */ | ||
| 122 | *(*table)++ = this; | ||
| 123 | *bits = 1; | ||
| 124 | return 0; /* no symbols, but wait for decoding to report error */ | ||
| 125 | } | ||
| 126 | for (min = 1; min <= MAXBITS; min++) | ||
| 127 | if (count[min] != 0) break; | ||
| 128 | if (root < min) root = min; | ||
| 129 | |||
| 130 | /* check for an over-subscribed or incomplete set of lengths */ | ||
| 131 | left = 1; | ||
| 132 | for (len = 1; len <= MAXBITS; len++) { | ||
| 133 | left <<= 1; | ||
| 134 | left -= count[len]; | ||
| 135 | if (left < 0) return -1; /* over-subscribed */ | ||
| 136 | } | ||
| 137 | if (left > 0 && (type == CODES || max != 1)) | ||
| 138 | return -1; /* incomplete set */ | ||
| 139 | |||
| 140 | /* generate offsets into symbol table for each length for sorting */ | ||
| 141 | offs[1] = 0; | ||
| 142 | for (len = 1; len < MAXBITS; len++) | ||
| 143 | offs[len + 1] = offs[len] + count[len]; | ||
| 144 | |||
| 145 | /* sort symbols by length, by symbol order within each length */ | ||
| 146 | for (sym = 0; sym < codes; sym++) | ||
| 147 | if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; | ||
| 148 | |||
| 149 | /* | ||
| 150 | Create and fill in decoding tables. In this loop, the table being | ||
| 151 | filled is at next and has curr index bits. The code being used is huff | ||
| 152 | with length len. That code is converted to an index by dropping drop | ||
| 153 | bits off of the bottom. For codes where len is less than drop + curr, | ||
| 154 | those top drop + curr - len bits are incremented through all values to | ||
| 155 | fill the table with replicated entries. | ||
| 156 | |||
| 157 | root is the number of index bits for the root table. When len exceeds | ||
| 158 | root, sub-tables are created pointed to by the root entry with an index | ||
| 159 | of the low root bits of huff. This is saved in low to check for when a | ||
| 160 | new sub-table should be started. drop is zero when the root table is | ||
| 161 | being filled, and drop is root when sub-tables are being filled. | ||
| 162 | |||
| 163 | When a new sub-table is needed, it is necessary to look ahead in the | ||
| 164 | code lengths to determine what size sub-table is needed. The length | ||
| 165 | counts are used for this, and so count[] is decremented as codes are | ||
| 166 | entered in the tables. | ||
| 167 | |||
| 168 | used keeps track of how many table entries have been allocated from the | ||
| 169 | provided *table space. It is checked when a LENS table is being made | ||
| 170 | against the space in *table, ENOUGH, minus the maximum space needed by | ||
| 171 | the worst case distance code, MAXD. This should never happen, but the | ||
| 172 | sufficiency of ENOUGH has not been proven exhaustively, hence the check. | ||
| 173 | This assumes that when type == LENS, bits == 9. | ||
| 174 | |||
| 175 | sym increments through all symbols, and the loop terminates when | ||
| 176 | all codes of length max, i.e. all codes, have been processed. This | ||
| 177 | routine permits incomplete codes, so another loop after this one fills | ||
| 178 | in the rest of the decoding tables with invalid code markers. | ||
| 179 | */ | ||
| 180 | |||
| 181 | /* set up for code type */ | ||
| 182 | switch (type) { | ||
| 183 | case CODES: | ||
| 184 | base = extra = work; /* dummy value--not used */ | ||
| 185 | end = 19; | ||
| 186 | break; | ||
| 187 | case LENS: | ||
| 188 | base = lbase; | ||
| 189 | base -= 257; | ||
| 190 | extra = lext; | ||
| 191 | extra -= 257; | ||
| 192 | end = 256; | ||
| 193 | break; | ||
| 194 | default: /* DISTS */ | ||
| 195 | base = dbase; | ||
| 196 | extra = dext; | ||
| 197 | end = -1; | ||
| 198 | } | ||
| 108 | 199 | ||
| 109 | uInt a; /* counter for codes of length k */ | 200 | /* initialize state for loop */ |
| 110 | uInt c[BMAX+1]; /* bit length count table */ | 201 | huff = 0; /* starting code */ |
| 111 | uInt f; /* i repeats in table every f entries */ | 202 | sym = 0; /* starting code symbol */ |
| 112 | int g; /* maximum code length */ | 203 | len = min; /* starting code length */ |
| 113 | int h; /* table level */ | 204 | next = *table; /* current table to fill in */ |
| 114 | register uInt i; /* counter, current code */ | 205 | curr = root; /* current table index bits */ |
| 115 | register uInt j; /* counter */ | 206 | drop = 0; /* current bits to drop from code for index */ |
| 116 | register int k; /* number of bits in current code */ | 207 | low = (unsigned)(-1); /* trigger new sub-table when len > root */ |
| 117 | int l; /* bits per table (returned in m) */ | 208 | used = 1U << root; /* use root table entries */ |
| 118 | uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ | 209 | mask = used - 1; /* mask for comparing low */ |
| 119 | register uInt *p; /* pointer into c[], b[], or v[] */ | 210 | |
| 120 | inflate_huft *q; /* points to current table */ | 211 | /* check available table space */ |
| 121 | struct inflate_huft_s r; /* table entry for structure assignment */ | 212 | if (type == LENS && used >= ENOUGH - MAXD) |
| 122 | inflate_huft *u[BMAX]; /* table stack */ | 213 | return 1; |
| 123 | register int w; /* bits before this table == (l * h) */ | 214 | |
| 124 | uInt x[BMAX+1]; /* bit offsets, then code stack */ | 215 | /* process all codes and make table entries */ |
| 125 | uInt *xp; /* pointer into x */ | 216 | for (;;) { |
| 126 | int y; /* number of dummy codes added */ | 217 | /* create table entry */ |
| 127 | uInt z; /* number of entries in current table */ | 218 | this.bits = (unsigned char)(len - drop); |
| 128 | 219 | if ((int)(work[sym]) < end) { | |
| 129 | 220 | this.op = (unsigned char)0; | |
| 130 | /* Generate counts for each bit length */ | 221 | this.val = work[sym]; |
| 131 | p = c; | ||
| 132 | #define C0 *p++ = 0; | ||
| 133 | #define C2 C0 C0 C0 C0 | ||
| 134 | #define C4 C2 C2 C2 C2 | ||
| 135 | C4 /* clear c[]--assume BMAX+1 is 16 */ | ||
| 136 | p = b; i = n; | ||
| 137 | do { | ||
| 138 | c[*p++]++; /* assume all entries <= BMAX */ | ||
| 139 | } while (--i); | ||
| 140 | if (c[0] == n) /* null input--all zero length codes */ | ||
| 141 | { | ||
| 142 | *t = NULL; | ||
| 143 | *m = 0; | ||
| 144 | return Z_OK; | ||
| 145 | } | ||
| 146 | |||
| 147 | |||
| 148 | /* Find minimum and maximum length, bound *m by those */ | ||
| 149 | l = *m; | ||
| 150 | for (j = 1; j <= BMAX; j++) | ||
| 151 | if (c[j]) | ||
| 152 | break; | ||
| 153 | k = j; /* minimum code length */ | ||
| 154 | if ((uInt)l < j) | ||
| 155 | l = j; | ||
| 156 | for (i = BMAX; i; i--) | ||
| 157 | if (c[i]) | ||
| 158 | break; | ||
| 159 | g = i; /* maximum code length */ | ||
| 160 | if ((uInt)l > i) | ||
| 161 | l = i; | ||
| 162 | *m = l; | ||
| 163 | |||
| 164 | |||
| 165 | /* Adjust last length count to fill out codes, if needed */ | ||
| 166 | for (y = 1 << j; j < i; j++, y <<= 1) | ||
| 167 | if ((y -= c[j]) < 0) | ||
| 168 | return Z_DATA_ERROR; | ||
| 169 | if ((y -= c[i]) < 0) | ||
| 170 | return Z_DATA_ERROR; | ||
| 171 | c[i] += y; | ||
| 172 | |||
| 173 | |||
| 174 | /* Generate starting offsets into the value table for each length */ | ||
| 175 | x[1] = j = 0; | ||
| 176 | p = c + 1; xp = x + 2; | ||
| 177 | while (--i) { /* note that i == g from above */ | ||
| 178 | *xp++ = (j += *p++); | ||
| 179 | } | ||
| 180 | |||
| 181 | |||
| 182 | /* Make a table of values in order of bit lengths */ | ||
| 183 | p = b; i = 0; | ||
| 184 | do { | ||
| 185 | if ((j = *p++) != 0) | ||
| 186 | v[x[j]++] = i; | ||
| 187 | } while (++i < n); | ||
| 188 | n = x[g]; /* set n to length of v */ | ||
| 189 | |||
| 190 | |||
| 191 | /* Generate the Huffman codes and for each, make the table entries */ | ||
| 192 | x[0] = i = 0; /* first Huffman code is zero */ | ||
| 193 | p = v; /* grab values in bit order */ | ||
| 194 | h = -1; /* no tables yet--level -1 */ | ||
| 195 | w = -l; /* bits decoded == (l * h) */ | ||
| 196 | u[0] = NULL; /* just to keep compilers happy */ | ||
| 197 | q = NULL; /* ditto */ | ||
| 198 | z = 0; /* ditto */ | ||
| 199 | |||
| 200 | /* go through the bit lengths (k already is bits in shortest code) */ | ||
| 201 | for (; k <= g; k++) | ||
| 202 | { | ||
| 203 | a = c[k]; | ||
| 204 | while (a--) | ||
| 205 | { | ||
| 206 | /* here i is the Huffman code of length k bits for value *p */ | ||
| 207 | /* make tables up to required level */ | ||
| 208 | while (k > w + l) | ||
| 209 | { | ||
| 210 | h++; | ||
| 211 | w += l; /* previous table always l bits */ | ||
| 212 | |||
| 213 | /* compute minimum size table less than or equal to l bits */ | ||
| 214 | z = g - w; | ||
| 215 | z = z > (uInt)l ? l : z; /* table size upper limit */ | ||
| 216 | if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ | ||
| 217 | { /* too few codes for k-w bit table */ | ||
| 218 | f -= a + 1; /* deduct codes from patterns left */ | ||
| 219 | xp = c + k; | ||
| 220 | if (j < z) | ||
| 221 | while (++j < z) /* try smaller tables up to z bits */ | ||
| 222 | { | ||
| 223 | if ((f <<= 1) <= *++xp) | ||
| 224 | break; /* enough codes to use up j bits */ | ||
| 225 | f -= *xp; /* else deduct codes from patterns */ | ||
| 226 | } | ||
| 227 | } | 222 | } |
| 228 | z = 1 << j; /* table entries for j-bit table */ | 223 | else if ((int)(work[sym]) > end) { |
| 229 | 224 | this.op = (unsigned char)(extra[work[sym]]); | |
| 230 | /* allocate new table */ | 225 | this.val = base[work[sym]]; |
| 231 | if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ | 226 | } |
| 232 | return Z_DATA_ERROR; /* overflow of MANY */ | 227 | else { |
| 233 | u[h] = q = hp + *hn; | 228 | this.op = (unsigned char)(32 + 64); /* end of block */ |
| 234 | *hn += z; | 229 | this.val = 0; |
| 235 | |||
| 236 | /* connect to last table, if there is one */ | ||
| 237 | if (h) | ||
| 238 | { | ||
| 239 | x[h] = i; /* save pattern for backing up */ | ||
| 240 | r.bits = (Byte)l; /* bits to dump before this table */ | ||
| 241 | r.exop = (Byte)j; /* bits in this table */ | ||
| 242 | j = i >> (w - l); | ||
| 243 | r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ | ||
| 244 | u[h-1][j] = r; /* connect to last table */ | ||
| 245 | } | 230 | } |
| 246 | else | ||
| 247 | *t = q; /* first table is returned result */ | ||
| 248 | } | ||
| 249 | |||
| 250 | /* set up table entry in r */ | ||
| 251 | r.bits = (Byte)(k - w); | ||
| 252 | if (p >= v + n) | ||
| 253 | r.exop = 128 + 64; /* out of values--invalid code */ | ||
| 254 | else if (*p < s) | ||
| 255 | { | ||
| 256 | r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ | ||
| 257 | r.base = *p++; /* simple code is just the value */ | ||
| 258 | } | ||
| 259 | else | ||
| 260 | { | ||
| 261 | r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ | ||
| 262 | r.base = d[*p++ - s]; | ||
| 263 | } | ||
| 264 | |||
| 265 | /* fill code-like entries with r */ | ||
| 266 | f = 1 << (k - w); | ||
| 267 | for (j = i >> w; j < z; j += f) | ||
| 268 | q[j] = r; | ||
| 269 | |||
| 270 | /* backwards increment the k-bit code i */ | ||
| 271 | for (j = 1 << (k - 1); i & j; j >>= 1) | ||
| 272 | i ^= j; | ||
| 273 | i ^= j; | ||
| 274 | |||
| 275 | /* backup over finished tables */ | ||
| 276 | mask = (1 << w) - 1; /* needed on HP, cc -O bug */ | ||
| 277 | while ((i & mask) != x[h]) | ||
| 278 | { | ||
| 279 | h--; /* don't need to update q */ | ||
| 280 | w -= l; | ||
| 281 | mask = (1 << w) - 1; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | } | ||
| 285 | 231 | ||
| 232 | /* replicate for those indices with low len bits equal to huff */ | ||
| 233 | incr = 1U << (len - drop); | ||
| 234 | fill = 1U << curr; | ||
| 235 | min = fill; /* save offset to next table */ | ||
| 236 | do { | ||
| 237 | fill -= incr; | ||
| 238 | next[(huff >> drop) + fill] = this; | ||
| 239 | } while (fill != 0); | ||
| 240 | |||
| 241 | /* backwards increment the len-bit code huff */ | ||
| 242 | incr = 1U << (len - 1); | ||
| 243 | while (huff & incr) | ||
| 244 | incr >>= 1; | ||
| 245 | if (incr != 0) { | ||
| 246 | huff &= incr - 1; | ||
| 247 | huff += incr; | ||
| 248 | } | ||
| 249 | else | ||
| 250 | huff = 0; | ||
| 286 | 251 | ||
| 287 | /* Return Z_BUF_ERROR if we were given an incomplete table */ | 252 | /* go to next symbol, update count, len */ |
| 288 | return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; | 253 | sym++; |
| 289 | } | 254 | if (--(count[len]) == 0) { |
| 255 | if (len == max) break; | ||
| 256 | len = lens[work[sym]]; | ||
| 257 | } | ||
| 290 | 258 | ||
| 259 | /* create new sub-table if needed */ | ||
| 260 | if (len > root && (huff & mask) != low) { | ||
| 261 | /* if first time, transition to sub-tables */ | ||
| 262 | if (drop == 0) | ||
| 263 | drop = root; | ||
| 264 | |||
| 265 | /* increment past last table */ | ||
| 266 | next += min; /* here min is 1 << curr */ | ||
| 267 | |||
| 268 | /* determine length of next table */ | ||
| 269 | curr = len - drop; | ||
| 270 | left = (int)(1 << curr); | ||
| 271 | while (curr + drop < max) { | ||
| 272 | left -= count[curr + drop]; | ||
| 273 | if (left <= 0) break; | ||
| 274 | curr++; | ||
| 275 | left <<= 1; | ||
| 276 | } | ||
| 291 | 277 | ||
| 292 | int zlib_inflate_trees_bits( | 278 | /* check for enough space */ |
| 293 | uInt *c, /* 19 code lengths */ | 279 | used += 1U << curr; |
| 294 | uInt *bb, /* bits tree desired/actual depth */ | 280 | if (type == LENS && used >= ENOUGH - MAXD) |
| 295 | inflate_huft **tb, /* bits tree result */ | 281 | return 1; |
| 296 | inflate_huft *hp, /* space for trees */ | ||
| 297 | z_streamp z /* for messages */ | ||
| 298 | ) | ||
| 299 | { | ||
| 300 | int r; | ||
| 301 | uInt hn = 0; /* hufts used in space */ | ||
| 302 | uInt *v; /* work area for huft_build */ | ||
| 303 | |||
| 304 | v = WS(z)->tree_work_area_1; | ||
| 305 | r = huft_build(c, 19, 19, NULL, NULL, tb, bb, hp, &hn, v); | ||
| 306 | if (r == Z_DATA_ERROR) | ||
| 307 | z->msg = (char*)"oversubscribed dynamic bit lengths tree"; | ||
| 308 | else if (r == Z_BUF_ERROR || *bb == 0) | ||
| 309 | { | ||
| 310 | z->msg = (char*)"incomplete dynamic bit lengths tree"; | ||
| 311 | r = Z_DATA_ERROR; | ||
| 312 | } | ||
| 313 | return r; | ||
| 314 | } | ||
| 315 | 282 | ||
| 316 | int zlib_inflate_trees_dynamic( | 283 | /* point entry in root table to sub-table */ |
| 317 | uInt nl, /* number of literal/length codes */ | 284 | low = huff & mask; |
| 318 | uInt nd, /* number of distance codes */ | 285 | (*table)[low].op = (unsigned char)curr; |
| 319 | uInt *c, /* that many (total) code lengths */ | 286 | (*table)[low].bits = (unsigned char)root; |
| 320 | uInt *bl, /* literal desired/actual bit depth */ | 287 | (*table)[low].val = (unsigned short)(next - *table); |
| 321 | uInt *bd, /* distance desired/actual bit depth */ | 288 | } |
| 322 | inflate_huft **tl, /* literal/length tree result */ | ||
| 323 | inflate_huft **td, /* distance tree result */ | ||
| 324 | inflate_huft *hp, /* space for trees */ | ||
| 325 | z_streamp z /* for messages */ | ||
| 326 | ) | ||
| 327 | { | ||
| 328 | int r; | ||
| 329 | uInt hn = 0; /* hufts used in space */ | ||
| 330 | uInt *v; /* work area for huft_build */ | ||
| 331 | |||
| 332 | /* allocate work area */ | ||
| 333 | v = WS(z)->tree_work_area_2; | ||
| 334 | |||
| 335 | /* build literal/length tree */ | ||
| 336 | r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); | ||
| 337 | if (r != Z_OK || *bl == 0) | ||
| 338 | { | ||
| 339 | if (r == Z_DATA_ERROR) | ||
| 340 | z->msg = (char*)"oversubscribed literal/length tree"; | ||
| 341 | else if (r != Z_MEM_ERROR) | ||
| 342 | { | ||
| 343 | z->msg = (char*)"incomplete literal/length tree"; | ||
| 344 | r = Z_DATA_ERROR; | ||
| 345 | } | ||
| 346 | return r; | ||
| 347 | } | ||
| 348 | |||
| 349 | /* build distance tree */ | ||
| 350 | r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); | ||
| 351 | if (r != Z_OK || (*bd == 0 && nl > 257)) | ||
| 352 | { | ||
| 353 | if (r == Z_DATA_ERROR) | ||
| 354 | z->msg = (char*)"oversubscribed distance tree"; | ||
| 355 | else if (r == Z_BUF_ERROR) { | ||
| 356 | #ifdef PKZIP_BUG_WORKAROUND | ||
| 357 | r = Z_OK; | ||
| 358 | } | ||
| 359 | #else | ||
| 360 | z->msg = (char*)"incomplete distance tree"; | ||
| 361 | r = Z_DATA_ERROR; | ||
| 362 | } | ||
| 363 | else if (r != Z_MEM_ERROR) | ||
| 364 | { | ||
| 365 | z->msg = (char*)"empty distance tree with lengths"; | ||
| 366 | r = Z_DATA_ERROR; | ||
| 367 | } | 289 | } |
| 368 | return r; | ||
| 369 | #endif | ||
| 370 | } | ||
| 371 | 290 | ||
| 372 | /* done */ | 291 | /* |
| 373 | return Z_OK; | 292 | Fill in rest of table for incomplete codes. This loop is similar to the |
| 374 | } | 293 | loop above in incrementing huff for table indices. It is assumed that |
| 294 | len is equal to curr + drop, so there is no loop needed to increment | ||
| 295 | through high index bits. When the current sub-table is filled, the loop | ||
| 296 | drops back to the root table to fill in any remaining entries there. | ||
| 297 | */ | ||
| 298 | this.op = (unsigned char)64; /* invalid code marker */ | ||
| 299 | this.bits = (unsigned char)(len - drop); | ||
| 300 | this.val = (unsigned short)0; | ||
| 301 | while (huff != 0) { | ||
| 302 | /* when done with sub-table, drop back to root table */ | ||
| 303 | if (drop != 0 && (huff & mask) != low) { | ||
| 304 | drop = 0; | ||
| 305 | len = root; | ||
| 306 | next = *table; | ||
| 307 | this.bits = (unsigned char)len; | ||
| 308 | } | ||
| 375 | 309 | ||
| 310 | /* put invalid code marker in table */ | ||
| 311 | next[huff >> drop] = this; | ||
| 376 | 312 | ||
| 377 | int zlib_inflate_trees_fixed( | 313 | /* backwards increment the len-bit code huff */ |
| 378 | uInt *bl, /* literal desired/actual bit depth */ | 314 | incr = 1U << (len - 1); |
| 379 | uInt *bd, /* distance desired/actual bit depth */ | 315 | while (huff & incr) |
| 380 | inflate_huft **tl, /* literal/length tree result */ | 316 | incr >>= 1; |
| 381 | inflate_huft **td, /* distance tree result */ | 317 | if (incr != 0) { |
| 382 | inflate_huft *hp, /* space for trees */ | 318 | huff &= incr - 1; |
| 383 | z_streamp z /* for memory allocation */ | 319 | huff += incr; |
| 384 | ) | 320 | } |
| 385 | { | 321 | else |
| 386 | int i; /* temporary variable */ | 322 | huff = 0; |
| 387 | unsigned l[288]; /* length list for huft_build */ | 323 | } |
| 388 | uInt *v; /* work area for huft_build */ | 324 | |
| 389 | 325 | /* set return parameters */ | |
| 390 | /* set up literal table */ | 326 | *table += used; |
| 391 | for (i = 0; i < 144; i++) | 327 | *bits = root; |
| 392 | l[i] = 8; | 328 | return 0; |
| 393 | for (; i < 256; i++) | ||
| 394 | l[i] = 9; | ||
| 395 | for (; i < 280; i++) | ||
| 396 | l[i] = 7; | ||
| 397 | for (; i < 288; i++) /* make a complete, but wrong code set */ | ||
| 398 | l[i] = 8; | ||
| 399 | *bl = 9; | ||
| 400 | v = WS(z)->tree_work_area_1; | ||
| 401 | if ((i = huft_build(l, 288, 257, cplens, cplext, tl, bl, hp, &i, v)) != 0) | ||
| 402 | return i; | ||
| 403 | |||
| 404 | /* set up distance table */ | ||
| 405 | for (i = 0; i < 30; i++) /* make an incomplete code set */ | ||
| 406 | l[i] = 5; | ||
| 407 | *bd = 5; | ||
| 408 | if ((i = huft_build(l, 30, 0, cpdist, cpdext, td, bd, hp, &i, v)) > 1) | ||
| 409 | return i; | ||
| 410 | |||
| 411 | return Z_OK; | ||
| 412 | } | 329 | } |
diff --git a/lib/zlib_inflate/inftrees.h b/lib/zlib_inflate/inftrees.h index e37705adc008..5f5219b1240e 100644 --- a/lib/zlib_inflate/inftrees.h +++ b/lib/zlib_inflate/inftrees.h | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* inftrees.h -- header to use inftrees.c | 1 | /* inftrees.h -- header to use inftrees.c |
| 2 | * Copyright (C) 1995-1998 Mark Adler | 2 | * Copyright (C) 1995-2005 Mark Adler |
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | 3 | * For conditions of distribution and use, see copyright notice in zlib.h |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | /* WARNING: this file should *not* be used by applications. It is | 6 | /* WARNING: this file should *not* be used by applications. It is |
| @@ -8,57 +8,48 @@ | |||
| 8 | subject to change. Applications should only use zlib.h. | 8 | subject to change. Applications should only use zlib.h. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | /* Huffman code lookup table entry--this entry is four bytes for machines | 11 | /* Structure for decoding tables. Each entry provides either the |
| 12 | that have 16-bit pointers (e.g. PC's in the small or medium model). */ | 12 | information needed to do the operation requested by the code that |
| 13 | 13 | indexed that table entry, or it provides a pointer to another | |
| 14 | #ifndef _INFTREES_H | 14 | table that indexes more bits of the code. op indicates whether |
| 15 | #define _INFTREES_H | 15 | the entry is a pointer to another table, a literal, a length or |
| 16 | 16 | distance, an end-of-block, or an invalid code. For a table | |
| 17 | typedef struct inflate_huft_s inflate_huft; | 17 | pointer, the low four bits of op is the number of index bits of |
| 18 | 18 | that table. For a length or distance, the low four bits of op | |
| 19 | struct inflate_huft_s { | 19 | is the number of extra bits to get after the code. bits is |
| 20 | union { | 20 | the number of bits in this code or part of the code to drop off |
| 21 | struct { | 21 | of the bit buffer. val is the actual byte to output in the case |
| 22 | Byte Exop; /* number of extra bits or operation */ | 22 | of a literal, the base length or distance, or the offset from |
| 23 | Byte Bits; /* number of bits in this code or subcode */ | 23 | the current table to the next table. Each entry is four bytes. */ |
| 24 | } what; | 24 | typedef struct { |
| 25 | uInt pad; /* pad structure to a power of 2 (4 bytes for */ | 25 | unsigned char op; /* operation, extra bits, table bits */ |
| 26 | } word; /* 16-bit, 8 bytes for 32-bit int's) */ | 26 | unsigned char bits; /* bits in this part of the code */ |
| 27 | uInt base; /* literal, length base, distance base, | 27 | unsigned short val; /* offset in table or code value */ |
| 28 | or table offset */ | 28 | } code; |
| 29 | }; | 29 | |
| 30 | /* op values as set by inflate_table(): | ||
| 31 | 00000000 - literal | ||
| 32 | 0000tttt - table link, tttt != 0 is the number of table index bits | ||
| 33 | 0001eeee - length or distance, eeee is the number of extra bits | ||
| 34 | 01100000 - end of block | ||
| 35 | 01000000 - invalid code | ||
| 36 | */ | ||
| 30 | 37 | ||
| 31 | /* Maximum size of dynamic tree. The maximum found in a long but non- | 38 | /* Maximum size of dynamic tree. The maximum found in a long but non- |
| 32 | exhaustive search was 1004 huft structures (850 for length/literals | 39 | exhaustive search was 1444 code structures (852 for length/literals |
| 33 | and 154 for distances, the latter actually the result of an | 40 | and 592 for distances, the latter actually the result of an |
| 34 | exhaustive search). The actual maximum is not known, but the | 41 | exhaustive search). The true maximum is not known, but the value |
| 35 | value below is more than safe. */ | 42 | below is more than safe. */ |
| 36 | #define MANY 1440 | 43 | #define ENOUGH 2048 |
| 37 | 44 | #define MAXD 592 | |
| 38 | extern int zlib_inflate_trees_bits ( | 45 | |
| 39 | uInt *, /* 19 code lengths */ | 46 | /* Type of code to build for inftable() */ |
| 40 | uInt *, /* bits tree desired/actual depth */ | 47 | typedef enum { |
| 41 | inflate_huft **, /* bits tree result */ | 48 | CODES, |
| 42 | inflate_huft *, /* space for trees */ | 49 | LENS, |
| 43 | z_streamp); /* for messages */ | 50 | DISTS |
| 44 | 51 | } codetype; | |
| 45 | extern int zlib_inflate_trees_dynamic ( | 52 | |
| 46 | uInt, /* number of literal/length codes */ | 53 | extern int zlib_inflate_table (codetype type, unsigned short *lens, |
| 47 | uInt, /* number of distance codes */ | 54 | unsigned codes, code **table, |
| 48 | uInt *, /* that many (total) code lengths */ | 55 | unsigned *bits, unsigned short *work); |
| 49 | uInt *, /* literal desired/actual bit depth */ | ||
| 50 | uInt *, /* distance desired/actual bit depth */ | ||
| 51 | inflate_huft **, /* literal/length tree result */ | ||
| 52 | inflate_huft **, /* distance tree result */ | ||
| 53 | inflate_huft *, /* space for trees */ | ||
| 54 | z_streamp); /* for messages */ | ||
| 55 | |||
| 56 | extern int zlib_inflate_trees_fixed ( | ||
| 57 | uInt *, /* literal desired/actual bit depth */ | ||
| 58 | uInt *, /* distance desired/actual bit depth */ | ||
| 59 | inflate_huft **, /* literal/length tree result */ | ||
| 60 | inflate_huft **, /* distance tree result */ | ||
| 61 | inflate_huft *, /* space for trees */ | ||
| 62 | z_streamp); /* for memory allocation */ | ||
| 63 | |||
| 64 | #endif /* _INFTREES_H */ | ||
diff --git a/lib/zlib_inflate/infutil.c b/lib/zlib_inflate/infutil.c deleted file mode 100644 index 00202b3438e1..000000000000 --- a/lib/zlib_inflate/infutil.c +++ /dev/null | |||
| @@ -1,88 +0,0 @@ | |||
| 1 | /* inflate_util.c -- data and routines common to blocks and codes | ||
| 2 | * Copyright (C) 1995-1998 Mark Adler | ||
| 3 | * For conditions of distribution and use, see copyright notice in zlib.h | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/zutil.h> | ||
| 7 | #include "infblock.h" | ||
| 8 | #include "inftrees.h" | ||
| 9 | #include "infcodes.h" | ||
| 10 | #include "infutil.h" | ||
| 11 | |||
| 12 | struct inflate_codes_state; | ||
| 13 | |||
| 14 | /* And'ing with mask[n] masks the lower n bits */ | ||
| 15 | uInt zlib_inflate_mask[17] = { | ||
| 16 | 0x0000, | ||
| 17 | 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, | ||
| 18 | 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff | ||
| 19 | }; | ||
| 20 | |||
| 21 | |||
| 22 | /* copy as much as possible from the sliding window to the output area */ | ||
| 23 | int zlib_inflate_flush( | ||
| 24 | inflate_blocks_statef *s, | ||
| 25 | z_streamp z, | ||
| 26 | int r | ||
| 27 | ) | ||
| 28 | { | ||
| 29 | uInt n; | ||
| 30 | Byte *p; | ||
| 31 | Byte *q; | ||
| 32 | |||
| 33 | /* local copies of source and destination pointers */ | ||
| 34 | p = z->next_out; | ||
| 35 | q = s->read; | ||
| 36 | |||
| 37 | /* compute number of bytes to copy as far as end of window */ | ||
| 38 | n = (uInt)((q <= s->write ? s->write : s->end) - q); | ||
| 39 | if (n > z->avail_out) n = z->avail_out; | ||
| 40 | if (n && r == Z_BUF_ERROR) r = Z_OK; | ||
| 41 | |||
| 42 | /* update counters */ | ||
| 43 | z->avail_out -= n; | ||
| 44 | z->total_out += n; | ||
| 45 | |||
| 46 | /* update check information */ | ||
| 47 | if (s->checkfn != NULL) | ||
| 48 | z->adler = s->check = (*s->checkfn)(s->check, q, n); | ||
| 49 | |||
| 50 | /* copy as far as end of window */ | ||
| 51 | memcpy(p, q, n); | ||
| 52 | p += n; | ||
| 53 | q += n; | ||
| 54 | |||
| 55 | /* see if more to copy at beginning of window */ | ||
| 56 | if (q == s->end) | ||
| 57 | { | ||
| 58 | /* wrap pointers */ | ||
| 59 | q = s->window; | ||
| 60 | if (s->write == s->end) | ||
| 61 | s->write = s->window; | ||
| 62 | |||
| 63 | /* compute bytes to copy */ | ||
| 64 | n = (uInt)(s->write - q); | ||
| 65 | if (n > z->avail_out) n = z->avail_out; | ||
| 66 | if (n && r == Z_BUF_ERROR) r = Z_OK; | ||
| 67 | |||
| 68 | /* update counters */ | ||
| 69 | z->avail_out -= n; | ||
| 70 | z->total_out += n; | ||
| 71 | |||
| 72 | /* update check information */ | ||
| 73 | if (s->checkfn != NULL) | ||
| 74 | z->adler = s->check = (*s->checkfn)(s->check, q, n); | ||
| 75 | |||
| 76 | /* copy */ | ||
| 77 | memcpy(p, q, n); | ||
| 78 | p += n; | ||
| 79 | q += n; | ||
| 80 | } | ||
| 81 | |||
| 82 | /* update pointers */ | ||
| 83 | z->next_out = p; | ||
| 84 | s->read = q; | ||
| 85 | |||
| 86 | /* done */ | ||
| 87 | return r; | ||
| 88 | } | ||
diff --git a/lib/zlib_inflate/infutil.h b/lib/zlib_inflate/infutil.h index a15875fc5f72..eb1a9007bd86 100644 --- a/lib/zlib_inflate/infutil.h +++ b/lib/zlib_inflate/infutil.h | |||
| @@ -11,184 +11,12 @@ | |||
| 11 | #ifndef _INFUTIL_H | 11 | #ifndef _INFUTIL_H |
| 12 | #define _INFUTIL_H | 12 | #define _INFUTIL_H |
| 13 | 13 | ||
| 14 | #include <linux/zconf.h> | 14 | #include <linux/zlib.h> |
| 15 | #include "inftrees.h" | ||
| 16 | #include "infcodes.h" | ||
| 17 | |||
| 18 | typedef enum { | ||
| 19 | TYPE, /* get type bits (3, including end bit) */ | ||
| 20 | LENS, /* get lengths for stored */ | ||
| 21 | STORED, /* processing stored block */ | ||
| 22 | TABLE, /* get table lengths */ | ||
| 23 | BTREE, /* get bit lengths tree for a dynamic block */ | ||
| 24 | DTREE, /* get length, distance trees for a dynamic block */ | ||
| 25 | CODES, /* processing fixed or dynamic block */ | ||
| 26 | DRY, /* output remaining window bytes */ | ||
| 27 | B_DONE, /* finished last block, done */ | ||
| 28 | B_BAD} /* got a data error--stuck here */ | ||
| 29 | inflate_block_mode; | ||
| 30 | |||
| 31 | /* inflate blocks semi-private state */ | ||
| 32 | struct inflate_blocks_state { | ||
| 33 | |||
| 34 | /* mode */ | ||
| 35 | inflate_block_mode mode; /* current inflate_block mode */ | ||
| 36 | |||
| 37 | /* mode dependent information */ | ||
| 38 | union { | ||
| 39 | uInt left; /* if STORED, bytes left to copy */ | ||
| 40 | struct { | ||
| 41 | uInt table; /* table lengths (14 bits) */ | ||
| 42 | uInt index; /* index into blens (or border) */ | ||
| 43 | uInt *blens; /* bit lengths of codes */ | ||
| 44 | uInt bb; /* bit length tree depth */ | ||
| 45 | inflate_huft *tb; /* bit length decoding tree */ | ||
| 46 | } trees; /* if DTREE, decoding info for trees */ | ||
| 47 | struct { | ||
| 48 | inflate_codes_statef | ||
| 49 | *codes; | ||
| 50 | } decode; /* if CODES, current state */ | ||
| 51 | } sub; /* submode */ | ||
| 52 | uInt last; /* true if this block is the last block */ | ||
| 53 | |||
| 54 | /* mode independent information */ | ||
| 55 | uInt bitk; /* bits in bit buffer */ | ||
| 56 | uLong bitb; /* bit buffer */ | ||
| 57 | inflate_huft *hufts; /* single malloc for tree space */ | ||
| 58 | Byte *window; /* sliding window */ | ||
| 59 | Byte *end; /* one byte after sliding window */ | ||
| 60 | Byte *read; /* window read pointer */ | ||
| 61 | Byte *write; /* window write pointer */ | ||
| 62 | check_func checkfn; /* check function */ | ||
| 63 | uLong check; /* check on output */ | ||
| 64 | |||
| 65 | }; | ||
| 66 | |||
| 67 | |||
| 68 | /* defines for inflate input/output */ | ||
| 69 | /* update pointers and return */ | ||
| 70 | #define UPDBITS {s->bitb=b;s->bitk=k;} | ||
| 71 | #define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} | ||
| 72 | #define UPDOUT {s->write=q;} | ||
| 73 | #define UPDATE {UPDBITS UPDIN UPDOUT} | ||
| 74 | #define LEAVE {UPDATE return zlib_inflate_flush(s,z,r);} | ||
| 75 | /* get bytes and bits */ | ||
| 76 | #define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} | ||
| 77 | #define NEEDBYTE {if(n)r=Z_OK;else LEAVE} | ||
| 78 | #define NEXTBYTE (n--,*p++) | ||
| 79 | #define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}} | ||
| 80 | #define DUMPBITS(j) {b>>=(j);k-=(j);} | ||
| 81 | /* output bytes */ | ||
| 82 | #define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q) | ||
| 83 | #define LOADOUT {q=s->write;m=(uInt)WAVAIL;} | ||
| 84 | #define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} | ||
| 85 | #define FLUSH {UPDOUT r=zlib_inflate_flush(s,z,r); LOADOUT} | ||
| 86 | #define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} | ||
| 87 | #define OUTBYTE(a) {*q++=(Byte)(a);m--;} | ||
| 88 | /* load local pointers */ | ||
| 89 | #define LOAD {LOADIN LOADOUT} | ||
| 90 | |||
| 91 | /* masks for lower bits (size given to avoid silly warnings with Visual C++) */ | ||
| 92 | extern uInt zlib_inflate_mask[17]; | ||
| 93 | |||
| 94 | /* copy as much as possible from the sliding window to the output area */ | ||
| 95 | extern int zlib_inflate_flush ( | ||
| 96 | inflate_blocks_statef *, | ||
| 97 | z_streamp , | ||
| 98 | int); | ||
| 99 | |||
| 100 | /* inflate private state */ | ||
| 101 | typedef enum { | ||
| 102 | METHOD, /* waiting for method byte */ | ||
| 103 | FLAG, /* waiting for flag byte */ | ||
| 104 | DICT4, /* four dictionary check bytes to go */ | ||
| 105 | DICT3, /* three dictionary check bytes to go */ | ||
| 106 | DICT2, /* two dictionary check bytes to go */ | ||
| 107 | DICT1, /* one dictionary check byte to go */ | ||
| 108 | DICT0, /* waiting for inflateSetDictionary */ | ||
| 109 | BLOCKS, /* decompressing blocks */ | ||
| 110 | CHECK4, /* four check bytes to go */ | ||
| 111 | CHECK3, /* three check bytes to go */ | ||
| 112 | CHECK2, /* two check bytes to go */ | ||
| 113 | CHECK1, /* one check byte to go */ | ||
| 114 | I_DONE, /* finished check, done */ | ||
| 115 | I_BAD} /* got an error--stay here */ | ||
| 116 | inflate_mode; | ||
| 117 | |||
| 118 | struct internal_state { | ||
| 119 | |||
| 120 | /* mode */ | ||
| 121 | inflate_mode mode; /* current inflate mode */ | ||
| 122 | |||
| 123 | /* mode dependent information */ | ||
| 124 | union { | ||
| 125 | uInt method; /* if FLAGS, method byte */ | ||
| 126 | struct { | ||
| 127 | uLong was; /* computed check value */ | ||
| 128 | uLong need; /* stream check value */ | ||
| 129 | } check; /* if CHECK, check values to compare */ | ||
| 130 | uInt marker; /* if BAD, inflateSync's marker bytes count */ | ||
| 131 | } sub; /* submode */ | ||
| 132 | |||
| 133 | /* mode independent information */ | ||
| 134 | int nowrap; /* flag for no wrapper */ | ||
| 135 | uInt wbits; /* log2(window size) (8..15, defaults to 15) */ | ||
| 136 | inflate_blocks_statef | ||
| 137 | *blocks; /* current inflate_blocks state */ | ||
| 138 | |||
| 139 | }; | ||
| 140 | |||
| 141 | /* inflate codes private state */ | ||
| 142 | typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ | ||
| 143 | START, /* x: set up for LEN */ | ||
| 144 | LEN, /* i: get length/literal/eob next */ | ||
| 145 | LENEXT, /* i: getting length extra (have base) */ | ||
| 146 | DIST, /* i: get distance next */ | ||
| 147 | DISTEXT, /* i: getting distance extra */ | ||
| 148 | COPY, /* o: copying bytes in window, waiting for space */ | ||
| 149 | LIT, /* o: got literal, waiting for output space */ | ||
| 150 | WASH, /* o: got eob, possibly still output waiting */ | ||
| 151 | END, /* x: got eob and all data flushed */ | ||
| 152 | BADCODE} /* x: got error */ | ||
| 153 | inflate_codes_mode; | ||
| 154 | |||
| 155 | struct inflate_codes_state { | ||
| 156 | |||
| 157 | /* mode */ | ||
| 158 | inflate_codes_mode mode; /* current inflate_codes mode */ | ||
| 159 | |||
| 160 | /* mode dependent information */ | ||
| 161 | uInt len; | ||
| 162 | union { | ||
| 163 | struct { | ||
| 164 | inflate_huft *tree; /* pointer into tree */ | ||
| 165 | uInt need; /* bits needed */ | ||
| 166 | } code; /* if LEN or DIST, where in tree */ | ||
| 167 | uInt lit; /* if LIT, literal */ | ||
| 168 | struct { | ||
| 169 | uInt get; /* bits to get for extra */ | ||
| 170 | uInt dist; /* distance back to copy from */ | ||
| 171 | } copy; /* if EXT or COPY, where and how much */ | ||
| 172 | } sub; /* submode */ | ||
| 173 | |||
| 174 | /* mode independent information */ | ||
| 175 | Byte lbits; /* ltree bits decoded per branch */ | ||
| 176 | Byte dbits; /* dtree bits decoder per branch */ | ||
| 177 | inflate_huft *ltree; /* literal/length/eob tree */ | ||
| 178 | inflate_huft *dtree; /* distance tree */ | ||
| 179 | |||
| 180 | }; | ||
| 181 | 15 | ||
| 182 | /* memory allocation for inflation */ | 16 | /* memory allocation for inflation */ |
| 183 | 17 | ||
| 184 | struct inflate_workspace { | 18 | struct inflate_workspace { |
| 185 | inflate_codes_statef working_state; | 19 | struct inflate_state inflate_state; |
| 186 | struct inflate_blocks_state working_blocks_state; | ||
| 187 | struct internal_state internal_state; | ||
| 188 | unsigned int tree_work_area_1[19]; | ||
| 189 | unsigned int tree_work_area_2[288]; | ||
| 190 | unsigned working_blens[258 + 0x1f + 0x1f]; | ||
| 191 | inflate_huft working_hufts[MANY]; | ||
| 192 | unsigned char working_window[1 << MAX_WBITS]; | 20 | unsigned char working_window[1 << MAX_WBITS]; |
| 193 | }; | 21 | }; |
| 194 | 22 | ||
diff --git a/security/dummy.c b/security/dummy.c index 64f6da0f422e..6de4a4a5eb13 100644 --- a/security/dummy.c +++ b/security/dummy.c | |||
| @@ -860,7 +860,7 @@ static int dummy_setprocattr(struct task_struct *p, char *name, void *value, siz | |||
| 860 | } | 860 | } |
| 861 | 861 | ||
| 862 | #ifdef CONFIG_KEYS | 862 | #ifdef CONFIG_KEYS |
| 863 | static inline int dummy_key_alloc(struct key *key) | 863 | static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx) |
| 864 | { | 864 | { |
| 865 | return 0; | 865 | return 0; |
| 866 | } | 866 | } |
diff --git a/security/keys/key.c b/security/keys/key.c index 3fdc49c6a02c..51f851557389 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -247,8 +247,8 @@ static inline void key_alloc_serial(struct key *key) | |||
| 247 | * instantiate the key or discard it before returning | 247 | * instantiate the key or discard it before returning |
| 248 | */ | 248 | */ |
| 249 | struct key *key_alloc(struct key_type *type, const char *desc, | 249 | struct key *key_alloc(struct key_type *type, const char *desc, |
| 250 | uid_t uid, gid_t gid, key_perm_t perm, | 250 | uid_t uid, gid_t gid, struct task_struct *ctx, |
| 251 | int not_in_quota) | 251 | key_perm_t perm, int not_in_quota) |
| 252 | { | 252 | { |
| 253 | struct key_user *user = NULL; | 253 | struct key_user *user = NULL; |
| 254 | struct key *key; | 254 | struct key *key; |
| @@ -318,7 +318,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, | |||
| 318 | #endif | 318 | #endif |
| 319 | 319 | ||
| 320 | /* let the security module know about the key */ | 320 | /* let the security module know about the key */ |
| 321 | ret = security_key_alloc(key); | 321 | ret = security_key_alloc(key, ctx); |
| 322 | if (ret < 0) | 322 | if (ret < 0) |
| 323 | goto security_error; | 323 | goto security_error; |
| 324 | 324 | ||
| @@ -822,7 +822,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 822 | 822 | ||
| 823 | /* allocate a new key */ | 823 | /* allocate a new key */ |
| 824 | key = key_alloc(ktype, description, current->fsuid, current->fsgid, | 824 | key = key_alloc(ktype, description, current->fsuid, current->fsgid, |
| 825 | perm, not_in_quota); | 825 | current, perm, not_in_quota); |
| 826 | if (IS_ERR(key)) { | 826 | if (IS_ERR(key)) { |
| 827 | key_ref = ERR_PTR(PTR_ERR(key)); | 827 | key_ref = ERR_PTR(PTR_ERR(key)); |
| 828 | goto error_3; | 828 | goto error_3; |
| @@ -907,6 +907,10 @@ void key_revoke(struct key *key) | |||
| 907 | * it */ | 907 | * it */ |
| 908 | down_write(&key->sem); | 908 | down_write(&key->sem); |
| 909 | set_bit(KEY_FLAG_REVOKED, &key->flags); | 909 | set_bit(KEY_FLAG_REVOKED, &key->flags); |
| 910 | |||
| 911 | if (key->type->revoke) | ||
| 912 | key->type->revoke(key); | ||
| 913 | |||
| 910 | up_write(&key->sem); | 914 | up_write(&key->sem); |
| 911 | 915 | ||
| 912 | } /* end key_revoke() */ | 916 | } /* end key_revoke() */ |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index bffa924c1f88..1357207fc9df 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -240,13 +240,14 @@ static long keyring_read(const struct key *keyring, | |||
| 240 | * allocate a keyring and link into the destination keyring | 240 | * allocate a keyring and link into the destination keyring |
| 241 | */ | 241 | */ |
| 242 | struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, | 242 | struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, |
| 243 | int not_in_quota, struct key *dest) | 243 | struct task_struct *ctx, int not_in_quota, |
| 244 | struct key *dest) | ||
| 244 | { | 245 | { |
| 245 | struct key *keyring; | 246 | struct key *keyring; |
| 246 | int ret; | 247 | int ret; |
| 247 | 248 | ||
| 248 | keyring = key_alloc(&key_type_keyring, description, | 249 | keyring = key_alloc(&key_type_keyring, description, |
| 249 | uid, gid, | 250 | uid, gid, ctx, |
| 250 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | 251 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, |
| 251 | not_in_quota); | 252 | not_in_quota); |
| 252 | 253 | ||
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 217a0bef3c82..4d9825f9962c 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -67,7 +67,8 @@ struct key root_session_keyring = { | |||
| 67 | /* | 67 | /* |
| 68 | * allocate the keyrings to be associated with a UID | 68 | * allocate the keyrings to be associated with a UID |
| 69 | */ | 69 | */ |
| 70 | int alloc_uid_keyring(struct user_struct *user) | 70 | int alloc_uid_keyring(struct user_struct *user, |
| 71 | struct task_struct *ctx) | ||
| 71 | { | 72 | { |
| 72 | struct key *uid_keyring, *session_keyring; | 73 | struct key *uid_keyring, *session_keyring; |
| 73 | char buf[20]; | 74 | char buf[20]; |
| @@ -76,7 +77,7 @@ int alloc_uid_keyring(struct user_struct *user) | |||
| 76 | /* concoct a default session keyring */ | 77 | /* concoct a default session keyring */ |
| 77 | sprintf(buf, "_uid_ses.%u", user->uid); | 78 | sprintf(buf, "_uid_ses.%u", user->uid); |
| 78 | 79 | ||
| 79 | session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL); | 80 | session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, NULL); |
| 80 | if (IS_ERR(session_keyring)) { | 81 | if (IS_ERR(session_keyring)) { |
| 81 | ret = PTR_ERR(session_keyring); | 82 | ret = PTR_ERR(session_keyring); |
| 82 | goto error; | 83 | goto error; |
| @@ -86,7 +87,7 @@ int alloc_uid_keyring(struct user_struct *user) | |||
| 86 | * keyring */ | 87 | * keyring */ |
| 87 | sprintf(buf, "_uid.%u", user->uid); | 88 | sprintf(buf, "_uid.%u", user->uid); |
| 88 | 89 | ||
| 89 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, | 90 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, |
| 90 | session_keyring); | 91 | session_keyring); |
| 91 | if (IS_ERR(uid_keyring)) { | 92 | if (IS_ERR(uid_keyring)) { |
| 92 | key_put(session_keyring); | 93 | key_put(session_keyring); |
| @@ -143,7 +144,7 @@ int install_thread_keyring(struct task_struct *tsk) | |||
| 143 | 144 | ||
| 144 | sprintf(buf, "_tid.%u", tsk->pid); | 145 | sprintf(buf, "_tid.%u", tsk->pid); |
| 145 | 146 | ||
| 146 | keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); | 147 | keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL); |
| 147 | if (IS_ERR(keyring)) { | 148 | if (IS_ERR(keyring)) { |
| 148 | ret = PTR_ERR(keyring); | 149 | ret = PTR_ERR(keyring); |
| 149 | goto error; | 150 | goto error; |
| @@ -177,7 +178,7 @@ int install_process_keyring(struct task_struct *tsk) | |||
| 177 | if (!tsk->signal->process_keyring) { | 178 | if (!tsk->signal->process_keyring) { |
| 178 | sprintf(buf, "_pid.%u", tsk->tgid); | 179 | sprintf(buf, "_pid.%u", tsk->tgid); |
| 179 | 180 | ||
| 180 | keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); | 181 | keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL); |
| 181 | if (IS_ERR(keyring)) { | 182 | if (IS_ERR(keyring)) { |
| 182 | ret = PTR_ERR(keyring); | 183 | ret = PTR_ERR(keyring); |
| 183 | goto error; | 184 | goto error; |
| @@ -217,7 +218,7 @@ static int install_session_keyring(struct task_struct *tsk, | |||
| 217 | if (!keyring) { | 218 | if (!keyring) { |
| 218 | sprintf(buf, "_ses.%u", tsk->tgid); | 219 | sprintf(buf, "_ses.%u", tsk->tgid); |
| 219 | 220 | ||
| 220 | keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); | 221 | keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL); |
| 221 | if (IS_ERR(keyring)) | 222 | if (IS_ERR(keyring)) |
| 222 | return PTR_ERR(keyring); | 223 | return PTR_ERR(keyring); |
| 223 | } | 224 | } |
| @@ -390,6 +391,8 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
| 390 | struct request_key_auth *rka; | 391 | struct request_key_auth *rka; |
| 391 | key_ref_t key_ref, ret, err; | 392 | key_ref_t key_ref, ret, err; |
| 392 | 393 | ||
| 394 | might_sleep(); | ||
| 395 | |||
| 393 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 396 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
| 394 | * searchable, but we failed to find a key or we found a negative key; | 397 | * searchable, but we failed to find a key or we found a negative key; |
| 395 | * otherwise we want to return a sample error (probably -EACCES) if | 398 | * otherwise we want to return a sample error (probably -EACCES) if |
| @@ -495,27 +498,35 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
| 495 | */ | 498 | */ |
| 496 | if (context->request_key_auth && | 499 | if (context->request_key_auth && |
| 497 | context == current && | 500 | context == current && |
| 498 | type != &key_type_request_key_auth && | 501 | type != &key_type_request_key_auth |
| 499 | key_validate(context->request_key_auth) == 0 | ||
| 500 | ) { | 502 | ) { |
| 501 | rka = context->request_key_auth->payload.data; | 503 | /* defend against the auth key being revoked */ |
| 504 | down_read(&context->request_key_auth->sem); | ||
| 502 | 505 | ||
| 503 | key_ref = search_process_keyrings(type, description, match, | 506 | if (key_validate(context->request_key_auth) == 0) { |
| 504 | rka->context); | 507 | rka = context->request_key_auth->payload.data; |
| 505 | 508 | ||
| 506 | if (!IS_ERR(key_ref)) | 509 | key_ref = search_process_keyrings(type, description, |
| 507 | goto found; | 510 | match, rka->context); |
| 508 | 511 | ||
| 509 | switch (PTR_ERR(key_ref)) { | 512 | up_read(&context->request_key_auth->sem); |
| 510 | case -EAGAIN: /* no key */ | 513 | |
| 511 | if (ret) | 514 | if (!IS_ERR(key_ref)) |
| 515 | goto found; | ||
| 516 | |||
| 517 | switch (PTR_ERR(key_ref)) { | ||
| 518 | case -EAGAIN: /* no key */ | ||
| 519 | if (ret) | ||
| 520 | break; | ||
| 521 | case -ENOKEY: /* negative key */ | ||
| 522 | ret = key_ref; | ||
| 512 | break; | 523 | break; |
| 513 | case -ENOKEY: /* negative key */ | 524 | default: |
| 514 | ret = key_ref; | 525 | err = key_ref; |
| 515 | break; | 526 | break; |
| 516 | default: | 527 | } |
| 517 | err = key_ref; | 528 | } else { |
| 518 | break; | 529 | up_read(&context->request_key_auth->sem); |
| 519 | } | 530 | } |
| 520 | } | 531 | } |
| 521 | 532 | ||
| @@ -717,7 +728,7 @@ long join_session_keyring(const char *name) | |||
| 717 | keyring = find_keyring_by_name(name, 0); | 728 | keyring = find_keyring_by_name(name, 0); |
| 718 | if (PTR_ERR(keyring) == -ENOKEY) { | 729 | if (PTR_ERR(keyring) == -ENOKEY) { |
| 719 | /* not found - try and create a new one */ | 730 | /* not found - try and create a new one */ |
| 720 | keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL); | 731 | keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, 0, NULL); |
| 721 | if (IS_ERR(keyring)) { | 732 | if (IS_ERR(keyring)) { |
| 722 | ret = PTR_ERR(keyring); | 733 | ret = PTR_ERR(keyring); |
| 723 | goto error2; | 734 | goto error2; |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index f030a0ccbb93..eab66a06ca53 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
| @@ -48,7 +48,8 @@ static int call_sbin_request_key(struct key *key, | |||
| 48 | /* allocate a new session keyring */ | 48 | /* allocate a new session keyring */ |
| 49 | sprintf(desc, "_req.%u", key->serial); | 49 | sprintf(desc, "_req.%u", key->serial); |
| 50 | 50 | ||
| 51 | keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL); | 51 | keyring = keyring_alloc(desc, current->fsuid, current->fsgid, |
| 52 | current, 1, NULL); | ||
| 52 | if (IS_ERR(keyring)) { | 53 | if (IS_ERR(keyring)) { |
| 53 | ret = PTR_ERR(keyring); | 54 | ret = PTR_ERR(keyring); |
| 54 | goto error_alloc; | 55 | goto error_alloc; |
| @@ -137,7 +138,8 @@ static struct key *__request_key_construction(struct key_type *type, | |||
| 137 | 138 | ||
| 138 | /* create a key and add it to the queue */ | 139 | /* create a key and add it to the queue */ |
| 139 | key = key_alloc(type, description, | 140 | key = key_alloc(type, description, |
| 140 | current->fsuid, current->fsgid, KEY_POS_ALL, 0); | 141 | current->fsuid, current->fsgid, |
| 142 | current, KEY_POS_ALL, 0); | ||
| 141 | if (IS_ERR(key)) | 143 | if (IS_ERR(key)) |
| 142 | goto alloc_failed; | 144 | goto alloc_failed; |
| 143 | 145 | ||
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index cce6ba6b0323..cb9817ced3fd 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | static int request_key_auth_instantiate(struct key *, const void *, size_t); | 21 | static int request_key_auth_instantiate(struct key *, const void *, size_t); |
| 22 | static void request_key_auth_describe(const struct key *, struct seq_file *); | 22 | static void request_key_auth_describe(const struct key *, struct seq_file *); |
| 23 | static void request_key_auth_revoke(struct key *); | ||
| 23 | static void request_key_auth_destroy(struct key *); | 24 | static void request_key_auth_destroy(struct key *); |
| 24 | static long request_key_auth_read(const struct key *, char __user *, size_t); | 25 | static long request_key_auth_read(const struct key *, char __user *, size_t); |
| 25 | 26 | ||
| @@ -31,6 +32,7 @@ struct key_type key_type_request_key_auth = { | |||
| 31 | .def_datalen = sizeof(struct request_key_auth), | 32 | .def_datalen = sizeof(struct request_key_auth), |
| 32 | .instantiate = request_key_auth_instantiate, | 33 | .instantiate = request_key_auth_instantiate, |
| 33 | .describe = request_key_auth_describe, | 34 | .describe = request_key_auth_describe, |
| 35 | .revoke = request_key_auth_revoke, | ||
| 34 | .destroy = request_key_auth_destroy, | 36 | .destroy = request_key_auth_destroy, |
| 35 | .read = request_key_auth_read, | 37 | .read = request_key_auth_read, |
| 36 | }; | 38 | }; |
| @@ -93,6 +95,24 @@ static long request_key_auth_read(const struct key *key, | |||
| 93 | 95 | ||
| 94 | /*****************************************************************************/ | 96 | /*****************************************************************************/ |
| 95 | /* | 97 | /* |
| 98 | * handle revocation of an authorisation token key | ||
| 99 | * - called with the key sem write-locked | ||
| 100 | */ | ||
| 101 | static void request_key_auth_revoke(struct key *key) | ||
| 102 | { | ||
| 103 | struct request_key_auth *rka = key->payload.data; | ||
| 104 | |||
| 105 | kenter("{%d}", key->serial); | ||
| 106 | |||
| 107 | if (rka->context) { | ||
| 108 | put_task_struct(rka->context); | ||
| 109 | rka->context = NULL; | ||
| 110 | } | ||
| 111 | |||
| 112 | } /* end request_key_auth_revoke() */ | ||
| 113 | |||
| 114 | /*****************************************************************************/ | ||
| 115 | /* | ||
| 96 | * destroy an instantiation authorisation token key | 116 | * destroy an instantiation authorisation token key |
| 97 | */ | 117 | */ |
| 98 | static void request_key_auth_destroy(struct key *key) | 118 | static void request_key_auth_destroy(struct key *key) |
| @@ -101,6 +121,11 @@ static void request_key_auth_destroy(struct key *key) | |||
| 101 | 121 | ||
| 102 | kenter("{%d}", key->serial); | 122 | kenter("{%d}", key->serial); |
| 103 | 123 | ||
| 124 | if (rka->context) { | ||
| 125 | put_task_struct(rka->context); | ||
| 126 | rka->context = NULL; | ||
| 127 | } | ||
| 128 | |||
| 104 | key_put(rka->target_key); | 129 | key_put(rka->target_key); |
| 105 | kfree(rka); | 130 | kfree(rka); |
| 106 | 131 | ||
| @@ -131,14 +156,26 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) | |||
| 131 | * another process */ | 156 | * another process */ |
| 132 | if (current->request_key_auth) { | 157 | if (current->request_key_auth) { |
| 133 | /* it is - use that instantiation context here too */ | 158 | /* it is - use that instantiation context here too */ |
| 159 | down_read(¤t->request_key_auth->sem); | ||
| 160 | |||
| 161 | /* if the auth key has been revoked, then the key we're | ||
| 162 | * servicing is already instantiated */ | ||
| 163 | if (test_bit(KEY_FLAG_REVOKED, | ||
| 164 | ¤t->request_key_auth->flags)) | ||
| 165 | goto auth_key_revoked; | ||
| 166 | |||
| 134 | irka = current->request_key_auth->payload.data; | 167 | irka = current->request_key_auth->payload.data; |
| 135 | rka->context = irka->context; | 168 | rka->context = irka->context; |
| 136 | rka->pid = irka->pid; | 169 | rka->pid = irka->pid; |
| 170 | get_task_struct(rka->context); | ||
| 171 | |||
| 172 | up_read(¤t->request_key_auth->sem); | ||
| 137 | } | 173 | } |
| 138 | else { | 174 | else { |
| 139 | /* it isn't - use this process as the context */ | 175 | /* it isn't - use this process as the context */ |
| 140 | rka->context = current; | 176 | rka->context = current; |
| 141 | rka->pid = current->pid; | 177 | rka->pid = current->pid; |
| 178 | get_task_struct(rka->context); | ||
| 142 | } | 179 | } |
| 143 | 180 | ||
| 144 | rka->target_key = key_get(target); | 181 | rka->target_key = key_get(target); |
| @@ -148,7 +185,7 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) | |||
| 148 | sprintf(desc, "%x", target->serial); | 185 | sprintf(desc, "%x", target->serial); |
| 149 | 186 | ||
| 150 | authkey = key_alloc(&key_type_request_key_auth, desc, | 187 | authkey = key_alloc(&key_type_request_key_auth, desc, |
| 151 | current->fsuid, current->fsgid, | 188 | current->fsuid, current->fsgid, current, |
| 152 | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | | 189 | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | |
| 153 | KEY_USR_VIEW, 1); | 190 | KEY_USR_VIEW, 1); |
| 154 | if (IS_ERR(authkey)) { | 191 | if (IS_ERR(authkey)) { |
| @@ -161,9 +198,15 @@ struct key *request_key_auth_new(struct key *target, const char *callout_info) | |||
| 161 | if (ret < 0) | 198 | if (ret < 0) |
| 162 | goto error_inst; | 199 | goto error_inst; |
| 163 | 200 | ||
| 164 | kleave(" = {%d})", authkey->serial); | 201 | kleave(" = {%d}", authkey->serial); |
| 165 | return authkey; | 202 | return authkey; |
| 166 | 203 | ||
| 204 | auth_key_revoked: | ||
| 205 | up_read(¤t->request_key_auth->sem); | ||
| 206 | kfree(rka); | ||
| 207 | kleave("= -EKEYREVOKED"); | ||
| 208 | return ERR_PTR(-EKEYREVOKED); | ||
| 209 | |||
| 167 | error_inst: | 210 | error_inst: |
| 168 | key_revoke(authkey); | 211 | key_revoke(authkey); |
| 169 | key_put(authkey); | 212 | key_put(authkey); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 54adc9d31e92..524915dfda64 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -4252,6 +4252,57 @@ static int selinux_setprocattr(struct task_struct *p, | |||
| 4252 | return size; | 4252 | return size; |
| 4253 | } | 4253 | } |
| 4254 | 4254 | ||
| 4255 | #ifdef CONFIG_KEYS | ||
| 4256 | |||
| 4257 | static int selinux_key_alloc(struct key *k, struct task_struct *tsk) | ||
| 4258 | { | ||
| 4259 | struct task_security_struct *tsec = tsk->security; | ||
| 4260 | struct key_security_struct *ksec; | ||
| 4261 | |||
| 4262 | ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL); | ||
| 4263 | if (!ksec) | ||
| 4264 | return -ENOMEM; | ||
| 4265 | |||
| 4266 | ksec->obj = k; | ||
| 4267 | ksec->sid = tsec->sid; | ||
| 4268 | k->security = ksec; | ||
| 4269 | |||
| 4270 | return 0; | ||
| 4271 | } | ||
| 4272 | |||
| 4273 | static void selinux_key_free(struct key *k) | ||
| 4274 | { | ||
| 4275 | struct key_security_struct *ksec = k->security; | ||
| 4276 | |||
| 4277 | k->security = NULL; | ||
| 4278 | kfree(ksec); | ||
| 4279 | } | ||
| 4280 | |||
| 4281 | static int selinux_key_permission(key_ref_t key_ref, | ||
| 4282 | struct task_struct *ctx, | ||
| 4283 | key_perm_t perm) | ||
| 4284 | { | ||
| 4285 | struct key *key; | ||
| 4286 | struct task_security_struct *tsec; | ||
| 4287 | struct key_security_struct *ksec; | ||
| 4288 | |||
| 4289 | key = key_ref_to_ptr(key_ref); | ||
| 4290 | |||
| 4291 | tsec = ctx->security; | ||
| 4292 | ksec = key->security; | ||
| 4293 | |||
| 4294 | /* if no specific permissions are requested, we skip the | ||
| 4295 | permission check. No serious, additional covert channels | ||
| 4296 | appear to be created. */ | ||
| 4297 | if (perm == 0) | ||
| 4298 | return 0; | ||
| 4299 | |||
| 4300 | return avc_has_perm(tsec->sid, ksec->sid, | ||
| 4301 | SECCLASS_KEY, perm, NULL); | ||
| 4302 | } | ||
| 4303 | |||
| 4304 | #endif | ||
| 4305 | |||
| 4255 | static struct security_operations selinux_ops = { | 4306 | static struct security_operations selinux_ops = { |
| 4256 | .ptrace = selinux_ptrace, | 4307 | .ptrace = selinux_ptrace, |
| 4257 | .capget = selinux_capget, | 4308 | .capget = selinux_capget, |
| @@ -4406,6 +4457,12 @@ static struct security_operations selinux_ops = { | |||
| 4406 | .xfrm_state_delete_security = selinux_xfrm_state_delete, | 4457 | .xfrm_state_delete_security = selinux_xfrm_state_delete, |
| 4407 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, | 4458 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, |
| 4408 | #endif | 4459 | #endif |
| 4460 | |||
| 4461 | #ifdef CONFIG_KEYS | ||
| 4462 | .key_alloc = selinux_key_alloc, | ||
| 4463 | .key_free = selinux_key_free, | ||
| 4464 | .key_permission = selinux_key_permission, | ||
| 4465 | #endif | ||
| 4409 | }; | 4466 | }; |
| 4410 | 4467 | ||
| 4411 | static __init int selinux_init(void) | 4468 | static __init int selinux_init(void) |
| @@ -4441,6 +4498,13 @@ static __init int selinux_init(void) | |||
| 4441 | } else { | 4498 | } else { |
| 4442 | printk(KERN_INFO "SELinux: Starting in permissive mode\n"); | 4499 | printk(KERN_INFO "SELinux: Starting in permissive mode\n"); |
| 4443 | } | 4500 | } |
| 4501 | |||
| 4502 | #ifdef CONFIG_KEYS | ||
| 4503 | /* Add security information to initial keyrings */ | ||
| 4504 | security_key_alloc(&root_user_keyring, current); | ||
| 4505 | security_key_alloc(&root_session_keyring, current); | ||
| 4506 | #endif | ||
| 4507 | |||
| 4444 | return 0; | 4508 | return 0; |
| 4445 | } | 4509 | } |
| 4446 | 4510 | ||
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h index 70ee65a58817..bc020bde6c86 100644 --- a/security/selinux/include/av_perm_to_string.h +++ b/security/selinux/include/av_perm_to_string.h | |||
| @@ -242,3 +242,9 @@ | |||
| 242 | S_(SECCLASS_PACKET, PACKET__SEND, "send") | 242 | S_(SECCLASS_PACKET, PACKET__SEND, "send") |
| 243 | S_(SECCLASS_PACKET, PACKET__RECV, "recv") | 243 | S_(SECCLASS_PACKET, PACKET__RECV, "recv") |
| 244 | S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto") | 244 | S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto") |
| 245 | S_(SECCLASS_KEY, KEY__VIEW, "view") | ||
| 246 | S_(SECCLASS_KEY, KEY__READ, "read") | ||
| 247 | S_(SECCLASS_KEY, KEY__WRITE, "write") | ||
| 248 | S_(SECCLASS_KEY, KEY__SEARCH, "search") | ||
| 249 | S_(SECCLASS_KEY, KEY__LINK, "link") | ||
| 250 | S_(SECCLASS_KEY, KEY__SETATTR, "setattr") | ||
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h index 1d9cf3d306bc..1205227a3a33 100644 --- a/security/selinux/include/av_permissions.h +++ b/security/selinux/include/av_permissions.h | |||
| @@ -959,3 +959,11 @@ | |||
| 959 | #define PACKET__SEND 0x00000001UL | 959 | #define PACKET__SEND 0x00000001UL |
| 960 | #define PACKET__RECV 0x00000002UL | 960 | #define PACKET__RECV 0x00000002UL |
| 961 | #define PACKET__RELABELTO 0x00000004UL | 961 | #define PACKET__RELABELTO 0x00000004UL |
| 962 | |||
| 963 | #define KEY__VIEW 0x00000001UL | ||
| 964 | #define KEY__READ 0x00000002UL | ||
| 965 | #define KEY__WRITE 0x00000004UL | ||
| 966 | #define KEY__SEARCH 0x00000008UL | ||
| 967 | #define KEY__LINK 0x00000010UL | ||
| 968 | #define KEY__SETATTR 0x00000020UL | ||
| 969 | |||
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h index 3aec75fee4f7..24303b61309f 100644 --- a/security/selinux/include/class_to_string.h +++ b/security/selinux/include/class_to_string.h | |||
| @@ -60,3 +60,4 @@ | |||
| 60 | S_("netlink_kobject_uevent_socket") | 60 | S_("netlink_kobject_uevent_socket") |
| 61 | S_("appletalk_socket") | 61 | S_("appletalk_socket") |
| 62 | S_("packet") | 62 | S_("packet") |
| 63 | S_("key") | ||
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h index a0eb9e281d18..95887aed2a68 100644 --- a/security/selinux/include/flask.h +++ b/security/selinux/include/flask.h | |||
| @@ -62,6 +62,7 @@ | |||
| 62 | #define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55 | 62 | #define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55 |
| 63 | #define SECCLASS_APPLETALK_SOCKET 56 | 63 | #define SECCLASS_APPLETALK_SOCKET 56 |
| 64 | #define SECCLASS_PACKET 57 | 64 | #define SECCLASS_PACKET 57 |
| 65 | #define SECCLASS_KEY 58 | ||
| 65 | 66 | ||
| 66 | /* | 67 | /* |
| 67 | * Security identifier indices for initial entities | 68 | * Security identifier indices for initial entities |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 54c030778882..8f5547ad1856 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
| @@ -99,6 +99,11 @@ struct sk_security_struct { | |||
| 99 | u32 peer_sid; /* SID of peer */ | 99 | u32 peer_sid; /* SID of peer */ |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | struct key_security_struct { | ||
| 103 | struct key *obj; /* back pointer */ | ||
| 104 | u32 sid; /* SID of key */ | ||
| 105 | }; | ||
| 106 | |||
| 102 | extern unsigned int selinux_checkreqprot; | 107 | extern unsigned int selinux_checkreqprot; |
| 103 | 108 | ||
| 104 | #endif /* _SELINUX_OBJSEC_H_ */ | 109 | #endif /* _SELINUX_OBJSEC_H_ */ |
diff --git a/sound/Kconfig b/sound/Kconfig index b65ee4701f98..e0d791a98452 100644 --- a/sound/Kconfig +++ b/sound/Kconfig | |||
| @@ -58,6 +58,8 @@ source "sound/pci/Kconfig" | |||
| 58 | 58 | ||
| 59 | source "sound/ppc/Kconfig" | 59 | source "sound/ppc/Kconfig" |
| 60 | 60 | ||
| 61 | source "sound/aoa/Kconfig" | ||
| 62 | |||
| 61 | source "sound/arm/Kconfig" | 63 | source "sound/arm/Kconfig" |
| 62 | 64 | ||
| 63 | source "sound/mips/Kconfig" | 65 | source "sound/mips/Kconfig" |
diff --git a/sound/Makefile b/sound/Makefile index f352bb235968..a682ea30f0c9 100644 --- a/sound/Makefile +++ b/sound/Makefile | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | obj-$(CONFIG_SOUND) += soundcore.o | 4 | obj-$(CONFIG_SOUND) += soundcore.o |
| 5 | obj-$(CONFIG_SOUND_PRIME) += oss/ | 5 | obj-$(CONFIG_SOUND_PRIME) += oss/ |
| 6 | obj-$(CONFIG_DMASOUND) += oss/ | 6 | obj-$(CONFIG_DMASOUND) += oss/ |
| 7 | obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ | 7 | obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ aoa/ |
| 8 | 8 | ||
| 9 | ifeq ($(CONFIG_SND),y) | 9 | ifeq ($(CONFIG_SND),y) |
| 10 | obj-y += last.o | 10 | obj-y += last.o |
diff --git a/sound/aoa/Kconfig b/sound/aoa/Kconfig new file mode 100644 index 000000000000..a85194fe0b06 --- /dev/null +++ b/sound/aoa/Kconfig | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | menu "Apple Onboard Audio driver" | ||
| 2 | depends on SND!=n && PPC | ||
| 3 | |||
| 4 | config SND_AOA | ||
| 5 | tristate "Apple Onboard Audio driver" | ||
| 6 | depends on SOUND && SND_PCM | ||
| 7 | ---help--- | ||
| 8 | This option enables the new driver for the various | ||
| 9 | Apple Onboard Audio components. | ||
| 10 | |||
| 11 | source "sound/aoa/fabrics/Kconfig" | ||
| 12 | |||
| 13 | source "sound/aoa/codecs/Kconfig" | ||
| 14 | |||
| 15 | source "sound/aoa/soundbus/Kconfig" | ||
| 16 | |||
| 17 | endmenu | ||
diff --git a/sound/aoa/Makefile b/sound/aoa/Makefile new file mode 100644 index 000000000000..d8de3e7df48d --- /dev/null +++ b/sound/aoa/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | obj-$(CONFIG_SND_AOA) += core/ | ||
| 2 | obj-$(CONFIG_SND_AOA) += codecs/ | ||
| 3 | obj-$(CONFIG_SND_AOA) += fabrics/ | ||
| 4 | obj-$(CONFIG_SND_AOA_SOUNDBUS) += soundbus/ | ||
diff --git a/sound/aoa/aoa-gpio.h b/sound/aoa/aoa-gpio.h new file mode 100644 index 000000000000..3a61f3115573 --- /dev/null +++ b/sound/aoa/aoa-gpio.h | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio GPIO definitions | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef __AOA_GPIO_H | ||
| 10 | #define __AOA_GPIO_H | ||
| 11 | #include <linux/workqueue.h> | ||
| 12 | #include <linux/mutex.h> | ||
| 13 | #include <asm/prom.h> | ||
| 14 | |||
| 15 | typedef void (*notify_func_t)(void *data); | ||
| 16 | |||
| 17 | enum notify_type { | ||
| 18 | AOA_NOTIFY_HEADPHONE, | ||
| 19 | AOA_NOTIFY_LINE_IN, | ||
| 20 | AOA_NOTIFY_LINE_OUT, | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct gpio_runtime; | ||
| 24 | struct gpio_methods { | ||
| 25 | /* for initialisation/de-initialisation of the GPIO layer */ | ||
| 26 | void (*init)(struct gpio_runtime *rt); | ||
| 27 | void (*exit)(struct gpio_runtime *rt); | ||
| 28 | |||
| 29 | /* turn off headphone, speakers, lineout */ | ||
| 30 | void (*all_amps_off)(struct gpio_runtime *rt); | ||
| 31 | /* turn headphone, speakers, lineout back to previous setting */ | ||
| 32 | void (*all_amps_restore)(struct gpio_runtime *rt); | ||
| 33 | |||
| 34 | void (*set_headphone)(struct gpio_runtime *rt, int on); | ||
| 35 | void (*set_speakers)(struct gpio_runtime *rt, int on); | ||
| 36 | void (*set_lineout)(struct gpio_runtime *rt, int on); | ||
| 37 | |||
| 38 | int (*get_headphone)(struct gpio_runtime *rt); | ||
| 39 | int (*get_speakers)(struct gpio_runtime *rt); | ||
| 40 | int (*get_lineout)(struct gpio_runtime *rt); | ||
| 41 | |||
| 42 | void (*set_hw_reset)(struct gpio_runtime *rt, int on); | ||
| 43 | |||
| 44 | /* use this to be notified of any events. The notification | ||
| 45 | * function is passed the data, and is called in process | ||
| 46 | * context by the use of schedule_work. | ||
| 47 | * The interface for it is that setting a function to NULL | ||
| 48 | * removes it, and they return 0 if the operation succeeded, | ||
| 49 | * and -EBUSY if the notification is already assigned by | ||
| 50 | * someone else. */ | ||
| 51 | int (*set_notify)(struct gpio_runtime *rt, | ||
| 52 | enum notify_type type, | ||
| 53 | notify_func_t notify, | ||
| 54 | void *data); | ||
| 55 | /* returns 0 if not plugged in, 1 if plugged in | ||
| 56 | * or a negative error code */ | ||
| 57 | int (*get_detect)(struct gpio_runtime *rt, | ||
| 58 | enum notify_type type); | ||
| 59 | }; | ||
| 60 | |||
| 61 | struct gpio_notification { | ||
| 62 | notify_func_t notify; | ||
| 63 | void *data; | ||
| 64 | void *gpio_private; | ||
| 65 | struct work_struct work; | ||
| 66 | struct mutex mutex; | ||
| 67 | }; | ||
| 68 | |||
| 69 | struct gpio_runtime { | ||
| 70 | /* to be assigned by fabric */ | ||
| 71 | struct device_node *node; | ||
| 72 | /* since everyone needs this pointer anyway... */ | ||
| 73 | struct gpio_methods *methods; | ||
| 74 | /* to be used by the gpio implementation */ | ||
| 75 | int implementation_private; | ||
| 76 | struct gpio_notification headphone_notify; | ||
| 77 | struct gpio_notification line_in_notify; | ||
| 78 | struct gpio_notification line_out_notify; | ||
| 79 | }; | ||
| 80 | |||
| 81 | #endif /* __AOA_GPIO_H */ | ||
diff --git a/sound/aoa/aoa.h b/sound/aoa/aoa.h new file mode 100644 index 000000000000..378ef1e9879b --- /dev/null +++ b/sound/aoa/aoa.h | |||
| @@ -0,0 +1,131 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio definitions | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef __AOA_H | ||
| 10 | #define __AOA_H | ||
| 11 | #include <asm/prom.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | /* So apparently there's a reason for requiring driver.h to be included first! */ | ||
| 14 | #include <sound/driver.h> | ||
| 15 | #include <sound/core.h> | ||
| 16 | #include <sound/asound.h> | ||
| 17 | #include <sound/control.h> | ||
| 18 | #include "aoa-gpio.h" | ||
| 19 | #include "soundbus/soundbus.h" | ||
| 20 | |||
| 21 | #define MAX_CODEC_NAME_LEN 32 | ||
| 22 | |||
| 23 | struct aoa_codec { | ||
| 24 | char name[MAX_CODEC_NAME_LEN]; | ||
| 25 | |||
| 26 | struct module *owner; | ||
| 27 | |||
| 28 | /* called when the fabric wants to init this codec. | ||
| 29 | * Do alsa card manipulations from here. */ | ||
| 30 | int (*init)(struct aoa_codec *codec); | ||
| 31 | |||
| 32 | /* called when the fabric is done with the codec. | ||
| 33 | * The alsa card will be cleaned up so don't bother. */ | ||
| 34 | void (*exit)(struct aoa_codec *codec); | ||
| 35 | |||
| 36 | /* May be NULL, but can be used by the fabric. | ||
| 37 | * Refcounting is the codec driver's responsibility */ | ||
| 38 | struct device_node *node; | ||
| 39 | |||
| 40 | /* assigned by fabric before init() is called, points | ||
| 41 | * to the soundbus device. Cannot be NULL. */ | ||
| 42 | struct soundbus_dev *soundbus_dev; | ||
| 43 | |||
| 44 | /* assigned by the fabric before init() is called, points | ||
| 45 | * to the fabric's gpio runtime record for the relevant | ||
| 46 | * device. */ | ||
| 47 | struct gpio_runtime *gpio; | ||
| 48 | |||
| 49 | /* assigned by the fabric before init() is called, contains | ||
| 50 | * a codec specific bitmask of what outputs and inputs are | ||
| 51 | * actually connected */ | ||
| 52 | u32 connected; | ||
| 53 | |||
| 54 | /* data the fabric can associate with this structure */ | ||
| 55 | void *fabric_data; | ||
| 56 | |||
| 57 | /* private! */ | ||
| 58 | struct list_head list; | ||
| 59 | struct aoa_fabric *fabric; | ||
| 60 | }; | ||
| 61 | |||
| 62 | /* return 0 on success */ | ||
| 63 | extern int | ||
| 64 | aoa_codec_register(struct aoa_codec *codec); | ||
| 65 | extern void | ||
| 66 | aoa_codec_unregister(struct aoa_codec *codec); | ||
| 67 | |||
| 68 | #define MAX_LAYOUT_NAME_LEN 32 | ||
| 69 | |||
| 70 | struct aoa_fabric { | ||
| 71 | char name[MAX_LAYOUT_NAME_LEN]; | ||
| 72 | |||
| 73 | struct module *owner; | ||
| 74 | |||
| 75 | /* once codecs register, they are passed here after. | ||
| 76 | * They are of course not initialised, since the | ||
| 77 | * fabric is responsible for initialising some fields | ||
| 78 | * in the codec structure! */ | ||
| 79 | int (*found_codec)(struct aoa_codec *codec); | ||
| 80 | /* called for each codec when it is removed, | ||
| 81 | * also in the case that aoa_fabric_unregister | ||
| 82 | * is called and all codecs are removed | ||
| 83 | * from this fabric. | ||
| 84 | * Also called if found_codec returned 0 but | ||
| 85 | * the codec couldn't initialise. */ | ||
| 86 | void (*remove_codec)(struct aoa_codec *codec); | ||
| 87 | /* If found_codec returned 0, and the codec | ||
| 88 | * could be initialised, this is called. */ | ||
| 89 | void (*attached_codec)(struct aoa_codec *codec); | ||
| 90 | }; | ||
| 91 | |||
| 92 | /* return 0 on success, -EEXIST if another fabric is | ||
| 93 | * registered, -EALREADY if the same fabric is registered. | ||
| 94 | * Passing NULL can be used to test for the presence | ||
| 95 | * of another fabric, if -EALREADY is returned there is | ||
| 96 | * no other fabric present. | ||
| 97 | * In the case that the function returns -EALREADY | ||
| 98 | * and the fabric passed is not NULL, all codecs | ||
| 99 | * that are not assigned yet are passed to the fabric | ||
| 100 | * again for reconsideration. */ | ||
| 101 | extern int | ||
| 102 | aoa_fabric_register(struct aoa_fabric *fabric); | ||
| 103 | |||
| 104 | /* it is vital to call this when the fabric exits! | ||
| 105 | * When calling, the remove_codec will be called | ||
| 106 | * for all codecs, unless it is NULL. */ | ||
| 107 | extern void | ||
| 108 | aoa_fabric_unregister(struct aoa_fabric *fabric); | ||
| 109 | |||
| 110 | /* if for some reason you want to get rid of a codec | ||
| 111 | * before the fabric is removed, use this. | ||
| 112 | * Note that remove_codec is called for it! */ | ||
| 113 | extern void | ||
| 114 | aoa_fabric_unlink_codec(struct aoa_codec *codec); | ||
| 115 | |||
| 116 | /* alsa help methods */ | ||
| 117 | struct aoa_card { | ||
| 118 | struct snd_card *alsa_card; | ||
| 119 | }; | ||
| 120 | |||
| 121 | extern int aoa_snd_device_new(snd_device_type_t type, | ||
| 122 | void * device_data, struct snd_device_ops * ops); | ||
| 123 | extern struct snd_card *aoa_get_card(void); | ||
| 124 | extern int aoa_snd_ctl_add(struct snd_kcontrol* control); | ||
| 125 | |||
| 126 | /* GPIO stuff */ | ||
| 127 | extern struct gpio_methods *pmf_gpio_methods; | ||
| 128 | extern struct gpio_methods *ftr_gpio_methods; | ||
| 129 | /* extern struct gpio_methods *map_gpio_methods; */ | ||
| 130 | |||
| 131 | #endif /* __AOA_H */ | ||
diff --git a/sound/aoa/codecs/Kconfig b/sound/aoa/codecs/Kconfig new file mode 100644 index 000000000000..90cf58f68630 --- /dev/null +++ b/sound/aoa/codecs/Kconfig | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | config SND_AOA_ONYX | ||
| 2 | tristate "support Onyx chip" | ||
| 3 | depends on SND_AOA | ||
| 4 | ---help--- | ||
| 5 | This option enables support for the Onyx (pcm3052) | ||
| 6 | codec chip found in the latest Apple machines | ||
| 7 | (most of those with digital audio output). | ||
| 8 | |||
| 9 | #config SND_AOA_TOPAZ | ||
| 10 | # tristate "support Topaz chips" | ||
| 11 | # depends on SND_AOA | ||
| 12 | # ---help--- | ||
| 13 | # This option enables support for the Topaz (CS84xx) | ||
| 14 | # codec chips found in the latest Apple machines, | ||
| 15 | # these chips do the digital input and output on | ||
| 16 | # some PowerMacs. | ||
| 17 | |||
| 18 | config SND_AOA_TAS | ||
| 19 | tristate "support TAS chips" | ||
| 20 | depends on SND_AOA | ||
| 21 | ---help--- | ||
| 22 | This option enables support for the tas chips | ||
| 23 | found in a lot of Apple Machines, especially | ||
| 24 | iBooks and PowerBooks without digital. | ||
| 25 | |||
| 26 | config SND_AOA_TOONIE | ||
| 27 | tristate "support Toonie chip" | ||
| 28 | depends on SND_AOA | ||
| 29 | ---help--- | ||
| 30 | This option enables support for the toonie codec | ||
| 31 | found in the Mac Mini. If you have a Mac Mini and | ||
| 32 | want to hear sound, select this option. | ||
diff --git a/sound/aoa/codecs/Makefile b/sound/aoa/codecs/Makefile new file mode 100644 index 000000000000..31cbe68fd42f --- /dev/null +++ b/sound/aoa/codecs/Makefile | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | obj-$(CONFIG_SND_AOA_ONYX) += snd-aoa-codec-onyx.o | ||
| 2 | obj-$(CONFIG_SND_AOA_TAS) += snd-aoa-codec-tas.o | ||
| 3 | obj-$(CONFIG_SND_AOA_TOONIE) += snd-aoa-codec-toonie.o | ||
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c new file mode 100644 index 000000000000..0b7650788f1f --- /dev/null +++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c | |||
| @@ -0,0 +1,1113 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio driver for Onyx codec | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | * | ||
| 8 | * | ||
| 9 | * This is a driver for the pcm3052 codec chip (codenamed Onyx) | ||
| 10 | * that is present in newer Apple hardware (with digital output). | ||
| 11 | * | ||
| 12 | * The Onyx codec has the following connections (listed by the bit | ||
| 13 | * to be used in aoa_codec.connected): | ||
| 14 | * 0: analog output | ||
| 15 | * 1: digital output | ||
| 16 | * 2: line input | ||
| 17 | * 3: microphone input | ||
| 18 | * Note that even though I know of no machine that has for example | ||
| 19 | * the digital output connected but not the analog, I have handled | ||
| 20 | * all the different cases in the code so that this driver may serve | ||
| 21 | * as a good example of what to do. | ||
| 22 | * | ||
| 23 | * NOTE: This driver assumes that there's at most one chip to be | ||
| 24 | * used with one alsa card, in form of creating all kinds | ||
| 25 | * of mixer elements without regard for their existence. | ||
| 26 | * But snd-aoa assumes that there's at most one card, so | ||
| 27 | * this means you can only have one onyx on a system. This | ||
| 28 | * should probably be fixed by changing the assumption of | ||
| 29 | * having just a single card on a system, and making the | ||
| 30 | * 'card' pointer accessible to anyone who needs it instead | ||
| 31 | * of hiding it in the aoa_snd_* functions... | ||
| 32 | * | ||
| 33 | */ | ||
| 34 | #include <linux/delay.h> | ||
| 35 | #include <linux/module.h> | ||
| 36 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
| 37 | MODULE_LICENSE("GPL"); | ||
| 38 | MODULE_DESCRIPTION("pcm3052 (onyx) codec driver for snd-aoa"); | ||
| 39 | |||
| 40 | #include "snd-aoa-codec-onyx.h" | ||
| 41 | #include "../aoa.h" | ||
| 42 | #include "../soundbus/soundbus.h" | ||
| 43 | |||
| 44 | |||
| 45 | #define PFX "snd-aoa-codec-onyx: " | ||
| 46 | |||
| 47 | struct onyx { | ||
| 48 | /* cache registers 65 to 80, they are write-only! */ | ||
| 49 | u8 cache[16]; | ||
| 50 | struct i2c_client i2c; | ||
| 51 | struct aoa_codec codec; | ||
| 52 | u32 initialised:1, | ||
| 53 | spdif_locked:1, | ||
| 54 | analog_locked:1, | ||
| 55 | original_mute:2; | ||
| 56 | int open_count; | ||
| 57 | struct codec_info *codec_info; | ||
| 58 | |||
| 59 | /* mutex serializes concurrent access to the device | ||
| 60 | * and this structure. | ||
| 61 | */ | ||
| 62 | struct mutex mutex; | ||
| 63 | }; | ||
| 64 | #define codec_to_onyx(c) container_of(c, struct onyx, codec) | ||
| 65 | |||
| 66 | /* both return 0 if all ok, else on error */ | ||
| 67 | static int onyx_read_register(struct onyx *onyx, u8 reg, u8 *value) | ||
| 68 | { | ||
| 69 | s32 v; | ||
| 70 | |||
| 71 | if (reg != ONYX_REG_CONTROL) { | ||
| 72 | *value = onyx->cache[reg-FIRSTREGISTER]; | ||
| 73 | return 0; | ||
| 74 | } | ||
| 75 | v = i2c_smbus_read_byte_data(&onyx->i2c, reg); | ||
| 76 | if (v < 0) | ||
| 77 | return -1; | ||
| 78 | *value = (u8)v; | ||
| 79 | onyx->cache[ONYX_REG_CONTROL-FIRSTREGISTER] = *value; | ||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int onyx_write_register(struct onyx *onyx, u8 reg, u8 value) | ||
| 84 | { | ||
| 85 | int result; | ||
| 86 | |||
| 87 | result = i2c_smbus_write_byte_data(&onyx->i2c, reg, value); | ||
| 88 | if (!result) | ||
| 89 | onyx->cache[reg-FIRSTREGISTER] = value; | ||
| 90 | return result; | ||
| 91 | } | ||
| 92 | |||
| 93 | /* alsa stuff */ | ||
| 94 | |||
| 95 | static int onyx_dev_register(struct snd_device *dev) | ||
| 96 | { | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | static struct snd_device_ops ops = { | ||
| 101 | .dev_register = onyx_dev_register, | ||
| 102 | }; | ||
| 103 | |||
| 104 | /* this is necessary because most alsa mixer programs | ||
| 105 | * can't properly handle the negative range */ | ||
| 106 | #define VOLUME_RANGE_SHIFT 128 | ||
| 107 | |||
| 108 | static int onyx_snd_vol_info(struct snd_kcontrol *kcontrol, | ||
| 109 | struct snd_ctl_elem_info *uinfo) | ||
| 110 | { | ||
| 111 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 112 | uinfo->count = 2; | ||
| 113 | uinfo->value.integer.min = -128 + VOLUME_RANGE_SHIFT; | ||
| 114 | uinfo->value.integer.max = -1 + VOLUME_RANGE_SHIFT; | ||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | static int onyx_snd_vol_get(struct snd_kcontrol *kcontrol, | ||
| 119 | struct snd_ctl_elem_value *ucontrol) | ||
| 120 | { | ||
| 121 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 122 | s8 l, r; | ||
| 123 | |||
| 124 | mutex_lock(&onyx->mutex); | ||
| 125 | onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l); | ||
| 126 | onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r); | ||
| 127 | mutex_unlock(&onyx->mutex); | ||
| 128 | |||
| 129 | ucontrol->value.integer.value[0] = l + VOLUME_RANGE_SHIFT; | ||
| 130 | ucontrol->value.integer.value[1] = r + VOLUME_RANGE_SHIFT; | ||
| 131 | |||
| 132 | return 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int onyx_snd_vol_put(struct snd_kcontrol *kcontrol, | ||
| 136 | struct snd_ctl_elem_value *ucontrol) | ||
| 137 | { | ||
| 138 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 139 | s8 l, r; | ||
| 140 | |||
| 141 | mutex_lock(&onyx->mutex); | ||
| 142 | onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, &l); | ||
| 143 | onyx_read_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, &r); | ||
| 144 | |||
| 145 | if (l + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[0] && | ||
| 146 | r + VOLUME_RANGE_SHIFT == ucontrol->value.integer.value[1]) { | ||
| 147 | mutex_unlock(&onyx->mutex); | ||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_LEFT, | ||
| 152 | ucontrol->value.integer.value[0] | ||
| 153 | - VOLUME_RANGE_SHIFT); | ||
| 154 | onyx_write_register(onyx, ONYX_REG_DAC_ATTEN_RIGHT, | ||
| 155 | ucontrol->value.integer.value[1] | ||
| 156 | - VOLUME_RANGE_SHIFT); | ||
| 157 | mutex_unlock(&onyx->mutex); | ||
| 158 | |||
| 159 | return 1; | ||
| 160 | } | ||
| 161 | |||
| 162 | static struct snd_kcontrol_new volume_control = { | ||
| 163 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 164 | .name = "Master Playback Volume", | ||
| 165 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 166 | .info = onyx_snd_vol_info, | ||
| 167 | .get = onyx_snd_vol_get, | ||
| 168 | .put = onyx_snd_vol_put, | ||
| 169 | }; | ||
| 170 | |||
| 171 | /* like above, this is necessary because a lot | ||
| 172 | * of alsa mixer programs don't handle ranges | ||
| 173 | * that don't start at 0 properly. | ||
| 174 | * even alsamixer is one of them... */ | ||
| 175 | #define INPUTGAIN_RANGE_SHIFT (-3) | ||
| 176 | |||
| 177 | static int onyx_snd_inputgain_info(struct snd_kcontrol *kcontrol, | ||
| 178 | struct snd_ctl_elem_info *uinfo) | ||
| 179 | { | ||
| 180 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 181 | uinfo->count = 1; | ||
| 182 | uinfo->value.integer.min = 3 + INPUTGAIN_RANGE_SHIFT; | ||
| 183 | uinfo->value.integer.max = 28 + INPUTGAIN_RANGE_SHIFT; | ||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | static int onyx_snd_inputgain_get(struct snd_kcontrol *kcontrol, | ||
| 188 | struct snd_ctl_elem_value *ucontrol) | ||
| 189 | { | ||
| 190 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 191 | u8 ig; | ||
| 192 | |||
| 193 | mutex_lock(&onyx->mutex); | ||
| 194 | onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &ig); | ||
| 195 | mutex_unlock(&onyx->mutex); | ||
| 196 | |||
| 197 | ucontrol->value.integer.value[0] = | ||
| 198 | (ig & ONYX_ADC_PGA_GAIN_MASK) + INPUTGAIN_RANGE_SHIFT; | ||
| 199 | |||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | |||
| 203 | static int onyx_snd_inputgain_put(struct snd_kcontrol *kcontrol, | ||
| 204 | struct snd_ctl_elem_value *ucontrol) | ||
| 205 | { | ||
| 206 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 207 | u8 v, n; | ||
| 208 | |||
| 209 | mutex_lock(&onyx->mutex); | ||
| 210 | onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); | ||
| 211 | n = v; | ||
| 212 | n &= ~ONYX_ADC_PGA_GAIN_MASK; | ||
| 213 | n |= (ucontrol->value.integer.value[0] - INPUTGAIN_RANGE_SHIFT) | ||
| 214 | & ONYX_ADC_PGA_GAIN_MASK; | ||
| 215 | onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, n); | ||
| 216 | mutex_unlock(&onyx->mutex); | ||
| 217 | |||
| 218 | return n != v; | ||
| 219 | } | ||
| 220 | |||
| 221 | static struct snd_kcontrol_new inputgain_control = { | ||
| 222 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 223 | .name = "Master Capture Volume", | ||
| 224 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 225 | .info = onyx_snd_inputgain_info, | ||
| 226 | .get = onyx_snd_inputgain_get, | ||
| 227 | .put = onyx_snd_inputgain_put, | ||
| 228 | }; | ||
| 229 | |||
| 230 | static int onyx_snd_capture_source_info(struct snd_kcontrol *kcontrol, | ||
| 231 | struct snd_ctl_elem_info *uinfo) | ||
| 232 | { | ||
| 233 | static char *texts[] = { "Line-In", "Microphone" }; | ||
| 234 | |||
| 235 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 236 | uinfo->count = 1; | ||
| 237 | uinfo->value.enumerated.items = 2; | ||
| 238 | if (uinfo->value.enumerated.item > 1) | ||
| 239 | uinfo->value.enumerated.item = 1; | ||
| 240 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
| 241 | return 0; | ||
| 242 | } | ||
| 243 | |||
| 244 | static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol, | ||
| 245 | struct snd_ctl_elem_value *ucontrol) | ||
| 246 | { | ||
| 247 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 248 | s8 v; | ||
| 249 | |||
| 250 | mutex_lock(&onyx->mutex); | ||
| 251 | onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); | ||
| 252 | mutex_unlock(&onyx->mutex); | ||
| 253 | |||
| 254 | ucontrol->value.enumerated.item[0] = !!(v&ONYX_ADC_INPUT_MIC); | ||
| 255 | |||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | static void onyx_set_capture_source(struct onyx *onyx, int mic) | ||
| 260 | { | ||
| 261 | s8 v; | ||
| 262 | |||
| 263 | mutex_lock(&onyx->mutex); | ||
| 264 | onyx_read_register(onyx, ONYX_REG_ADC_CONTROL, &v); | ||
| 265 | v &= ~ONYX_ADC_INPUT_MIC; | ||
| 266 | if (mic) | ||
| 267 | v |= ONYX_ADC_INPUT_MIC; | ||
| 268 | onyx_write_register(onyx, ONYX_REG_ADC_CONTROL, v); | ||
| 269 | mutex_unlock(&onyx->mutex); | ||
| 270 | } | ||
| 271 | |||
| 272 | static int onyx_snd_capture_source_put(struct snd_kcontrol *kcontrol, | ||
| 273 | struct snd_ctl_elem_value *ucontrol) | ||
| 274 | { | ||
| 275 | onyx_set_capture_source(snd_kcontrol_chip(kcontrol), | ||
| 276 | ucontrol->value.enumerated.item[0]); | ||
| 277 | return 1; | ||
| 278 | } | ||
| 279 | |||
| 280 | static struct snd_kcontrol_new capture_source_control = { | ||
| 281 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 282 | /* If we name this 'Input Source', it properly shows up in | ||
| 283 | * alsamixer as a selection, * but it's shown under the | ||
| 284 | * 'Playback' category. | ||
| 285 | * If I name it 'Capture Source', it shows up in strange | ||
| 286 | * ways (two bools of which one can be selected at a | ||
| 287 | * time) but at least it's shown in the 'Capture' | ||
| 288 | * category. | ||
| 289 | * I was told that this was due to backward compatibility, | ||
| 290 | * but I don't understand then why the mangling is *not* | ||
| 291 | * done when I name it "Input Source"..... | ||
| 292 | */ | ||
| 293 | .name = "Capture Source", | ||
| 294 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 295 | .info = onyx_snd_capture_source_info, | ||
| 296 | .get = onyx_snd_capture_source_get, | ||
| 297 | .put = onyx_snd_capture_source_put, | ||
| 298 | }; | ||
| 299 | |||
| 300 | static int onyx_snd_mute_info(struct snd_kcontrol *kcontrol, | ||
| 301 | struct snd_ctl_elem_info *uinfo) | ||
| 302 | { | ||
| 303 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
| 304 | uinfo->count = 2; | ||
| 305 | uinfo->value.integer.min = 0; | ||
| 306 | uinfo->value.integer.max = 1; | ||
| 307 | return 0; | ||
| 308 | } | ||
| 309 | |||
| 310 | static int onyx_snd_mute_get(struct snd_kcontrol *kcontrol, | ||
| 311 | struct snd_ctl_elem_value *ucontrol) | ||
| 312 | { | ||
| 313 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 314 | u8 c; | ||
| 315 | |||
| 316 | mutex_lock(&onyx->mutex); | ||
| 317 | onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &c); | ||
| 318 | mutex_unlock(&onyx->mutex); | ||
| 319 | |||
| 320 | ucontrol->value.integer.value[0] = !(c & ONYX_MUTE_LEFT); | ||
| 321 | ucontrol->value.integer.value[1] = !(c & ONYX_MUTE_RIGHT); | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | static int onyx_snd_mute_put(struct snd_kcontrol *kcontrol, | ||
| 327 | struct snd_ctl_elem_value *ucontrol) | ||
| 328 | { | ||
| 329 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 330 | u8 v = 0, c = 0; | ||
| 331 | int err = -EBUSY; | ||
| 332 | |||
| 333 | mutex_lock(&onyx->mutex); | ||
| 334 | if (onyx->analog_locked) | ||
| 335 | goto out_unlock; | ||
| 336 | |||
| 337 | onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v); | ||
| 338 | c = v; | ||
| 339 | c &= ~(ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT); | ||
| 340 | if (!ucontrol->value.integer.value[0]) | ||
| 341 | c |= ONYX_MUTE_LEFT; | ||
| 342 | if (!ucontrol->value.integer.value[1]) | ||
| 343 | c |= ONYX_MUTE_RIGHT; | ||
| 344 | err = onyx_write_register(onyx, ONYX_REG_DAC_CONTROL, c); | ||
| 345 | |||
| 346 | out_unlock: | ||
| 347 | mutex_unlock(&onyx->mutex); | ||
| 348 | |||
| 349 | return !err ? (v != c) : err; | ||
| 350 | } | ||
| 351 | |||
| 352 | static struct snd_kcontrol_new mute_control = { | ||
| 353 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 354 | .name = "Master Playback Switch", | ||
| 355 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 356 | .info = onyx_snd_mute_info, | ||
| 357 | .get = onyx_snd_mute_get, | ||
| 358 | .put = onyx_snd_mute_put, | ||
| 359 | }; | ||
| 360 | |||
| 361 | |||
| 362 | static int onyx_snd_single_bit_info(struct snd_kcontrol *kcontrol, | ||
| 363 | struct snd_ctl_elem_info *uinfo) | ||
| 364 | { | ||
| 365 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
| 366 | uinfo->count = 1; | ||
| 367 | uinfo->value.integer.min = 0; | ||
| 368 | uinfo->value.integer.max = 1; | ||
| 369 | return 0; | ||
| 370 | } | ||
| 371 | |||
| 372 | #define FLAG_POLARITY_INVERT 1 | ||
| 373 | #define FLAG_SPDIFLOCK 2 | ||
| 374 | |||
| 375 | static int onyx_snd_single_bit_get(struct snd_kcontrol *kcontrol, | ||
| 376 | struct snd_ctl_elem_value *ucontrol) | ||
| 377 | { | ||
| 378 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 379 | u8 c; | ||
| 380 | long int pv = kcontrol->private_value; | ||
| 381 | u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT; | ||
| 382 | u8 address = (pv >> 8) & 0xff; | ||
| 383 | u8 mask = pv & 0xff; | ||
| 384 | |||
| 385 | mutex_lock(&onyx->mutex); | ||
| 386 | onyx_read_register(onyx, address, &c); | ||
| 387 | mutex_unlock(&onyx->mutex); | ||
| 388 | |||
| 389 | ucontrol->value.integer.value[0] = !!(c & mask) ^ polarity; | ||
| 390 | |||
| 391 | return 0; | ||
| 392 | } | ||
| 393 | |||
| 394 | static int onyx_snd_single_bit_put(struct snd_kcontrol *kcontrol, | ||
| 395 | struct snd_ctl_elem_value *ucontrol) | ||
| 396 | { | ||
| 397 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 398 | u8 v = 0, c = 0; | ||
| 399 | int err; | ||
| 400 | long int pv = kcontrol->private_value; | ||
| 401 | u8 polarity = (pv >> 16) & FLAG_POLARITY_INVERT; | ||
| 402 | u8 spdiflock = (pv >> 16) & FLAG_SPDIFLOCK; | ||
| 403 | u8 address = (pv >> 8) & 0xff; | ||
| 404 | u8 mask = pv & 0xff; | ||
| 405 | |||
| 406 | mutex_lock(&onyx->mutex); | ||
| 407 | if (spdiflock && onyx->spdif_locked) { | ||
| 408 | /* even if alsamixer doesn't care.. */ | ||
| 409 | err = -EBUSY; | ||
| 410 | goto out_unlock; | ||
| 411 | } | ||
| 412 | onyx_read_register(onyx, address, &v); | ||
| 413 | c = v; | ||
| 414 | c &= ~(mask); | ||
| 415 | if (!!ucontrol->value.integer.value[0] ^ polarity) | ||
| 416 | c |= mask; | ||
| 417 | err = onyx_write_register(onyx, address, c); | ||
| 418 | |||
| 419 | out_unlock: | ||
| 420 | mutex_unlock(&onyx->mutex); | ||
| 421 | |||
| 422 | return !err ? (v != c) : err; | ||
| 423 | } | ||
| 424 | |||
| 425 | #define SINGLE_BIT(n, type, description, address, mask, flags) \ | ||
| 426 | static struct snd_kcontrol_new n##_control = { \ | ||
| 427 | .iface = SNDRV_CTL_ELEM_IFACE_##type, \ | ||
| 428 | .name = description, \ | ||
| 429 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
| 430 | .info = onyx_snd_single_bit_info, \ | ||
| 431 | .get = onyx_snd_single_bit_get, \ | ||
| 432 | .put = onyx_snd_single_bit_put, \ | ||
| 433 | .private_value = (flags << 16) | (address << 8) | mask \ | ||
| 434 | } | ||
| 435 | |||
| 436 | SINGLE_BIT(spdif, | ||
| 437 | MIXER, | ||
| 438 | SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), | ||
| 439 | ONYX_REG_DIG_INFO4, | ||
| 440 | ONYX_SPDIF_ENABLE, | ||
| 441 | FLAG_SPDIFLOCK); | ||
| 442 | SINGLE_BIT(ovr1, | ||
| 443 | MIXER, | ||
| 444 | "Oversampling Rate", | ||
| 445 | ONYX_REG_DAC_CONTROL, | ||
| 446 | ONYX_OVR1, | ||
| 447 | 0); | ||
| 448 | SINGLE_BIT(flt0, | ||
| 449 | MIXER, | ||
| 450 | "Fast Digital Filter Rolloff", | ||
| 451 | ONYX_REG_DAC_FILTER, | ||
| 452 | ONYX_ROLLOFF_FAST, | ||
| 453 | FLAG_POLARITY_INVERT); | ||
| 454 | SINGLE_BIT(hpf, | ||
| 455 | MIXER, | ||
| 456 | "Highpass Filter", | ||
| 457 | ONYX_REG_ADC_HPF_BYPASS, | ||
| 458 | ONYX_HPF_DISABLE, | ||
| 459 | FLAG_POLARITY_INVERT); | ||
| 460 | SINGLE_BIT(dm12, | ||
| 461 | MIXER, | ||
| 462 | "Digital De-Emphasis", | ||
| 463 | ONYX_REG_DAC_DEEMPH, | ||
| 464 | ONYX_DIGDEEMPH_CTRL, | ||
| 465 | 0); | ||
| 466 | |||
| 467 | static int onyx_spdif_info(struct snd_kcontrol *kcontrol, | ||
| 468 | struct snd_ctl_elem_info *uinfo) | ||
| 469 | { | ||
| 470 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
| 471 | uinfo->count = 1; | ||
| 472 | return 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | static int onyx_spdif_mask_get(struct snd_kcontrol *kcontrol, | ||
| 476 | struct snd_ctl_elem_value *ucontrol) | ||
| 477 | { | ||
| 478 | /* datasheet page 30, all others are 0 */ | ||
| 479 | ucontrol->value.iec958.status[0] = 0x3e; | ||
| 480 | ucontrol->value.iec958.status[1] = 0xff; | ||
| 481 | |||
| 482 | ucontrol->value.iec958.status[3] = 0x3f; | ||
| 483 | ucontrol->value.iec958.status[4] = 0x0f; | ||
| 484 | |||
| 485 | return 0; | ||
| 486 | } | ||
| 487 | |||
| 488 | static struct snd_kcontrol_new onyx_spdif_mask = { | ||
| 489 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
| 490 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
| 491 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), | ||
| 492 | .info = onyx_spdif_info, | ||
| 493 | .get = onyx_spdif_mask_get, | ||
| 494 | }; | ||
| 495 | |||
| 496 | static int onyx_spdif_get(struct snd_kcontrol *kcontrol, | ||
| 497 | struct snd_ctl_elem_value *ucontrol) | ||
| 498 | { | ||
| 499 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 500 | u8 v; | ||
| 501 | |||
| 502 | mutex_lock(&onyx->mutex); | ||
| 503 | onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v); | ||
| 504 | ucontrol->value.iec958.status[0] = v & 0x3e; | ||
| 505 | |||
| 506 | onyx_read_register(onyx, ONYX_REG_DIG_INFO2, &v); | ||
| 507 | ucontrol->value.iec958.status[1] = v; | ||
| 508 | |||
| 509 | onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v); | ||
| 510 | ucontrol->value.iec958.status[3] = v & 0x3f; | ||
| 511 | |||
| 512 | onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); | ||
| 513 | ucontrol->value.iec958.status[4] = v & 0x0f; | ||
| 514 | mutex_unlock(&onyx->mutex); | ||
| 515 | |||
| 516 | return 0; | ||
| 517 | } | ||
| 518 | |||
| 519 | static int onyx_spdif_put(struct snd_kcontrol *kcontrol, | ||
| 520 | struct snd_ctl_elem_value *ucontrol) | ||
| 521 | { | ||
| 522 | struct onyx *onyx = snd_kcontrol_chip(kcontrol); | ||
| 523 | u8 v; | ||
| 524 | |||
| 525 | mutex_lock(&onyx->mutex); | ||
| 526 | onyx_read_register(onyx, ONYX_REG_DIG_INFO1, &v); | ||
| 527 | v = (v & ~0x3e) | (ucontrol->value.iec958.status[0] & 0x3e); | ||
| 528 | onyx_write_register(onyx, ONYX_REG_DIG_INFO1, v); | ||
| 529 | |||
| 530 | v = ucontrol->value.iec958.status[1]; | ||
| 531 | onyx_write_register(onyx, ONYX_REG_DIG_INFO2, v); | ||
| 532 | |||
| 533 | onyx_read_register(onyx, ONYX_REG_DIG_INFO3, &v); | ||
| 534 | v = (v & ~0x3f) | (ucontrol->value.iec958.status[3] & 0x3f); | ||
| 535 | onyx_write_register(onyx, ONYX_REG_DIG_INFO3, v); | ||
| 536 | |||
| 537 | onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); | ||
| 538 | v = (v & ~0x0f) | (ucontrol->value.iec958.status[4] & 0x0f); | ||
| 539 | onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v); | ||
| 540 | mutex_unlock(&onyx->mutex); | ||
| 541 | |||
| 542 | return 1; | ||
| 543 | } | ||
| 544 | |||
| 545 | static struct snd_kcontrol_new onyx_spdif_ctrl = { | ||
| 546 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 547 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
| 548 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | ||
| 549 | .info = onyx_spdif_info, | ||
| 550 | .get = onyx_spdif_get, | ||
| 551 | .put = onyx_spdif_put, | ||
| 552 | }; | ||
| 553 | |||
| 554 | /* our registers */ | ||
| 555 | |||
| 556 | static u8 register_map[] = { | ||
| 557 | ONYX_REG_DAC_ATTEN_LEFT, | ||
| 558 | ONYX_REG_DAC_ATTEN_RIGHT, | ||
| 559 | ONYX_REG_CONTROL, | ||
| 560 | ONYX_REG_DAC_CONTROL, | ||
| 561 | ONYX_REG_DAC_DEEMPH, | ||
| 562 | ONYX_REG_DAC_FILTER, | ||
| 563 | ONYX_REG_DAC_OUTPHASE, | ||
| 564 | ONYX_REG_ADC_CONTROL, | ||
| 565 | ONYX_REG_ADC_HPF_BYPASS, | ||
| 566 | ONYX_REG_DIG_INFO1, | ||
| 567 | ONYX_REG_DIG_INFO2, | ||
| 568 | ONYX_REG_DIG_INFO3, | ||
| 569 | ONYX_REG_DIG_INFO4 | ||
| 570 | }; | ||
| 571 | |||
| 572 | static u8 initial_values[ARRAY_SIZE(register_map)] = { | ||
| 573 | 0x80, 0x80, /* muted */ | ||
| 574 | ONYX_MRST | ONYX_SRST, /* but handled specially! */ | ||
| 575 | ONYX_MUTE_LEFT | ONYX_MUTE_RIGHT, | ||
| 576 | 0, /* no deemphasis */ | ||
| 577 | ONYX_DAC_FILTER_ALWAYS, | ||
| 578 | ONYX_OUTPHASE_INVERTED, | ||
| 579 | (-1 /*dB*/ + 8) & 0xF, /* line in selected, -1 dB gain*/ | ||
| 580 | ONYX_ADC_HPF_ALWAYS, | ||
| 581 | (1<<2), /* pcm audio */ | ||
| 582 | 2, /* category: pcm coder */ | ||
| 583 | 0, /* sampling frequency 44.1 kHz, clock accuracy level II */ | ||
| 584 | 1 /* 24 bit depth */ | ||
| 585 | }; | ||
| 586 | |||
| 587 | /* reset registers of chip, either to initial or to previous values */ | ||
| 588 | static int onyx_register_init(struct onyx *onyx) | ||
| 589 | { | ||
| 590 | int i; | ||
| 591 | u8 val; | ||
| 592 | u8 regs[sizeof(initial_values)]; | ||
| 593 | |||
| 594 | if (!onyx->initialised) { | ||
| 595 | memcpy(regs, initial_values, sizeof(initial_values)); | ||
| 596 | if (onyx_read_register(onyx, ONYX_REG_CONTROL, &val)) | ||
| 597 | return -1; | ||
| 598 | val &= ~ONYX_SILICONVERSION; | ||
| 599 | val |= initial_values[3]; | ||
| 600 | regs[3] = val; | ||
| 601 | } else { | ||
| 602 | for (i=0; i<sizeof(register_map); i++) | ||
| 603 | regs[i] = onyx->cache[register_map[i]-FIRSTREGISTER]; | ||
| 604 | } | ||
| 605 | |||
| 606 | for (i=0; i<sizeof(register_map); i++) { | ||
| 607 | if (onyx_write_register(onyx, register_map[i], regs[i])) | ||
| 608 | return -1; | ||
| 609 | } | ||
| 610 | onyx->initialised = 1; | ||
| 611 | return 0; | ||
| 612 | } | ||
| 613 | |||
| 614 | static struct transfer_info onyx_transfers[] = { | ||
| 615 | /* this is first so we can skip it if no input is present... | ||
| 616 | * No hardware exists with that, but it's here as an example | ||
| 617 | * of what to do :) */ | ||
| 618 | { | ||
| 619 | /* analog input */ | ||
| 620 | .formats = SNDRV_PCM_FMTBIT_S8 | | ||
| 621 | SNDRV_PCM_FMTBIT_S16_BE | | ||
| 622 | SNDRV_PCM_FMTBIT_S24_BE, | ||
| 623 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
| 624 | .transfer_in = 1, | ||
| 625 | .must_be_clock_source = 0, | ||
| 626 | .tag = 0, | ||
| 627 | }, | ||
| 628 | { | ||
| 629 | /* if analog and digital are currently off, anything should go, | ||
| 630 | * so this entry describes everything we can do... */ | ||
| 631 | .formats = SNDRV_PCM_FMTBIT_S8 | | ||
| 632 | SNDRV_PCM_FMTBIT_S16_BE | | ||
| 633 | SNDRV_PCM_FMTBIT_S24_BE | ||
| 634 | #ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE | ||
| 635 | | SNDRV_PCM_FMTBIT_COMPRESSED_16BE | ||
| 636 | #endif | ||
| 637 | , | ||
| 638 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
| 639 | .tag = 0, | ||
| 640 | }, | ||
| 641 | { | ||
| 642 | /* analog output */ | ||
| 643 | .formats = SNDRV_PCM_FMTBIT_S8 | | ||
| 644 | SNDRV_PCM_FMTBIT_S16_BE | | ||
| 645 | SNDRV_PCM_FMTBIT_S24_BE, | ||
| 646 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
| 647 | .transfer_in = 0, | ||
| 648 | .must_be_clock_source = 0, | ||
| 649 | .tag = 1, | ||
| 650 | }, | ||
| 651 | { | ||
| 652 | /* digital pcm output, also possible for analog out */ | ||
| 653 | .formats = SNDRV_PCM_FMTBIT_S8 | | ||
| 654 | SNDRV_PCM_FMTBIT_S16_BE | | ||
| 655 | SNDRV_PCM_FMTBIT_S24_BE, | ||
| 656 | .rates = SNDRV_PCM_RATE_32000 | | ||
| 657 | SNDRV_PCM_RATE_44100 | | ||
| 658 | SNDRV_PCM_RATE_48000, | ||
| 659 | .transfer_in = 0, | ||
| 660 | .must_be_clock_source = 0, | ||
| 661 | .tag = 2, | ||
| 662 | }, | ||
| 663 | #ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE | ||
| 664 | Once alsa gets supports for this kind of thing we can add it... | ||
| 665 | { | ||
| 666 | /* digital compressed output */ | ||
| 667 | .formats = SNDRV_PCM_FMTBIT_COMPRESSED_16BE, | ||
| 668 | .rates = SNDRV_PCM_RATE_32000 | | ||
| 669 | SNDRV_PCM_RATE_44100 | | ||
| 670 | SNDRV_PCM_RATE_48000, | ||
| 671 | .tag = 2, | ||
| 672 | }, | ||
| 673 | #endif | ||
| 674 | {} | ||
| 675 | }; | ||
| 676 | |||
| 677 | static int onyx_usable(struct codec_info_item *cii, | ||
| 678 | struct transfer_info *ti, | ||
| 679 | struct transfer_info *out) | ||
| 680 | { | ||
| 681 | u8 v; | ||
| 682 | struct onyx *onyx = cii->codec_data; | ||
| 683 | int spdif_enabled, analog_enabled; | ||
| 684 | |||
| 685 | mutex_lock(&onyx->mutex); | ||
| 686 | onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); | ||
| 687 | spdif_enabled = !!(v & ONYX_SPDIF_ENABLE); | ||
| 688 | onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v); | ||
| 689 | analog_enabled = | ||
| 690 | (v & (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT)) | ||
| 691 | != (ONYX_MUTE_RIGHT|ONYX_MUTE_LEFT); | ||
| 692 | mutex_unlock(&onyx->mutex); | ||
| 693 | |||
| 694 | switch (ti->tag) { | ||
| 695 | case 0: return 1; | ||
| 696 | case 1: return analog_enabled; | ||
| 697 | case 2: return spdif_enabled; | ||
| 698 | } | ||
| 699 | return 1; | ||
| 700 | } | ||
| 701 | |||
| 702 | static int onyx_prepare(struct codec_info_item *cii, | ||
| 703 | struct bus_info *bi, | ||
| 704 | struct snd_pcm_substream *substream) | ||
| 705 | { | ||
| 706 | u8 v; | ||
| 707 | struct onyx *onyx = cii->codec_data; | ||
| 708 | int err = -EBUSY; | ||
| 709 | |||
| 710 | mutex_lock(&onyx->mutex); | ||
| 711 | |||
| 712 | #ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE | ||
| 713 | if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) { | ||
| 714 | /* mute and lock analog output */ | ||
| 715 | onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v); | ||
| 716 | if (onyx_write_register(onyx | ||
| 717 | ONYX_REG_DAC_CONTROL, | ||
| 718 | v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT)) | ||
| 719 | goto out_unlock; | ||
| 720 | onyx->analog_locked = 1; | ||
| 721 | err = 0; | ||
| 722 | goto out_unlock; | ||
| 723 | } | ||
| 724 | #endif | ||
| 725 | switch (substream->runtime->rate) { | ||
| 726 | case 32000: | ||
| 727 | case 44100: | ||
| 728 | case 48000: | ||
| 729 | /* these rates are ok for all outputs */ | ||
| 730 | /* FIXME: program spdif channel control bits here so that | ||
| 731 | * userspace doesn't have to if it only plays pcm! */ | ||
| 732 | err = 0; | ||
| 733 | goto out_unlock; | ||
| 734 | default: | ||
| 735 | /* got some rate that the digital output can't do, | ||
| 736 | * so disable and lock it */ | ||
| 737 | onyx_read_register(cii->codec_data, ONYX_REG_DIG_INFO4, &v); | ||
| 738 | if (onyx_write_register(onyx, | ||
| 739 | ONYX_REG_DIG_INFO4, | ||
| 740 | v & ~ONYX_SPDIF_ENABLE)) | ||
| 741 | goto out_unlock; | ||
| 742 | onyx->spdif_locked = 1; | ||
| 743 | err = 0; | ||
| 744 | goto out_unlock; | ||
| 745 | } | ||
| 746 | |||
| 747 | out_unlock: | ||
| 748 | mutex_unlock(&onyx->mutex); | ||
| 749 | |||
| 750 | return err; | ||
| 751 | } | ||
| 752 | |||
| 753 | static int onyx_open(struct codec_info_item *cii, | ||
| 754 | struct snd_pcm_substream *substream) | ||
| 755 | { | ||
| 756 | struct onyx *onyx = cii->codec_data; | ||
| 757 | |||
| 758 | mutex_lock(&onyx->mutex); | ||
| 759 | onyx->open_count++; | ||
| 760 | mutex_unlock(&onyx->mutex); | ||
| 761 | |||
| 762 | return 0; | ||
| 763 | } | ||
| 764 | |||
| 765 | static int onyx_close(struct codec_info_item *cii, | ||
| 766 | struct snd_pcm_substream *substream) | ||
| 767 | { | ||
| 768 | struct onyx *onyx = cii->codec_data; | ||
| 769 | |||
| 770 | mutex_lock(&onyx->mutex); | ||
| 771 | onyx->open_count--; | ||
| 772 | if (!onyx->open_count) | ||
| 773 | onyx->spdif_locked = onyx->analog_locked = 0; | ||
| 774 | mutex_unlock(&onyx->mutex); | ||
| 775 | |||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | |||
| 779 | static int onyx_switch_clock(struct codec_info_item *cii, | ||
| 780 | enum clock_switch what) | ||
| 781 | { | ||
| 782 | struct onyx *onyx = cii->codec_data; | ||
| 783 | |||
| 784 | mutex_lock(&onyx->mutex); | ||
| 785 | /* this *MUST* be more elaborate later... */ | ||
| 786 | switch (what) { | ||
| 787 | case CLOCK_SWITCH_PREPARE_SLAVE: | ||
| 788 | onyx->codec.gpio->methods->all_amps_off(onyx->codec.gpio); | ||
| 789 | break; | ||
| 790 | case CLOCK_SWITCH_SLAVE: | ||
| 791 | onyx->codec.gpio->methods->all_amps_restore(onyx->codec.gpio); | ||
| 792 | break; | ||
| 793 | default: /* silence warning */ | ||
| 794 | break; | ||
| 795 | } | ||
| 796 | mutex_unlock(&onyx->mutex); | ||
| 797 | |||
| 798 | return 0; | ||
| 799 | } | ||
| 800 | |||
| 801 | #ifdef CONFIG_PM | ||
| 802 | |||
| 803 | static int onyx_suspend(struct codec_info_item *cii, pm_message_t state) | ||
| 804 | { | ||
| 805 | struct onyx *onyx = cii->codec_data; | ||
| 806 | u8 v; | ||
| 807 | int err = -ENXIO; | ||
| 808 | |||
| 809 | mutex_lock(&onyx->mutex); | ||
| 810 | if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v)) | ||
| 811 | goto out_unlock; | ||
| 812 | onyx_write_register(onyx, ONYX_REG_CONTROL, v | ONYX_ADPSV | ONYX_DAPSV); | ||
| 813 | /* Apple does a sleep here but the datasheet says to do it on resume */ | ||
| 814 | err = 0; | ||
| 815 | out_unlock: | ||
| 816 | mutex_unlock(&onyx->mutex); | ||
| 817 | |||
| 818 | return err; | ||
| 819 | } | ||
| 820 | |||
| 821 | static int onyx_resume(struct codec_info_item *cii) | ||
| 822 | { | ||
| 823 | struct onyx *onyx = cii->codec_data; | ||
| 824 | u8 v; | ||
| 825 | int err = -ENXIO; | ||
| 826 | |||
| 827 | mutex_lock(&onyx->mutex); | ||
| 828 | /* take codec out of suspend */ | ||
| 829 | if (onyx_read_register(onyx, ONYX_REG_CONTROL, &v)) | ||
| 830 | goto out_unlock; | ||
| 831 | onyx_write_register(onyx, ONYX_REG_CONTROL, v & ~(ONYX_ADPSV | ONYX_DAPSV)); | ||
| 832 | /* FIXME: should divide by sample rate, but 8k is the lowest we go */ | ||
| 833 | msleep(2205000/8000); | ||
| 834 | /* reset all values */ | ||
| 835 | onyx_register_init(onyx); | ||
| 836 | err = 0; | ||
| 837 | out_unlock: | ||
| 838 | mutex_unlock(&onyx->mutex); | ||
| 839 | |||
| 840 | return err; | ||
| 841 | } | ||
| 842 | |||
| 843 | #endif /* CONFIG_PM */ | ||
| 844 | |||
| 845 | static struct codec_info onyx_codec_info = { | ||
| 846 | .transfers = onyx_transfers, | ||
| 847 | .sysclock_factor = 256, | ||
| 848 | .bus_factor = 64, | ||
| 849 | .owner = THIS_MODULE, | ||
| 850 | .usable = onyx_usable, | ||
| 851 | .prepare = onyx_prepare, | ||
| 852 | .open = onyx_open, | ||
| 853 | .close = onyx_close, | ||
| 854 | .switch_clock = onyx_switch_clock, | ||
| 855 | #ifdef CONFIG_PM | ||
| 856 | .suspend = onyx_suspend, | ||
| 857 | .resume = onyx_resume, | ||
| 858 | #endif | ||
| 859 | }; | ||
| 860 | |||
| 861 | static int onyx_init_codec(struct aoa_codec *codec) | ||
| 862 | { | ||
| 863 | struct onyx *onyx = codec_to_onyx(codec); | ||
| 864 | struct snd_kcontrol *ctl; | ||
| 865 | struct codec_info *ci = &onyx_codec_info; | ||
| 866 | u8 v; | ||
| 867 | int err; | ||
| 868 | |||
| 869 | if (!onyx->codec.gpio || !onyx->codec.gpio->methods) { | ||
| 870 | printk(KERN_ERR PFX "gpios not assigned!!\n"); | ||
| 871 | return -EINVAL; | ||
| 872 | } | ||
| 873 | |||
| 874 | onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); | ||
| 875 | msleep(1); | ||
| 876 | onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 1); | ||
| 877 | msleep(1); | ||
| 878 | onyx->codec.gpio->methods->set_hw_reset(onyx->codec.gpio, 0); | ||
| 879 | msleep(1); | ||
| 880 | |||
| 881 | if (onyx_register_init(onyx)) { | ||
| 882 | printk(KERN_ERR PFX "failed to initialise onyx registers\n"); | ||
| 883 | return -ENODEV; | ||
| 884 | } | ||
| 885 | |||
| 886 | if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, onyx, &ops)) { | ||
| 887 | printk(KERN_ERR PFX "failed to create onyx snd device!\n"); | ||
| 888 | return -ENODEV; | ||
| 889 | } | ||
| 890 | |||
| 891 | /* nothing connected? what a joke! */ | ||
| 892 | if ((onyx->codec.connected & 0xF) == 0) | ||
| 893 | return -ENOTCONN; | ||
| 894 | |||
| 895 | /* if no inputs are present... */ | ||
| 896 | if ((onyx->codec.connected & 0xC) == 0) { | ||
| 897 | if (!onyx->codec_info) | ||
| 898 | onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL); | ||
| 899 | if (!onyx->codec_info) | ||
| 900 | return -ENOMEM; | ||
| 901 | ci = onyx->codec_info; | ||
| 902 | *ci = onyx_codec_info; | ||
| 903 | ci->transfers++; | ||
| 904 | } | ||
| 905 | |||
| 906 | /* if no outputs are present... */ | ||
| 907 | if ((onyx->codec.connected & 3) == 0) { | ||
| 908 | if (!onyx->codec_info) | ||
| 909 | onyx->codec_info = kmalloc(sizeof(struct codec_info), GFP_KERNEL); | ||
| 910 | if (!onyx->codec_info) | ||
| 911 | return -ENOMEM; | ||
| 912 | ci = onyx->codec_info; | ||
| 913 | /* this is fine as there have to be inputs | ||
| 914 | * if we end up in this part of the code */ | ||
| 915 | *ci = onyx_codec_info; | ||
| 916 | ci->transfers[1].formats = 0; | ||
| 917 | } | ||
| 918 | |||
| 919 | if (onyx->codec.soundbus_dev->attach_codec(onyx->codec.soundbus_dev, | ||
| 920 | aoa_get_card(), | ||
| 921 | ci, onyx)) { | ||
| 922 | printk(KERN_ERR PFX "error creating onyx pcm\n"); | ||
| 923 | return -ENODEV; | ||
| 924 | } | ||
| 925 | #define ADDCTL(n) \ | ||
| 926 | do { \ | ||
| 927 | ctl = snd_ctl_new1(&n, onyx); \ | ||
| 928 | if (ctl) { \ | ||
| 929 | ctl->id.device = \ | ||
| 930 | onyx->codec.soundbus_dev->pcm->device; \ | ||
| 931 | err = aoa_snd_ctl_add(ctl); \ | ||
| 932 | if (err) \ | ||
| 933 | goto error; \ | ||
| 934 | } \ | ||
| 935 | } while (0) | ||
| 936 | |||
| 937 | if (onyx->codec.soundbus_dev->pcm) { | ||
| 938 | /* give the user appropriate controls | ||
| 939 | * depending on what inputs are connected */ | ||
| 940 | if ((onyx->codec.connected & 0xC) == 0xC) | ||
| 941 | ADDCTL(capture_source_control); | ||
| 942 | else if (onyx->codec.connected & 4) | ||
| 943 | onyx_set_capture_source(onyx, 0); | ||
| 944 | else | ||
| 945 | onyx_set_capture_source(onyx, 1); | ||
| 946 | if (onyx->codec.connected & 0xC) | ||
| 947 | ADDCTL(inputgain_control); | ||
| 948 | |||
| 949 | /* depending on what output is connected, | ||
| 950 | * give the user appropriate controls */ | ||
| 951 | if (onyx->codec.connected & 1) { | ||
| 952 | ADDCTL(volume_control); | ||
| 953 | ADDCTL(mute_control); | ||
| 954 | ADDCTL(ovr1_control); | ||
| 955 | ADDCTL(flt0_control); | ||
| 956 | ADDCTL(hpf_control); | ||
| 957 | ADDCTL(dm12_control); | ||
| 958 | /* spdif control defaults to off */ | ||
| 959 | } | ||
| 960 | if (onyx->codec.connected & 2) { | ||
| 961 | ADDCTL(onyx_spdif_mask); | ||
| 962 | ADDCTL(onyx_spdif_ctrl); | ||
| 963 | } | ||
| 964 | if ((onyx->codec.connected & 3) == 3) | ||
| 965 | ADDCTL(spdif_control); | ||
| 966 | /* if only S/PDIF is connected, enable it unconditionally */ | ||
| 967 | if ((onyx->codec.connected & 3) == 2) { | ||
| 968 | onyx_read_register(onyx, ONYX_REG_DIG_INFO4, &v); | ||
| 969 | v |= ONYX_SPDIF_ENABLE; | ||
| 970 | onyx_write_register(onyx, ONYX_REG_DIG_INFO4, v); | ||
| 971 | } | ||
| 972 | } | ||
| 973 | #undef ADDCTL | ||
| 974 | printk(KERN_INFO PFX "attached to onyx codec via i2c\n"); | ||
| 975 | |||
| 976 | return 0; | ||
| 977 | error: | ||
| 978 | onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx); | ||
| 979 | snd_device_free(aoa_get_card(), onyx); | ||
| 980 | return err; | ||
| 981 | } | ||
| 982 | |||
| 983 | static void onyx_exit_codec(struct aoa_codec *codec) | ||
| 984 | { | ||
| 985 | struct onyx *onyx = codec_to_onyx(codec); | ||
| 986 | |||
| 987 | if (!onyx->codec.soundbus_dev) { | ||
| 988 | printk(KERN_ERR PFX "onyx_exit_codec called without soundbus_dev!\n"); | ||
| 989 | return; | ||
| 990 | } | ||
| 991 | onyx->codec.soundbus_dev->detach_codec(onyx->codec.soundbus_dev, onyx); | ||
| 992 | } | ||
| 993 | |||
| 994 | static struct i2c_driver onyx_driver; | ||
| 995 | |||
| 996 | static int onyx_create(struct i2c_adapter *adapter, | ||
| 997 | struct device_node *node, | ||
| 998 | int addr) | ||
| 999 | { | ||
| 1000 | struct onyx *onyx; | ||
| 1001 | u8 dummy; | ||
| 1002 | |||
| 1003 | onyx = kzalloc(sizeof(struct onyx), GFP_KERNEL); | ||
| 1004 | |||
| 1005 | if (!onyx) | ||
| 1006 | return -ENOMEM; | ||
| 1007 | |||
| 1008 | mutex_init(&onyx->mutex); | ||
| 1009 | onyx->i2c.driver = &onyx_driver; | ||
| 1010 | onyx->i2c.adapter = adapter; | ||
| 1011 | onyx->i2c.addr = addr & 0x7f; | ||
| 1012 | strlcpy(onyx->i2c.name, "onyx audio codec", I2C_NAME_SIZE-1); | ||
| 1013 | |||
| 1014 | if (i2c_attach_client(&onyx->i2c)) { | ||
| 1015 | printk(KERN_ERR PFX "failed to attach to i2c\n"); | ||
| 1016 | goto fail; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | /* we try to read from register ONYX_REG_CONTROL | ||
| 1020 | * to check if the codec is present */ | ||
| 1021 | if (onyx_read_register(onyx, ONYX_REG_CONTROL, &dummy) != 0) { | ||
| 1022 | i2c_detach_client(&onyx->i2c); | ||
| 1023 | printk(KERN_ERR PFX "failed to read control register\n"); | ||
| 1024 | goto fail; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | strlcpy(onyx->codec.name, "onyx", MAX_CODEC_NAME_LEN-1); | ||
| 1028 | onyx->codec.owner = THIS_MODULE; | ||
| 1029 | onyx->codec.init = onyx_init_codec; | ||
| 1030 | onyx->codec.exit = onyx_exit_codec; | ||
| 1031 | onyx->codec.node = of_node_get(node); | ||
| 1032 | |||
| 1033 | if (aoa_codec_register(&onyx->codec)) { | ||
| 1034 | i2c_detach_client(&onyx->i2c); | ||
| 1035 | goto fail; | ||
| 1036 | } | ||
| 1037 | printk(KERN_DEBUG PFX "created and attached onyx instance\n"); | ||
| 1038 | return 0; | ||
| 1039 | fail: | ||
| 1040 | kfree(onyx); | ||
| 1041 | return -EINVAL; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | static int onyx_i2c_attach(struct i2c_adapter *adapter) | ||
| 1045 | { | ||
| 1046 | struct device_node *busnode, *dev = NULL; | ||
| 1047 | struct pmac_i2c_bus *bus; | ||
| 1048 | |||
| 1049 | bus = pmac_i2c_adapter_to_bus(adapter); | ||
| 1050 | if (bus == NULL) | ||
| 1051 | return -ENODEV; | ||
| 1052 | busnode = pmac_i2c_get_bus_node(bus); | ||
| 1053 | |||
| 1054 | while ((dev = of_get_next_child(busnode, dev)) != NULL) { | ||
| 1055 | if (device_is_compatible(dev, "pcm3052")) { | ||
| 1056 | u32 *addr; | ||
| 1057 | printk(KERN_DEBUG PFX "found pcm3052\n"); | ||
| 1058 | addr = (u32 *) get_property(dev, "reg", NULL); | ||
| 1059 | if (!addr) | ||
| 1060 | return -ENODEV; | ||
| 1061 | return onyx_create(adapter, dev, (*addr)>>1); | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | /* if that didn't work, try desperate mode for older | ||
| 1066 | * machines that have stuff missing from the device tree */ | ||
| 1067 | |||
| 1068 | if (!device_is_compatible(busnode, "k2-i2c")) | ||
| 1069 | return -ENODEV; | ||
| 1070 | |||
| 1071 | printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n"); | ||
| 1072 | /* probe both possible addresses for the onyx chip */ | ||
| 1073 | if (onyx_create(adapter, NULL, 0x46) == 0) | ||
| 1074 | return 0; | ||
| 1075 | return onyx_create(adapter, NULL, 0x47); | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | static int onyx_i2c_detach(struct i2c_client *client) | ||
| 1079 | { | ||
| 1080 | struct onyx *onyx = container_of(client, struct onyx, i2c); | ||
| 1081 | int err; | ||
| 1082 | |||
| 1083 | if ((err = i2c_detach_client(client))) | ||
| 1084 | return err; | ||
| 1085 | aoa_codec_unregister(&onyx->codec); | ||
| 1086 | of_node_put(onyx->codec.node); | ||
| 1087 | if (onyx->codec_info) | ||
| 1088 | kfree(onyx->codec_info); | ||
| 1089 | kfree(onyx); | ||
| 1090 | return 0; | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | static struct i2c_driver onyx_driver = { | ||
| 1094 | .driver = { | ||
| 1095 | .name = "aoa_codec_onyx", | ||
| 1096 | .owner = THIS_MODULE, | ||
| 1097 | }, | ||
| 1098 | .attach_adapter = onyx_i2c_attach, | ||
| 1099 | .detach_client = onyx_i2c_detach, | ||
| 1100 | }; | ||
| 1101 | |||
| 1102 | static int __init onyx_init(void) | ||
| 1103 | { | ||
| 1104 | return i2c_add_driver(&onyx_driver); | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | static void __exit onyx_exit(void) | ||
| 1108 | { | ||
| 1109 | i2c_del_driver(&onyx_driver); | ||
| 1110 | } | ||
| 1111 | |||
| 1112 | module_init(onyx_init); | ||
| 1113 | module_exit(onyx_exit); | ||
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.h b/sound/aoa/codecs/snd-aoa-codec-onyx.h new file mode 100644 index 000000000000..aeedda773699 --- /dev/null +++ b/sound/aoa/codecs/snd-aoa-codec-onyx.h | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio driver for Onyx codec (header) | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | #ifndef __SND_AOA_CODEC_ONYX_H | ||
| 9 | #define __SND_AOA_CODEC_ONYX_H | ||
| 10 | #include <stddef.h> | ||
| 11 | #include <linux/i2c.h> | ||
| 12 | #include <linux/i2c-dev.h> | ||
| 13 | #include <asm/pmac_low_i2c.h> | ||
| 14 | #include <asm/prom.h> | ||
| 15 | |||
| 16 | /* PCM3052 register definitions */ | ||
| 17 | |||
| 18 | /* the attenuation registers take values from | ||
| 19 | * -1 (0dB) to -127 (-63.0 dB) or others (muted) */ | ||
| 20 | #define ONYX_REG_DAC_ATTEN_LEFT 65 | ||
| 21 | #define FIRSTREGISTER ONYX_REG_DAC_ATTEN_LEFT | ||
| 22 | #define ONYX_REG_DAC_ATTEN_RIGHT 66 | ||
| 23 | |||
| 24 | #define ONYX_REG_CONTROL 67 | ||
| 25 | # define ONYX_MRST (1<<7) | ||
| 26 | # define ONYX_SRST (1<<6) | ||
| 27 | # define ONYX_ADPSV (1<<5) | ||
| 28 | # define ONYX_DAPSV (1<<4) | ||
| 29 | # define ONYX_SILICONVERSION (1<<0) | ||
| 30 | /* all others reserved */ | ||
| 31 | |||
| 32 | #define ONYX_REG_DAC_CONTROL 68 | ||
| 33 | # define ONYX_OVR1 (1<<6) | ||
| 34 | # define ONYX_MUTE_RIGHT (1<<1) | ||
| 35 | # define ONYX_MUTE_LEFT (1<<0) | ||
| 36 | |||
| 37 | #define ONYX_REG_DAC_DEEMPH 69 | ||
| 38 | # define ONYX_DIGDEEMPH_SHIFT 5 | ||
| 39 | # define ONYX_DIGDEEMPH_MASK (3<<ONYX_DIGDEEMPH_SHIFT) | ||
| 40 | # define ONYX_DIGDEEMPH_CTRL (1<<4) | ||
| 41 | |||
| 42 | #define ONYX_REG_DAC_FILTER 70 | ||
| 43 | # define ONYX_ROLLOFF_FAST (1<<5) | ||
| 44 | # define ONYX_DAC_FILTER_ALWAYS (1<<2) | ||
| 45 | |||
| 46 | #define ONYX_REG_DAC_OUTPHASE 71 | ||
| 47 | # define ONYX_OUTPHASE_INVERTED (1<<0) | ||
| 48 | |||
| 49 | #define ONYX_REG_ADC_CONTROL 72 | ||
| 50 | # define ONYX_ADC_INPUT_MIC (1<<5) | ||
| 51 | /* 8 + input gain in dB, valid range for input gain is -4 .. 20 dB */ | ||
| 52 | # define ONYX_ADC_PGA_GAIN_MASK 0x1f | ||
| 53 | |||
| 54 | #define ONYX_REG_ADC_HPF_BYPASS 75 | ||
| 55 | # define ONYX_HPF_DISABLE (1<<3) | ||
| 56 | # define ONYX_ADC_HPF_ALWAYS (1<<2) | ||
| 57 | |||
| 58 | #define ONYX_REG_DIG_INFO1 77 | ||
| 59 | # define ONYX_MASK_DIN_TO_BPZ (1<<7) | ||
| 60 | /* bits 1-5 control channel bits 1-5 */ | ||
| 61 | # define ONYX_DIGOUT_DISABLE (1<<0) | ||
| 62 | |||
| 63 | #define ONYX_REG_DIG_INFO2 78 | ||
| 64 | /* controls channel bits 8-15 */ | ||
| 65 | |||
| 66 | #define ONYX_REG_DIG_INFO3 79 | ||
| 67 | /* control channel bits 24-29, high 2 bits reserved */ | ||
| 68 | |||
| 69 | #define ONYX_REG_DIG_INFO4 80 | ||
| 70 | # define ONYX_VALIDL (1<<7) | ||
| 71 | # define ONYX_VALIDR (1<<6) | ||
| 72 | # define ONYX_SPDIF_ENABLE (1<<5) | ||
| 73 | /* lower 4 bits control bits 32-35 of channel control and word length */ | ||
| 74 | # define ONYX_WORDLEN_MASK (0xF) | ||
| 75 | |||
| 76 | #endif /* __SND_AOA_CODEC_ONYX_H */ | ||
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h b/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h new file mode 100644 index 000000000000..4cfa6757715e --- /dev/null +++ b/sound/aoa/codecs/snd-aoa-codec-tas-gain-table.h | |||
| @@ -0,0 +1,209 @@ | |||
| 1 | /* | ||
| 2 | This is the program used to generate below table. | ||
| 3 | |||
| 4 | #include <stdio.h> | ||
| 5 | #include <math.h> | ||
| 6 | int main() { | ||
| 7 | int dB2; | ||
| 8 | printf("/" "* This file is only included exactly once!\n"); | ||
| 9 | printf(" *\n"); | ||
| 10 | printf(" * If they'd only tell us that generating this table was\n"); | ||
| 11 | printf(" * as easy as calculating\n"); | ||
| 12 | printf(" * hwvalue = 1048576.0*exp(0.057564628*dB*2)\n"); | ||
| 13 | printf(" * :) *" "/\n"); | ||
| 14 | printf("static int tas_gaintable[] = {\n"); | ||
| 15 | printf(" 0x000000, /" "* -infinity dB *" "/\n"); | ||
| 16 | for (dB2=-140;dB2<=36;dB2++) | ||
| 17 | printf(" 0x%.6x, /" "* %-02.1f dB *" "/\n", (int)(1048576.0*exp(0.057564628*dB2)), dB2/2.0); | ||
| 18 | printf("};\n\n"); | ||
| 19 | } | ||
| 20 | |||
| 21 | */ | ||
| 22 | |||
| 23 | /* This file is only included exactly once! | ||
| 24 | * | ||
| 25 | * If they'd only tell us that generating this table was | ||
| 26 | * as easy as calculating | ||
| 27 | * hwvalue = 1048576.0*exp(0.057564628*dB*2) | ||
| 28 | * :) */ | ||
| 29 | static int tas_gaintable[] = { | ||
| 30 | 0x000000, /* -infinity dB */ | ||
| 31 | 0x00014b, /* -70.0 dB */ | ||
| 32 | 0x00015f, /* -69.5 dB */ | ||
| 33 | 0x000174, /* -69.0 dB */ | ||
| 34 | 0x00018a, /* -68.5 dB */ | ||
| 35 | 0x0001a1, /* -68.0 dB */ | ||
| 36 | 0x0001ba, /* -67.5 dB */ | ||
| 37 | 0x0001d4, /* -67.0 dB */ | ||
| 38 | 0x0001f0, /* -66.5 dB */ | ||
| 39 | 0x00020d, /* -66.0 dB */ | ||
| 40 | 0x00022c, /* -65.5 dB */ | ||
| 41 | 0x00024d, /* -65.0 dB */ | ||
| 42 | 0x000270, /* -64.5 dB */ | ||
| 43 | 0x000295, /* -64.0 dB */ | ||
| 44 | 0x0002bc, /* -63.5 dB */ | ||
| 45 | 0x0002e6, /* -63.0 dB */ | ||
| 46 | 0x000312, /* -62.5 dB */ | ||
| 47 | 0x000340, /* -62.0 dB */ | ||
| 48 | 0x000372, /* -61.5 dB */ | ||
| 49 | 0x0003a6, /* -61.0 dB */ | ||
| 50 | 0x0003dd, /* -60.5 dB */ | ||
| 51 | 0x000418, /* -60.0 dB */ | ||
| 52 | 0x000456, /* -59.5 dB */ | ||
| 53 | 0x000498, /* -59.0 dB */ | ||
| 54 | 0x0004de, /* -58.5 dB */ | ||
| 55 | 0x000528, /* -58.0 dB */ | ||
| 56 | 0x000576, /* -57.5 dB */ | ||
| 57 | 0x0005c9, /* -57.0 dB */ | ||
| 58 | 0x000620, /* -56.5 dB */ | ||
| 59 | 0x00067d, /* -56.0 dB */ | ||
| 60 | 0x0006e0, /* -55.5 dB */ | ||
| 61 | 0x000748, /* -55.0 dB */ | ||
| 62 | 0x0007b7, /* -54.5 dB */ | ||
| 63 | 0x00082c, /* -54.0 dB */ | ||
| 64 | 0x0008a8, /* -53.5 dB */ | ||
| 65 | 0x00092b, /* -53.0 dB */ | ||
| 66 | 0x0009b6, /* -52.5 dB */ | ||
| 67 | 0x000a49, /* -52.0 dB */ | ||
| 68 | 0x000ae5, /* -51.5 dB */ | ||
| 69 | 0x000b8b, /* -51.0 dB */ | ||
| 70 | 0x000c3a, /* -50.5 dB */ | ||
| 71 | 0x000cf3, /* -50.0 dB */ | ||
| 72 | 0x000db8, /* -49.5 dB */ | ||
| 73 | 0x000e88, /* -49.0 dB */ | ||
| 74 | 0x000f64, /* -48.5 dB */ | ||
| 75 | 0x00104e, /* -48.0 dB */ | ||
| 76 | 0x001145, /* -47.5 dB */ | ||
| 77 | 0x00124b, /* -47.0 dB */ | ||
| 78 | 0x001361, /* -46.5 dB */ | ||
| 79 | 0x001487, /* -46.0 dB */ | ||
| 80 | 0x0015be, /* -45.5 dB */ | ||
| 81 | 0x001708, /* -45.0 dB */ | ||
| 82 | 0x001865, /* -44.5 dB */ | ||
| 83 | 0x0019d8, /* -44.0 dB */ | ||
| 84 | 0x001b60, /* -43.5 dB */ | ||
| 85 | 0x001cff, /* -43.0 dB */ | ||
| 86 | 0x001eb7, /* -42.5 dB */ | ||
| 87 | 0x002089, /* -42.0 dB */ | ||
| 88 | 0x002276, /* -41.5 dB */ | ||
| 89 | 0x002481, /* -41.0 dB */ | ||
| 90 | 0x0026ab, /* -40.5 dB */ | ||
| 91 | 0x0028f5, /* -40.0 dB */ | ||
| 92 | 0x002b63, /* -39.5 dB */ | ||
| 93 | 0x002df5, /* -39.0 dB */ | ||
| 94 | 0x0030ae, /* -38.5 dB */ | ||
| 95 | 0x003390, /* -38.0 dB */ | ||
| 96 | 0x00369e, /* -37.5 dB */ | ||
| 97 | 0x0039db, /* -37.0 dB */ | ||
| 98 | 0x003d49, /* -36.5 dB */ | ||
| 99 | 0x0040ea, /* -36.0 dB */ | ||
| 100 | 0x0044c3, /* -35.5 dB */ | ||
| 101 | 0x0048d6, /* -35.0 dB */ | ||
| 102 | 0x004d27, /* -34.5 dB */ | ||
| 103 | 0x0051b9, /* -34.0 dB */ | ||
| 104 | 0x005691, /* -33.5 dB */ | ||
| 105 | 0x005bb2, /* -33.0 dB */ | ||
| 106 | 0x006121, /* -32.5 dB */ | ||
| 107 | 0x0066e3, /* -32.0 dB */ | ||
| 108 | 0x006cfb, /* -31.5 dB */ | ||
| 109 | 0x007370, /* -31.0 dB */ | ||
| 110 | 0x007a48, /* -30.5 dB */ | ||
| 111 | 0x008186, /* -30.0 dB */ | ||
| 112 | 0x008933, /* -29.5 dB */ | ||
| 113 | 0x009154, /* -29.0 dB */ | ||
| 114 | 0x0099f1, /* -28.5 dB */ | ||
| 115 | 0x00a310, /* -28.0 dB */ | ||
| 116 | 0x00acba, /* -27.5 dB */ | ||
| 117 | 0x00b6f6, /* -27.0 dB */ | ||
| 118 | 0x00c1cd, /* -26.5 dB */ | ||
| 119 | 0x00cd49, /* -26.0 dB */ | ||
| 120 | 0x00d973, /* -25.5 dB */ | ||
| 121 | 0x00e655, /* -25.0 dB */ | ||
| 122 | 0x00f3fb, /* -24.5 dB */ | ||
| 123 | 0x010270, /* -24.0 dB */ | ||
| 124 | 0x0111c0, /* -23.5 dB */ | ||
| 125 | 0x0121f9, /* -23.0 dB */ | ||
| 126 | 0x013328, /* -22.5 dB */ | ||
| 127 | 0x01455b, /* -22.0 dB */ | ||
| 128 | 0x0158a2, /* -21.5 dB */ | ||
| 129 | 0x016d0e, /* -21.0 dB */ | ||
| 130 | 0x0182af, /* -20.5 dB */ | ||
| 131 | 0x019999, /* -20.0 dB */ | ||
| 132 | 0x01b1de, /* -19.5 dB */ | ||
| 133 | 0x01cb94, /* -19.0 dB */ | ||
| 134 | 0x01e6cf, /* -18.5 dB */ | ||
| 135 | 0x0203a7, /* -18.0 dB */ | ||
| 136 | 0x022235, /* -17.5 dB */ | ||
| 137 | 0x024293, /* -17.0 dB */ | ||
| 138 | 0x0264db, /* -16.5 dB */ | ||
| 139 | 0x02892c, /* -16.0 dB */ | ||
| 140 | 0x02afa3, /* -15.5 dB */ | ||
| 141 | 0x02d862, /* -15.0 dB */ | ||
| 142 | 0x03038a, /* -14.5 dB */ | ||
| 143 | 0x033142, /* -14.0 dB */ | ||
| 144 | 0x0361af, /* -13.5 dB */ | ||
| 145 | 0x0394fa, /* -13.0 dB */ | ||
| 146 | 0x03cb50, /* -12.5 dB */ | ||
| 147 | 0x0404de, /* -12.0 dB */ | ||
| 148 | 0x0441d5, /* -11.5 dB */ | ||
| 149 | 0x048268, /* -11.0 dB */ | ||
| 150 | 0x04c6d0, /* -10.5 dB */ | ||
| 151 | 0x050f44, /* -10.0 dB */ | ||
| 152 | 0x055c04, /* -9.5 dB */ | ||
| 153 | 0x05ad50, /* -9.0 dB */ | ||
| 154 | 0x06036e, /* -8.5 dB */ | ||
| 155 | 0x065ea5, /* -8.0 dB */ | ||
| 156 | 0x06bf44, /* -7.5 dB */ | ||
| 157 | 0x07259d, /* -7.0 dB */ | ||
| 158 | 0x079207, /* -6.5 dB */ | ||
| 159 | 0x0804dc, /* -6.0 dB */ | ||
| 160 | 0x087e80, /* -5.5 dB */ | ||
| 161 | 0x08ff59, /* -5.0 dB */ | ||
| 162 | 0x0987d5, /* -4.5 dB */ | ||
| 163 | 0x0a1866, /* -4.0 dB */ | ||
| 164 | 0x0ab189, /* -3.5 dB */ | ||
| 165 | 0x0b53be, /* -3.0 dB */ | ||
| 166 | 0x0bff91, /* -2.5 dB */ | ||
| 167 | 0x0cb591, /* -2.0 dB */ | ||
| 168 | 0x0d765a, /* -1.5 dB */ | ||
| 169 | 0x0e4290, /* -1.0 dB */ | ||
| 170 | 0x0f1adf, /* -0.5 dB */ | ||
| 171 | 0x100000, /* 0.0 dB */ | ||
| 172 | 0x10f2b4, /* 0.5 dB */ | ||
| 173 | 0x11f3c9, /* 1.0 dB */ | ||
| 174 | 0x13041a, /* 1.5 dB */ | ||
| 175 | 0x14248e, /* 2.0 dB */ | ||
| 176 | 0x15561a, /* 2.5 dB */ | ||
| 177 | 0x1699c0, /* 3.0 dB */ | ||
| 178 | 0x17f094, /* 3.5 dB */ | ||
| 179 | 0x195bb8, /* 4.0 dB */ | ||
| 180 | 0x1adc61, /* 4.5 dB */ | ||
| 181 | 0x1c73d5, /* 5.0 dB */ | ||
| 182 | 0x1e236d, /* 5.5 dB */ | ||
| 183 | 0x1fec98, /* 6.0 dB */ | ||
| 184 | 0x21d0d9, /* 6.5 dB */ | ||
| 185 | 0x23d1cd, /* 7.0 dB */ | ||
| 186 | 0x25f125, /* 7.5 dB */ | ||
| 187 | 0x2830af, /* 8.0 dB */ | ||
| 188 | 0x2a9254, /* 8.5 dB */ | ||
| 189 | 0x2d1818, /* 9.0 dB */ | ||
| 190 | 0x2fc420, /* 9.5 dB */ | ||
| 191 | 0x3298b0, /* 10.0 dB */ | ||
| 192 | 0x35982f, /* 10.5 dB */ | ||
| 193 | 0x38c528, /* 11.0 dB */ | ||
| 194 | 0x3c224c, /* 11.5 dB */ | ||
| 195 | 0x3fb278, /* 12.0 dB */ | ||
| 196 | 0x4378b0, /* 12.5 dB */ | ||
| 197 | 0x477829, /* 13.0 dB */ | ||
| 198 | 0x4bb446, /* 13.5 dB */ | ||
| 199 | 0x5030a1, /* 14.0 dB */ | ||
| 200 | 0x54f106, /* 14.5 dB */ | ||
| 201 | 0x59f980, /* 15.0 dB */ | ||
| 202 | 0x5f4e52, /* 15.5 dB */ | ||
| 203 | 0x64f403, /* 16.0 dB */ | ||
| 204 | 0x6aef5e, /* 16.5 dB */ | ||
| 205 | 0x714575, /* 17.0 dB */ | ||
| 206 | 0x77fbaa, /* 17.5 dB */ | ||
| 207 | 0x7f17af, /* 18.0 dB */ | ||
| 208 | }; | ||
| 209 | |||
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c new file mode 100644 index 000000000000..2e39ff6ee349 --- /dev/null +++ b/sound/aoa/codecs/snd-aoa-codec-tas.c | |||
| @@ -0,0 +1,654 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio driver for tas codec | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | * | ||
| 8 | * Open questions: | ||
| 9 | * - How to distinguish between 3004 and versions? | ||
| 10 | * | ||
| 11 | * FIXMEs: | ||
| 12 | * - This codec driver doesn't honour the 'connected' | ||
| 13 | * property of the aoa_codec struct, hence if | ||
| 14 | * it is used in machines where not everything is | ||
| 15 | * connected it will display wrong mixer elements. | ||
| 16 | * - Driver assumes that the microphone is always | ||
| 17 | * monaureal and connected to the right channel of | ||
| 18 | * the input. This should also be a codec-dependent | ||
| 19 | * flag, maybe the codec should have 3 different | ||
| 20 | * bits for the three different possibilities how | ||
| 21 | * it can be hooked up... | ||
| 22 | * But as long as I don't see any hardware hooked | ||
| 23 | * up that way... | ||
| 24 | * - As Apple notes in their code, the tas3004 seems | ||
| 25 | * to delay the right channel by one sample. You can | ||
| 26 | * see this when for example recording stereo in | ||
| 27 | * audacity, or recording the tas output via cable | ||
| 28 | * on another machine (use a sinus generator or so). | ||
| 29 | * I tried programming the BiQuads but couldn't | ||
| 30 | * make the delay work, maybe someone can read the | ||
| 31 | * datasheet and fix it. The relevant Apple comment | ||
| 32 | * is in AppleTAS3004Audio.cpp lines 1637 ff. Note | ||
| 33 | * that their comment describing how they program | ||
| 34 | * the filters sucks... | ||
| 35 | * | ||
| 36 | * Other things: | ||
| 37 | * - this should actually register *two* aoa_codec | ||
| 38 | * structs since it has two inputs. Then it must | ||
| 39 | * use the prepare callback to forbid running the | ||
| 40 | * secondary output on a different clock. | ||
| 41 | * Also, whatever bus knows how to do this must | ||
| 42 | * provide two soundbus_dev devices and the fabric | ||
| 43 | * must be able to link them correctly. | ||
| 44 | * | ||
| 45 | * I don't even know if Apple ever uses the second | ||
| 46 | * port on the tas3004 though, I don't think their | ||
| 47 | * i2s controllers can even do it. OTOH, they all | ||
| 48 | * derive the clocks from common clocks, so it | ||
| 49 | * might just be possible. The framework allows the | ||
| 50 | * codec to refine the transfer_info items in the | ||
| 51 | * usable callback, so we can simply remove the | ||
| 52 | * rates the second instance is not using when it | ||
| 53 | * actually is in use. | ||
| 54 | * Maybe we'll need to make the sound busses have | ||
| 55 | * a 'clock group id' value so the codec can | ||
| 56 | * determine if the two outputs can be driven at | ||
| 57 | * the same time. But that is likely overkill, up | ||
| 58 | * to the fabric to not link them up incorrectly, | ||
| 59 | * and up to the hardware designer to not wire | ||
| 60 | * them up in some weird unusable way. | ||
| 61 | */ | ||
| 62 | #include <stddef.h> | ||
| 63 | #include <linux/i2c.h> | ||
| 64 | #include <linux/i2c-dev.h> | ||
| 65 | #include <asm/pmac_low_i2c.h> | ||
| 66 | #include <asm/prom.h> | ||
| 67 | #include <linux/delay.h> | ||
| 68 | #include <linux/module.h> | ||
| 69 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
| 70 | MODULE_LICENSE("GPL"); | ||
| 71 | MODULE_DESCRIPTION("tas codec driver for snd-aoa"); | ||
| 72 | |||
| 73 | #include "snd-aoa-codec-tas.h" | ||
| 74 | #include "snd-aoa-codec-tas-gain-table.h" | ||
| 75 | #include "../aoa.h" | ||
| 76 | #include "../soundbus/soundbus.h" | ||
| 77 | |||
| 78 | |||
| 79 | #define PFX "snd-aoa-codec-tas: " | ||
| 80 | |||
| 81 | struct tas { | ||
| 82 | struct aoa_codec codec; | ||
| 83 | struct i2c_client i2c; | ||
| 84 | u32 muted_l:1, muted_r:1, | ||
| 85 | controls_created:1; | ||
| 86 | u8 cached_volume_l, cached_volume_r; | ||
| 87 | u8 mixer_l[3], mixer_r[3]; | ||
| 88 | u8 acr; | ||
| 89 | }; | ||
| 90 | |||
| 91 | static struct tas *codec_to_tas(struct aoa_codec *codec) | ||
| 92 | { | ||
| 93 | return container_of(codec, struct tas, codec); | ||
| 94 | } | ||
| 95 | |||
| 96 | static inline int tas_write_reg(struct tas *tas, u8 reg, u8 len, u8 *data) | ||
| 97 | { | ||
| 98 | if (len == 1) | ||
| 99 | return i2c_smbus_write_byte_data(&tas->i2c, reg, *data); | ||
| 100 | else | ||
| 101 | return i2c_smbus_write_i2c_block_data(&tas->i2c, reg, len, data); | ||
| 102 | } | ||
| 103 | |||
| 104 | static void tas_set_volume(struct tas *tas) | ||
| 105 | { | ||
| 106 | u8 block[6]; | ||
| 107 | int tmp; | ||
| 108 | u8 left, right; | ||
| 109 | |||
| 110 | left = tas->cached_volume_l; | ||
| 111 | right = tas->cached_volume_r; | ||
| 112 | |||
| 113 | if (left > 177) left = 177; | ||
| 114 | if (right > 177) right = 177; | ||
| 115 | |||
| 116 | if (tas->muted_l) left = 0; | ||
| 117 | if (tas->muted_r) right = 0; | ||
| 118 | |||
| 119 | /* analysing the volume and mixer tables shows | ||
| 120 | * that they are similar enough when we shift | ||
| 121 | * the mixer table down by 4 bits. The error | ||
| 122 | * is miniscule, in just one item the error | ||
| 123 | * is 1, at a value of 0x07f17b (mixer table | ||
| 124 | * value is 0x07f17a) */ | ||
| 125 | tmp = tas_gaintable[left]; | ||
| 126 | block[0] = tmp>>20; | ||
| 127 | block[1] = tmp>>12; | ||
| 128 | block[2] = tmp>>4; | ||
| 129 | tmp = tas_gaintable[right]; | ||
| 130 | block[3] = tmp>>20; | ||
| 131 | block[4] = tmp>>12; | ||
| 132 | block[5] = tmp>>4; | ||
| 133 | tas_write_reg(tas, TAS_REG_VOL, 6, block); | ||
| 134 | } | ||
| 135 | |||
| 136 | static void tas_set_mixer(struct tas *tas) | ||
| 137 | { | ||
| 138 | u8 block[9]; | ||
| 139 | int tmp, i; | ||
| 140 | u8 val; | ||
| 141 | |||
| 142 | for (i=0;i<3;i++) { | ||
| 143 | val = tas->mixer_l[i]; | ||
| 144 | if (val > 177) val = 177; | ||
| 145 | tmp = tas_gaintable[val]; | ||
| 146 | block[3*i+0] = tmp>>16; | ||
| 147 | block[3*i+1] = tmp>>8; | ||
| 148 | block[3*i+2] = tmp; | ||
| 149 | } | ||
| 150 | tas_write_reg(tas, TAS_REG_LMIX, 9, block); | ||
| 151 | |||
| 152 | for (i=0;i<3;i++) { | ||
| 153 | val = tas->mixer_r[i]; | ||
| 154 | if (val > 177) val = 177; | ||
| 155 | tmp = tas_gaintable[val]; | ||
| 156 | block[3*i+0] = tmp>>16; | ||
| 157 | block[3*i+1] = tmp>>8; | ||
| 158 | block[3*i+2] = tmp; | ||
| 159 | } | ||
| 160 | tas_write_reg(tas, TAS_REG_RMIX, 9, block); | ||
| 161 | } | ||
| 162 | |||
| 163 | /* alsa stuff */ | ||
| 164 | |||
| 165 | static int tas_dev_register(struct snd_device *dev) | ||
| 166 | { | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | static struct snd_device_ops ops = { | ||
| 171 | .dev_register = tas_dev_register, | ||
| 172 | }; | ||
| 173 | |||
| 174 | static int tas_snd_vol_info(struct snd_kcontrol *kcontrol, | ||
| 175 | struct snd_ctl_elem_info *uinfo) | ||
| 176 | { | ||
| 177 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 178 | uinfo->count = 2; | ||
| 179 | uinfo->value.integer.min = 0; | ||
| 180 | uinfo->value.integer.max = 177; | ||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | static int tas_snd_vol_get(struct snd_kcontrol *kcontrol, | ||
| 185 | struct snd_ctl_elem_value *ucontrol) | ||
| 186 | { | ||
| 187 | struct tas *tas = snd_kcontrol_chip(kcontrol); | ||
| 188 | |||
| 189 | ucontrol->value.integer.value[0] = tas->cached_volume_l; | ||
| 190 | ucontrol->value.integer.value[1] = tas->cached_volume_r; | ||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | |||
| 194 | static int tas_snd_vol_put(struct snd_kcontrol *kcontrol, | ||
| 195 | struct snd_ctl_elem_value *ucontrol) | ||
| 196 | { | ||
| 197 | struct tas *tas = snd_kcontrol_chip(kcontrol); | ||
| 198 | |||
| 199 | if (tas->cached_volume_l == ucontrol->value.integer.value[0] | ||
| 200 | && tas->cached_volume_r == ucontrol->value.integer.value[1]) | ||
| 201 | return 0; | ||
| 202 | |||
| 203 | tas->cached_volume_l = ucontrol->value.integer.value[0]; | ||
| 204 | tas->cached_volume_r = ucontrol->value.integer.value[1]; | ||
| 205 | tas_set_volume(tas); | ||
| 206 | return 1; | ||
| 207 | } | ||
| 208 | |||
| 209 | static struct snd_kcontrol_new volume_control = { | ||
| 210 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 211 | .name = "Master Playback Volume", | ||
| 212 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 213 | .info = tas_snd_vol_info, | ||
| 214 | .get = tas_snd_vol_get, | ||
| 215 | .put = tas_snd_vol_put, | ||
| 216 | }; | ||
| 217 | |||
| 218 | static int tas_snd_mute_info(struct snd_kcontrol *kcontrol, | ||
| 219 | struct snd_ctl_elem_info *uinfo) | ||
| 220 | { | ||
| 221 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
| 222 | uinfo->count = 2; | ||
| 223 | uinfo->value.integer.min = 0; | ||
| 224 | uinfo->value.integer.max = 1; | ||
| 225 | return 0; | ||
| 226 | } | ||
| 227 | |||
| 228 | static int tas_snd_mute_get(struct snd_kcontrol *kcontrol, | ||
| 229 | struct snd_ctl_elem_value *ucontrol) | ||
| 230 | { | ||
| 231 | struct tas *tas = snd_kcontrol_chip(kcontrol); | ||
| 232 | |||
| 233 | ucontrol->value.integer.value[0] = !tas->muted_l; | ||
| 234 | ucontrol->value.integer.value[1] = !tas->muted_r; | ||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | |||
| 238 | static int tas_snd_mute_put(struct snd_kcontrol *kcontrol, | ||
| 239 | struct snd_ctl_elem_value *ucontrol) | ||
| 240 | { | ||
| 241 | struct tas *tas = snd_kcontrol_chip(kcontrol); | ||
| 242 | |||
| 243 | if (tas->muted_l == !ucontrol->value.integer.value[0] | ||
| 244 | && tas->muted_r == !ucontrol->value.integer.value[1]) | ||
| 245 | return 0; | ||
| 246 | |||
| 247 | tas->muted_l = !ucontrol->value.integer.value[0]; | ||
| 248 | tas->muted_r = !ucontrol->value.integer.value[1]; | ||
| 249 | tas_set_volume(tas); | ||
| 250 | return 1; | ||
| 251 | } | ||
| 252 | |||
| 253 | static struct snd_kcontrol_new mute_control = { | ||
| 254 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 255 | .name = "Master Playback Switch", | ||
| 256 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 257 | .info = tas_snd_mute_info, | ||
| 258 | .get = tas_snd_mute_get, | ||
| 259 | .put = tas_snd_mute_put, | ||
| 260 | }; | ||
| 261 | |||
| 262 | static int tas_snd_mixer_info(struct snd_kcontrol *kcontrol, | ||
| 263 | struct snd_ctl_elem_info *uinfo) | ||
| 264 | { | ||
| 265 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 266 | uinfo->count = 2; | ||
| 267 | uinfo->value.integer.min = 0; | ||
| 268 | uinfo->value.integer.max = 177; | ||
| 269 | return 0; | ||
| 270 | } | ||
| 271 | |||
| 272 | static int tas_snd_mixer_get(struct snd_kcontrol *kcontrol, | ||
| 273 | struct snd_ctl_elem_value *ucontrol) | ||
| 274 | { | ||
| 275 | struct tas *tas = snd_kcontrol_chip(kcontrol); | ||
| 276 | int idx = kcontrol->private_value; | ||
| 277 | |||
| 278 | ucontrol->value.integer.value[0] = tas->mixer_l[idx]; | ||
| 279 | ucontrol->value.integer.value[1] = tas->mixer_r[idx]; | ||
| 280 | |||
| 281 | return 0; | ||
| 282 | } | ||
| 283 | |||
| 284 | static int tas_snd_mixer_put(struct snd_kcontrol *kcontrol, | ||
| 285 | struct snd_ctl_elem_value *ucontrol) | ||
| 286 | { | ||
| 287 | struct tas *tas = snd_kcontrol_chip(kcontrol); | ||
| 288 | int idx = kcontrol->private_value; | ||
| 289 | |||
| 290 | if (tas->mixer_l[idx] == ucontrol->value.integer.value[0] | ||
| 291 | && tas->mixer_r[idx] == ucontrol->value.integer.value[1]) | ||
| 292 | return 0; | ||
| 293 | |||
| 294 | tas->mixer_l[idx] = ucontrol->value.integer.value[0]; | ||
| 295 | tas->mixer_r[idx] = ucontrol->value.integer.value[1]; | ||
| 296 | |||
| 297 | tas_set_mixer(tas); | ||
| 298 | return 1; | ||
| 299 | } | ||
| 300 | |||
| 301 | #define MIXER_CONTROL(n,descr,idx) \ | ||
| 302 | static struct snd_kcontrol_new n##_control = { \ | ||
| 303 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
| 304 | .name = descr " Playback Volume", \ | ||
| 305 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
| 306 | .info = tas_snd_mixer_info, \ | ||
| 307 | .get = tas_snd_mixer_get, \ | ||
| 308 | .put = tas_snd_mixer_put, \ | ||
| 309 | .private_value = idx, \ | ||
| 310 | } | ||
| 311 | |||
| 312 | MIXER_CONTROL(pcm1, "PCM1", 0); | ||
| 313 | MIXER_CONTROL(monitor, "Monitor", 2); | ||
| 314 | |||
| 315 | static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol, | ||
| 316 | struct snd_ctl_elem_info *uinfo) | ||
| 317 | { | ||
| 318 | static char *texts[] = { "Line-In", "Microphone" }; | ||
| 319 | |||
| 320 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 321 | uinfo->count = 1; | ||
| 322 | uinfo->value.enumerated.items = 2; | ||
| 323 | if (uinfo->value.enumerated.item > 1) | ||
| 324 | uinfo->value.enumerated.item = 1; | ||
| 325 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
| 326 | return 0; | ||
| 327 | } | ||
| 328 | |||
| 329 | static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol, | ||
| 330 | struct snd_ctl_elem_value *ucontrol) | ||
| 331 | { | ||
| 332 | struct tas *tas = snd_kcontrol_chip(kcontrol); | ||
| 333 | |||
| 334 | ucontrol->value.enumerated.item[0] = !!(tas->acr & TAS_ACR_INPUT_B); | ||
| 335 | return 0; | ||
| 336 | } | ||
| 337 | |||
| 338 | static int tas_snd_capture_source_put(struct snd_kcontrol *kcontrol, | ||
| 339 | struct snd_ctl_elem_value *ucontrol) | ||
| 340 | { | ||
| 341 | struct tas *tas = snd_kcontrol_chip(kcontrol); | ||
| 342 | int oldacr = tas->acr; | ||
| 343 | |||
| 344 | tas->acr &= ~TAS_ACR_INPUT_B; | ||
| 345 | if (ucontrol->value.enumerated.item[0]) | ||
| 346 | tas->acr |= TAS_ACR_INPUT_B; | ||
| 347 | if (oldacr == tas->acr) | ||
| 348 | return 0; | ||
| 349 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); | ||
| 350 | return 1; | ||
| 351 | } | ||
| 352 | |||
| 353 | static struct snd_kcontrol_new capture_source_control = { | ||
| 354 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 355 | /* If we name this 'Input Source', it properly shows up in | ||
| 356 | * alsamixer as a selection, * but it's shown under the | ||
| 357 | * 'Playback' category. | ||
| 358 | * If I name it 'Capture Source', it shows up in strange | ||
| 359 | * ways (two bools of which one can be selected at a | ||
| 360 | * time) but at least it's shown in the 'Capture' | ||
| 361 | * category. | ||
| 362 | * I was told that this was due to backward compatibility, | ||
| 363 | * but I don't understand then why the mangling is *not* | ||
| 364 | * done when I name it "Input Source"..... | ||
| 365 | */ | ||
| 366 | .name = "Capture Source", | ||
| 367 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 368 | .info = tas_snd_capture_source_info, | ||
| 369 | .get = tas_snd_capture_source_get, | ||
| 370 | .put = tas_snd_capture_source_put, | ||
| 371 | }; | ||
| 372 | |||
| 373 | |||
| 374 | static struct transfer_info tas_transfers[] = { | ||
| 375 | { | ||
| 376 | /* input */ | ||
| 377 | .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE | | ||
| 378 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE, | ||
| 379 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | ||
| 380 | .transfer_in = 1, | ||
| 381 | }, | ||
| 382 | { | ||
| 383 | /* output */ | ||
| 384 | .formats = SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_S16_BE | | ||
| 385 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S24_BE, | ||
| 386 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | ||
| 387 | .transfer_in = 0, | ||
| 388 | }, | ||
| 389 | {} | ||
| 390 | }; | ||
| 391 | |||
| 392 | static int tas_usable(struct codec_info_item *cii, | ||
| 393 | struct transfer_info *ti, | ||
| 394 | struct transfer_info *out) | ||
| 395 | { | ||
| 396 | return 1; | ||
| 397 | } | ||
| 398 | |||
| 399 | static int tas_reset_init(struct tas *tas) | ||
| 400 | { | ||
| 401 | u8 tmp; | ||
| 402 | tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0); | ||
| 403 | msleep(1); | ||
| 404 | tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 1); | ||
| 405 | msleep(1); | ||
| 406 | tas->codec.gpio->methods->set_hw_reset(tas->codec.gpio, 0); | ||
| 407 | msleep(1); | ||
| 408 | |||
| 409 | tas->acr &= ~TAS_ACR_ANALOG_PDOWN; | ||
| 410 | tas->acr |= TAS_ACR_B_MONAUREAL | TAS_ACR_B_MON_SEL_RIGHT; | ||
| 411 | if (tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr)) | ||
| 412 | return -ENODEV; | ||
| 413 | |||
| 414 | tmp = TAS_MCS_SCLK64 | TAS_MCS_SPORT_MODE_I2S | TAS_MCS_SPORT_WL_24BIT; | ||
| 415 | if (tas_write_reg(tas, TAS_REG_MCS, 1, &tmp)) | ||
| 416 | return -ENODEV; | ||
| 417 | |||
| 418 | tmp = 0; | ||
| 419 | if (tas_write_reg(tas, TAS_REG_MCS2, 1, &tmp)) | ||
| 420 | return -ENODEV; | ||
| 421 | |||
| 422 | return 0; | ||
| 423 | } | ||
| 424 | |||
| 425 | /* we are controlled via i2c and assume that is always up | ||
| 426 | * If that wasn't the case, we'd have to suspend once | ||
| 427 | * our i2c device is suspended, and then take note of that! */ | ||
| 428 | static int tas_suspend(struct tas *tas) | ||
| 429 | { | ||
| 430 | tas->acr |= TAS_ACR_ANALOG_PDOWN; | ||
| 431 | tas_write_reg(tas, TAS_REG_ACR, 1, &tas->acr); | ||
| 432 | return 0; | ||
| 433 | } | ||
| 434 | |||
| 435 | static int tas_resume(struct tas *tas) | ||
| 436 | { | ||
| 437 | /* reset codec */ | ||
| 438 | tas_reset_init(tas); | ||
| 439 | tas_set_volume(tas); | ||
| 440 | tas_set_mixer(tas); | ||
| 441 | return 0; | ||
| 442 | } | ||
| 443 | |||
| 444 | #ifdef CONFIG_PM | ||
| 445 | static int _tas_suspend(struct codec_info_item *cii, pm_message_t state) | ||
| 446 | { | ||
| 447 | return tas_suspend(cii->codec_data); | ||
| 448 | } | ||
| 449 | |||
| 450 | static int _tas_resume(struct codec_info_item *cii) | ||
| 451 | { | ||
| 452 | return tas_resume(cii->codec_data); | ||
| 453 | } | ||
| 454 | #endif | ||
| 455 | |||
| 456 | static struct codec_info tas_codec_info = { | ||
| 457 | .transfers = tas_transfers, | ||
| 458 | /* in theory, we can drive it at 512 too... | ||
| 459 | * but so far the framework doesn't allow | ||
| 460 | * for that and I don't see much point in it. */ | ||
| 461 | .sysclock_factor = 256, | ||
| 462 | /* same here, could be 32 for just one 16 bit format */ | ||
| 463 | .bus_factor = 64, | ||
| 464 | .owner = THIS_MODULE, | ||
| 465 | .usable = tas_usable, | ||
| 466 | #ifdef CONFIG_PM | ||
| 467 | .suspend = _tas_suspend, | ||
| 468 | .resume = _tas_resume, | ||
| 469 | #endif | ||
| 470 | }; | ||
| 471 | |||
| 472 | static int tas_init_codec(struct aoa_codec *codec) | ||
| 473 | { | ||
| 474 | struct tas *tas = codec_to_tas(codec); | ||
| 475 | int err; | ||
| 476 | |||
| 477 | if (!tas->codec.gpio || !tas->codec.gpio->methods) { | ||
| 478 | printk(KERN_ERR PFX "gpios not assigned!!\n"); | ||
| 479 | return -EINVAL; | ||
| 480 | } | ||
| 481 | |||
| 482 | if (tas_reset_init(tas)) { | ||
| 483 | printk(KERN_ERR PFX "tas failed to initialise\n"); | ||
| 484 | return -ENXIO; | ||
| 485 | } | ||
| 486 | |||
| 487 | if (tas->codec.soundbus_dev->attach_codec(tas->codec.soundbus_dev, | ||
| 488 | aoa_get_card(), | ||
| 489 | &tas_codec_info, tas)) { | ||
| 490 | printk(KERN_ERR PFX "error attaching tas to soundbus\n"); | ||
| 491 | return -ENODEV; | ||
| 492 | } | ||
| 493 | |||
| 494 | if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, tas, &ops)) { | ||
| 495 | printk(KERN_ERR PFX "failed to create tas snd device!\n"); | ||
| 496 | return -ENODEV; | ||
| 497 | } | ||
| 498 | err = aoa_snd_ctl_add(snd_ctl_new1(&volume_control, tas)); | ||
| 499 | if (err) | ||
| 500 | goto error; | ||
| 501 | |||
| 502 | err = aoa_snd_ctl_add(snd_ctl_new1(&mute_control, tas)); | ||
| 503 | if (err) | ||
| 504 | goto error; | ||
| 505 | |||
| 506 | err = aoa_snd_ctl_add(snd_ctl_new1(&pcm1_control, tas)); | ||
| 507 | if (err) | ||
| 508 | goto error; | ||
| 509 | |||
| 510 | err = aoa_snd_ctl_add(snd_ctl_new1(&monitor_control, tas)); | ||
| 511 | if (err) | ||
| 512 | goto error; | ||
| 513 | |||
| 514 | err = aoa_snd_ctl_add(snd_ctl_new1(&capture_source_control, tas)); | ||
| 515 | if (err) | ||
| 516 | goto error; | ||
| 517 | |||
| 518 | return 0; | ||
| 519 | error: | ||
| 520 | tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas); | ||
| 521 | snd_device_free(aoa_get_card(), tas); | ||
| 522 | return err; | ||
| 523 | } | ||
| 524 | |||
| 525 | static void tas_exit_codec(struct aoa_codec *codec) | ||
| 526 | { | ||
| 527 | struct tas *tas = codec_to_tas(codec); | ||
| 528 | |||
| 529 | if (!tas->codec.soundbus_dev) | ||
| 530 | return; | ||
| 531 | tas->codec.soundbus_dev->detach_codec(tas->codec.soundbus_dev, tas); | ||
| 532 | } | ||
| 533 | |||
| 534 | |||
| 535 | static struct i2c_driver tas_driver; | ||
| 536 | |||
| 537 | static int tas_create(struct i2c_adapter *adapter, | ||
| 538 | struct device_node *node, | ||
| 539 | int addr) | ||
| 540 | { | ||
| 541 | struct tas *tas; | ||
| 542 | |||
| 543 | tas = kzalloc(sizeof(struct tas), GFP_KERNEL); | ||
| 544 | |||
| 545 | if (!tas) | ||
| 546 | return -ENOMEM; | ||
| 547 | |||
| 548 | tas->i2c.driver = &tas_driver; | ||
| 549 | tas->i2c.adapter = adapter; | ||
| 550 | tas->i2c.addr = addr; | ||
| 551 | strlcpy(tas->i2c.name, "tas audio codec", I2C_NAME_SIZE-1); | ||
| 552 | |||
| 553 | if (i2c_attach_client(&tas->i2c)) { | ||
| 554 | printk(KERN_ERR PFX "failed to attach to i2c\n"); | ||
| 555 | goto fail; | ||
| 556 | } | ||
| 557 | |||
| 558 | strlcpy(tas->codec.name, "tas", MAX_CODEC_NAME_LEN-1); | ||
| 559 | tas->codec.owner = THIS_MODULE; | ||
| 560 | tas->codec.init = tas_init_codec; | ||
| 561 | tas->codec.exit = tas_exit_codec; | ||
| 562 | tas->codec.node = of_node_get(node); | ||
| 563 | |||
| 564 | if (aoa_codec_register(&tas->codec)) { | ||
| 565 | goto detach; | ||
| 566 | } | ||
| 567 | printk(KERN_DEBUG "snd-aoa-codec-tas: created and attached tas instance\n"); | ||
| 568 | return 0; | ||
| 569 | detach: | ||
| 570 | i2c_detach_client(&tas->i2c); | ||
| 571 | fail: | ||
| 572 | kfree(tas); | ||
| 573 | return -EINVAL; | ||
| 574 | } | ||
| 575 | |||
| 576 | static int tas_i2c_attach(struct i2c_adapter *adapter) | ||
| 577 | { | ||
| 578 | struct device_node *busnode, *dev = NULL; | ||
| 579 | struct pmac_i2c_bus *bus; | ||
| 580 | |||
| 581 | bus = pmac_i2c_adapter_to_bus(adapter); | ||
| 582 | if (bus == NULL) | ||
| 583 | return -ENODEV; | ||
| 584 | busnode = pmac_i2c_get_bus_node(bus); | ||
| 585 | |||
| 586 | while ((dev = of_get_next_child(busnode, dev)) != NULL) { | ||
| 587 | if (device_is_compatible(dev, "tas3004")) { | ||
| 588 | u32 *addr; | ||
| 589 | printk(KERN_DEBUG PFX "found tas3004\n"); | ||
| 590 | addr = (u32 *) get_property(dev, "reg", NULL); | ||
| 591 | if (!addr) | ||
| 592 | continue; | ||
| 593 | return tas_create(adapter, dev, ((*addr) >> 1) & 0x7f); | ||
| 594 | } | ||
| 595 | /* older machines have no 'codec' node with a 'compatible' | ||
| 596 | * property that says 'tas3004', they just have a 'deq' | ||
| 597 | * node without any such property... */ | ||
| 598 | if (strcmp(dev->name, "deq") == 0) { | ||
| 599 | u32 *_addr, addr; | ||
| 600 | printk(KERN_DEBUG PFX "found 'deq' node\n"); | ||
| 601 | _addr = (u32 *) get_property(dev, "i2c-address", NULL); | ||
| 602 | if (!_addr) | ||
| 603 | continue; | ||
| 604 | addr = ((*_addr) >> 1) & 0x7f; | ||
| 605 | /* now, if the address doesn't match any of the two | ||
| 606 | * that a tas3004 can have, we cannot handle this. | ||
| 607 | * I doubt it ever happens but hey. */ | ||
| 608 | if (addr != 0x34 && addr != 0x35) | ||
| 609 | continue; | ||
| 610 | return tas_create(adapter, dev, addr); | ||
| 611 | } | ||
| 612 | } | ||
| 613 | return -ENODEV; | ||
| 614 | } | ||
| 615 | |||
| 616 | static int tas_i2c_detach(struct i2c_client *client) | ||
| 617 | { | ||
| 618 | struct tas *tas = container_of(client, struct tas, i2c); | ||
| 619 | int err; | ||
| 620 | u8 tmp = TAS_ACR_ANALOG_PDOWN; | ||
| 621 | |||
| 622 | if ((err = i2c_detach_client(client))) | ||
| 623 | return err; | ||
| 624 | aoa_codec_unregister(&tas->codec); | ||
| 625 | of_node_put(tas->codec.node); | ||
| 626 | |||
| 627 | /* power down codec chip */ | ||
| 628 | tas_write_reg(tas, TAS_REG_ACR, 1, &tmp); | ||
| 629 | |||
| 630 | kfree(tas); | ||
| 631 | return 0; | ||
| 632 | } | ||
| 633 | |||
| 634 | static struct i2c_driver tas_driver = { | ||
| 635 | .driver = { | ||
| 636 | .name = "aoa_codec_tas", | ||
| 637 | .owner = THIS_MODULE, | ||
| 638 | }, | ||
| 639 | .attach_adapter = tas_i2c_attach, | ||
| 640 | .detach_client = tas_i2c_detach, | ||
| 641 | }; | ||
| 642 | |||
| 643 | static int __init tas_init(void) | ||
| 644 | { | ||
| 645 | return i2c_add_driver(&tas_driver); | ||
| 646 | } | ||
| 647 | |||
| 648 | static void __exit tas_exit(void) | ||
| 649 | { | ||
| 650 | i2c_del_driver(&tas_driver); | ||
| 651 | } | ||
| 652 | |||
| 653 | module_init(tas_init); | ||
| 654 | module_exit(tas_exit); | ||
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.h b/sound/aoa/codecs/snd-aoa-codec-tas.h new file mode 100644 index 000000000000..daf81f45d83a --- /dev/null +++ b/sound/aoa/codecs/snd-aoa-codec-tas.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio driver for tas codec (header) | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | #ifndef __SND_AOA_CODECTASH | ||
| 9 | #define __SND_AOA_CODECTASH | ||
| 10 | |||
| 11 | #define TAS_REG_MCS 0x01 /* main control */ | ||
| 12 | # define TAS_MCS_FASTLOAD (1<<7) | ||
| 13 | # define TAS_MCS_SCLK64 (1<<6) | ||
| 14 | # define TAS_MCS_SPORT_MODE_MASK (3<<4) | ||
| 15 | # define TAS_MCS_SPORT_MODE_I2S (2<<4) | ||
| 16 | # define TAS_MCS_SPORT_MODE_RJ (1<<4) | ||
| 17 | # define TAS_MCS_SPORT_MODE_LJ (0<<4) | ||
| 18 | # define TAS_MCS_SPORT_WL_MASK (3<<0) | ||
| 19 | # define TAS_MCS_SPORT_WL_16BIT (0<<0) | ||
| 20 | # define TAS_MCS_SPORT_WL_18BIT (1<<0) | ||
| 21 | # define TAS_MCS_SPORT_WL_20BIT (2<<0) | ||
| 22 | # define TAS_MCS_SPORT_WL_24BIT (3<<0) | ||
| 23 | |||
| 24 | #define TAS_REG_DRC 0x02 | ||
| 25 | #define TAS_REG_VOL 0x04 | ||
| 26 | #define TAS_REG_TREBLE 0x05 | ||
| 27 | #define TAS_REG_BASS 0x06 | ||
| 28 | #define TAS_REG_LMIX 0x07 | ||
| 29 | #define TAS_REG_RMIX 0x08 | ||
| 30 | |||
| 31 | #define TAS_REG_ACR 0x40 /* analog control */ | ||
| 32 | # define TAS_ACR_B_MONAUREAL (1<<7) | ||
| 33 | # define TAS_ACR_B_MON_SEL_RIGHT (1<<6) | ||
| 34 | # define TAS_ACR_DEEMPH_MASK (3<<2) | ||
| 35 | # define TAS_ACR_DEEMPH_OFF (0<<2) | ||
| 36 | # define TAS_ACR_DEEMPH_48KHz (1<<2) | ||
| 37 | # define TAS_ACR_DEEMPH_44KHz (2<<2) | ||
| 38 | # define TAS_ACR_INPUT_B (1<<1) | ||
| 39 | # define TAS_ACR_ANALOG_PDOWN (1<<0) | ||
| 40 | |||
| 41 | #define TAS_REG_MCS2 0x43 /* main control 2 */ | ||
| 42 | # define TAS_MCS2_ALLPASS (1<<1) | ||
| 43 | |||
| 44 | #define TAS_REG_LEFT_BIQUAD6 0x10 | ||
| 45 | #define TAS_REG_RIGHT_BIQUAD6 0x19 | ||
| 46 | |||
| 47 | #endif /* __SND_AOA_CODECTASH */ | ||
diff --git a/sound/aoa/codecs/snd-aoa-codec-toonie.c b/sound/aoa/codecs/snd-aoa-codec-toonie.c new file mode 100644 index 000000000000..bcc555647e79 --- /dev/null +++ b/sound/aoa/codecs/snd-aoa-codec-toonie.c | |||
| @@ -0,0 +1,141 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio driver for Toonie codec | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | * | ||
| 8 | * | ||
| 9 | * This is a driver for the toonie codec chip. This chip is present | ||
| 10 | * on the Mac Mini and is nothing but a DAC. | ||
| 11 | */ | ||
| 12 | #include <linux/delay.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
| 15 | MODULE_LICENSE("GPL"); | ||
| 16 | MODULE_DESCRIPTION("toonie codec driver for snd-aoa"); | ||
| 17 | |||
| 18 | #include "../aoa.h" | ||
| 19 | #include "../soundbus/soundbus.h" | ||
| 20 | |||
| 21 | |||
| 22 | #define PFX "snd-aoa-codec-toonie: " | ||
| 23 | |||
| 24 | struct toonie { | ||
| 25 | struct aoa_codec codec; | ||
| 26 | }; | ||
| 27 | #define codec_to_toonie(c) container_of(c, struct toonie, codec) | ||
| 28 | |||
| 29 | static int toonie_dev_register(struct snd_device *dev) | ||
| 30 | { | ||
| 31 | return 0; | ||
| 32 | } | ||
| 33 | |||
| 34 | static struct snd_device_ops ops = { | ||
| 35 | .dev_register = toonie_dev_register, | ||
| 36 | }; | ||
| 37 | |||
| 38 | static struct transfer_info toonie_transfers[] = { | ||
| 39 | /* This thing *only* has analog output, | ||
| 40 | * the rates are taken from Info.plist | ||
| 41 | * from Darwin. */ | ||
| 42 | { | ||
| 43 | .formats = SNDRV_PCM_FMTBIT_S16_BE | | ||
| 44 | SNDRV_PCM_FMTBIT_S24_BE, | ||
| 45 | .rates = SNDRV_PCM_RATE_32000 | | ||
| 46 | SNDRV_PCM_RATE_44100 | | ||
| 47 | SNDRV_PCM_RATE_48000 | | ||
| 48 | SNDRV_PCM_RATE_88200 | | ||
| 49 | SNDRV_PCM_RATE_96000, | ||
| 50 | }, | ||
| 51 | {} | ||
| 52 | }; | ||
| 53 | |||
| 54 | #ifdef CONFIG_PM | ||
| 55 | static int toonie_suspend(struct codec_info_item *cii, pm_message_t state) | ||
| 56 | { | ||
| 57 | /* can we turn it off somehow? */ | ||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | static int toonie_resume(struct codec_info_item *cii) | ||
| 62 | { | ||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | #endif /* CONFIG_PM */ | ||
| 66 | |||
| 67 | static struct codec_info toonie_codec_info = { | ||
| 68 | .transfers = toonie_transfers, | ||
| 69 | .sysclock_factor = 256, | ||
| 70 | .bus_factor = 64, | ||
| 71 | .owner = THIS_MODULE, | ||
| 72 | #ifdef CONFIG_PM | ||
| 73 | .suspend = toonie_suspend, | ||
| 74 | .resume = toonie_resume, | ||
| 75 | #endif | ||
| 76 | }; | ||
| 77 | |||
| 78 | static int toonie_init_codec(struct aoa_codec *codec) | ||
| 79 | { | ||
| 80 | struct toonie *toonie = codec_to_toonie(codec); | ||
| 81 | |||
| 82 | if (aoa_snd_device_new(SNDRV_DEV_LOWLEVEL, toonie, &ops)) { | ||
| 83 | printk(KERN_ERR PFX "failed to create toonie snd device!\n"); | ||
| 84 | return -ENODEV; | ||
| 85 | } | ||
| 86 | |||
| 87 | /* nothing connected? what a joke! */ | ||
| 88 | if (toonie->codec.connected != 1) | ||
| 89 | return -ENOTCONN; | ||
| 90 | |||
| 91 | if (toonie->codec.soundbus_dev->attach_codec(toonie->codec.soundbus_dev, | ||
| 92 | aoa_get_card(), | ||
| 93 | &toonie_codec_info, toonie)) { | ||
| 94 | printk(KERN_ERR PFX "error creating toonie pcm\n"); | ||
| 95 | return -ENODEV; | ||
| 96 | } | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static void toonie_exit_codec(struct aoa_codec *codec) | ||
| 102 | { | ||
| 103 | struct toonie *toonie = codec_to_toonie(codec); | ||
| 104 | |||
| 105 | if (!toonie->codec.soundbus_dev) { | ||
| 106 | printk(KERN_ERR PFX "toonie_exit_codec called without soundbus_dev!\n"); | ||
| 107 | return; | ||
| 108 | } | ||
| 109 | toonie->codec.soundbus_dev->detach_codec(toonie->codec.soundbus_dev, toonie); | ||
| 110 | } | ||
| 111 | |||
| 112 | static struct toonie *toonie; | ||
| 113 | |||
| 114 | static int __init toonie_init(void) | ||
| 115 | { | ||
| 116 | toonie = kzalloc(sizeof(struct toonie), GFP_KERNEL); | ||
| 117 | |||
| 118 | if (!toonie) | ||
| 119 | return -ENOMEM; | ||
| 120 | |||
| 121 | strlcpy(toonie->codec.name, "toonie", sizeof(toonie->codec.name)); | ||
| 122 | toonie->codec.owner = THIS_MODULE; | ||
| 123 | toonie->codec.init = toonie_init_codec; | ||
| 124 | toonie->codec.exit = toonie_exit_codec; | ||
| 125 | |||
| 126 | if (aoa_codec_register(&toonie->codec)) { | ||
| 127 | kfree(toonie); | ||
| 128 | return -EINVAL; | ||
| 129 | } | ||
| 130 | |||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | static void __exit toonie_exit(void) | ||
| 135 | { | ||
| 136 | aoa_codec_unregister(&toonie->codec); | ||
| 137 | kfree(toonie); | ||
| 138 | } | ||
| 139 | |||
| 140 | module_init(toonie_init); | ||
| 141 | module_exit(toonie_exit); | ||
diff --git a/sound/aoa/core/Makefile b/sound/aoa/core/Makefile new file mode 100644 index 000000000000..62dc7287f663 --- /dev/null +++ b/sound/aoa/core/Makefile | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | obj-$(CONFIG_SND_AOA) += snd-aoa.o | ||
| 2 | snd-aoa-objs := snd-aoa-core.o \ | ||
| 3 | snd-aoa-alsa.o \ | ||
| 4 | snd-aoa-gpio-pmf.o \ | ||
| 5 | snd-aoa-gpio-feature.o | ||
diff --git a/sound/aoa/core/snd-aoa-alsa.c b/sound/aoa/core/snd-aoa-alsa.c new file mode 100644 index 000000000000..b42fdea77ed0 --- /dev/null +++ b/sound/aoa/core/snd-aoa-alsa.c | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio Alsa helpers | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | #include <linux/module.h> | ||
| 9 | #include "snd-aoa-alsa.h" | ||
| 10 | |||
| 11 | static int index = -1; | ||
| 12 | module_param(index, int, 0444); | ||
| 13 | MODULE_PARM_DESC(index, "index for AOA sound card."); | ||
| 14 | |||
| 15 | static struct aoa_card *aoa_card; | ||
| 16 | |||
| 17 | int aoa_alsa_init(char *name, struct module *mod) | ||
| 18 | { | ||
| 19 | struct snd_card *alsa_card; | ||
| 20 | int err; | ||
| 21 | |||
| 22 | if (aoa_card) | ||
| 23 | /* cannot be EEXIST due to usage in aoa_fabric_register */ | ||
| 24 | return -EBUSY; | ||
| 25 | |||
| 26 | alsa_card = snd_card_new(index, name, mod, sizeof(struct aoa_card)); | ||
| 27 | if (!alsa_card) | ||
| 28 | return -ENOMEM; | ||
| 29 | aoa_card = alsa_card->private_data; | ||
| 30 | aoa_card->alsa_card = alsa_card; | ||
| 31 | strlcpy(alsa_card->driver, "AppleOnbdAudio", sizeof(alsa_card->driver)); | ||
| 32 | strlcpy(alsa_card->shortname, name, sizeof(alsa_card->shortname)); | ||
| 33 | strlcpy(alsa_card->longname, name, sizeof(alsa_card->longname)); | ||
| 34 | strlcpy(alsa_card->mixername, name, sizeof(alsa_card->mixername)); | ||
| 35 | err = snd_card_register(aoa_card->alsa_card); | ||
| 36 | if (err < 0) { | ||
| 37 | printk(KERN_ERR "snd-aoa: couldn't register alsa card\n"); | ||
| 38 | snd_card_free(aoa_card->alsa_card); | ||
| 39 | aoa_card = NULL; | ||
| 40 | return err; | ||
| 41 | } | ||
| 42 | return 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | struct snd_card *aoa_get_card(void) | ||
| 46 | { | ||
| 47 | if (aoa_card) | ||
| 48 | return aoa_card->alsa_card; | ||
| 49 | return NULL; | ||
| 50 | } | ||
| 51 | EXPORT_SYMBOL_GPL(aoa_get_card); | ||
| 52 | |||
| 53 | void aoa_alsa_cleanup(void) | ||
| 54 | { | ||
| 55 | if (aoa_card) { | ||
| 56 | snd_card_free(aoa_card->alsa_card); | ||
| 57 | aoa_card = NULL; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | int aoa_snd_device_new(snd_device_type_t type, | ||
| 62 | void * device_data, struct snd_device_ops * ops) | ||
| 63 | { | ||
| 64 | struct snd_card *card = aoa_get_card(); | ||
| 65 | int err; | ||
| 66 | |||
| 67 | if (!card) return -ENOMEM; | ||
| 68 | |||
| 69 | err = snd_device_new(card, type, device_data, ops); | ||
| 70 | if (err) { | ||
| 71 | printk(KERN_ERR "snd-aoa: failed to create snd device (%d)\n", err); | ||
| 72 | return err; | ||
| 73 | } | ||
| 74 | err = snd_device_register(card, device_data); | ||
| 75 | if (err) { | ||
| 76 | printk(KERN_ERR "snd-aoa: failed to register " | ||
| 77 | "snd device (%d)\n", err); | ||
| 78 | printk(KERN_ERR "snd-aoa: have you forgotten the " | ||
| 79 | "dev_register callback?\n"); | ||
| 80 | snd_device_free(card, device_data); | ||
| 81 | } | ||
| 82 | return err; | ||
| 83 | } | ||
| 84 | EXPORT_SYMBOL_GPL(aoa_snd_device_new); | ||
| 85 | |||
| 86 | int aoa_snd_ctl_add(struct snd_kcontrol* control) | ||
| 87 | { | ||
| 88 | int err; | ||
| 89 | |||
| 90 | if (!aoa_card) return -ENODEV; | ||
| 91 | |||
| 92 | err = snd_ctl_add(aoa_card->alsa_card, control); | ||
| 93 | if (err) | ||
| 94 | printk(KERN_ERR "snd-aoa: failed to add alsa control (%d)\n", | ||
| 95 | err); | ||
| 96 | return err; | ||
| 97 | } | ||
| 98 | EXPORT_SYMBOL_GPL(aoa_snd_ctl_add); | ||
diff --git a/sound/aoa/core/snd-aoa-alsa.h b/sound/aoa/core/snd-aoa-alsa.h new file mode 100644 index 000000000000..660d2f1793bb --- /dev/null +++ b/sound/aoa/core/snd-aoa-alsa.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio Alsa private helpers | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef __SND_AOA_ALSA_H | ||
| 10 | #define __SND_AOA_ALSA_H | ||
| 11 | #include "../aoa.h" | ||
| 12 | |||
| 13 | extern int aoa_alsa_init(char *name, struct module *mod); | ||
| 14 | extern void aoa_alsa_cleanup(void); | ||
| 15 | |||
| 16 | #endif /* __SND_AOA_ALSA_H */ | ||
diff --git a/sound/aoa/core/snd-aoa-core.c b/sound/aoa/core/snd-aoa-core.c new file mode 100644 index 000000000000..ecd2d8263f2d --- /dev/null +++ b/sound/aoa/core/snd-aoa-core.c | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio driver core | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/list.h> | ||
| 12 | #include "../aoa.h" | ||
| 13 | #include "snd-aoa-alsa.h" | ||
| 14 | |||
| 15 | MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver"); | ||
| 16 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
| 17 | MODULE_LICENSE("GPL"); | ||
| 18 | |||
| 19 | /* We allow only one fabric. This simplifies things, | ||
| 20 | * and more don't really make that much sense */ | ||
| 21 | static struct aoa_fabric *fabric; | ||
| 22 | static LIST_HEAD(codec_list); | ||
| 23 | |||
| 24 | static int attach_codec_to_fabric(struct aoa_codec *c) | ||
| 25 | { | ||
| 26 | int err; | ||
| 27 | |||
| 28 | if (!try_module_get(c->owner)) | ||
| 29 | return -EBUSY; | ||
| 30 | /* found_codec has to be assigned */ | ||
| 31 | err = -ENOENT; | ||
| 32 | if (fabric->found_codec) | ||
| 33 | err = fabric->found_codec(c); | ||
| 34 | if (err) { | ||
| 35 | module_put(c->owner); | ||
| 36 | printk(KERN_ERR "snd-aoa: fabric didn't like codec %s\n", | ||
| 37 | c->name); | ||
| 38 | return err; | ||
| 39 | } | ||
| 40 | c->fabric = fabric; | ||
| 41 | |||
| 42 | err = 0; | ||
| 43 | if (c->init) | ||
| 44 | err = c->init(c); | ||
| 45 | if (err) { | ||
| 46 | printk(KERN_ERR "snd-aoa: codec %s didn't init\n", c->name); | ||
| 47 | c->fabric = NULL; | ||
| 48 | if (fabric->remove_codec) | ||
| 49 | fabric->remove_codec(c); | ||
| 50 | module_put(c->owner); | ||
| 51 | return err; | ||
| 52 | } | ||
| 53 | if (fabric->attached_codec) | ||
| 54 | fabric->attached_codec(c); | ||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | int aoa_codec_register(struct aoa_codec *codec) | ||
| 59 | { | ||
| 60 | int err = 0; | ||
| 61 | |||
| 62 | /* if there's a fabric already, we can tell if we | ||
| 63 | * will want to have this codec, so propagate error | ||
| 64 | * through. Otherwise, this will happen later... */ | ||
| 65 | if (fabric) | ||
| 66 | err = attach_codec_to_fabric(codec); | ||
| 67 | if (!err) | ||
| 68 | list_add(&codec->list, &codec_list); | ||
| 69 | return err; | ||
| 70 | } | ||
| 71 | EXPORT_SYMBOL_GPL(aoa_codec_register); | ||
| 72 | |||
| 73 | void aoa_codec_unregister(struct aoa_codec *codec) | ||
| 74 | { | ||
| 75 | list_del(&codec->list); | ||
| 76 | if (codec->fabric && codec->exit) | ||
| 77 | codec->exit(codec); | ||
| 78 | if (fabric && fabric->remove_codec) | ||
| 79 | fabric->remove_codec(codec); | ||
| 80 | codec->fabric = NULL; | ||
| 81 | module_put(codec->owner); | ||
| 82 | } | ||
| 83 | EXPORT_SYMBOL_GPL(aoa_codec_unregister); | ||
| 84 | |||
| 85 | int aoa_fabric_register(struct aoa_fabric *new_fabric) | ||
| 86 | { | ||
| 87 | struct aoa_codec *c; | ||
| 88 | int err; | ||
| 89 | |||
| 90 | /* allow querying for presence of fabric | ||
| 91 | * (i.e. do this test first!) */ | ||
| 92 | if (new_fabric == fabric) { | ||
| 93 | err = -EALREADY; | ||
| 94 | goto attach; | ||
| 95 | } | ||
| 96 | if (fabric) | ||
| 97 | return -EEXIST; | ||
| 98 | if (!new_fabric) | ||
| 99 | return -EINVAL; | ||
| 100 | |||
| 101 | err = aoa_alsa_init(new_fabric->name, new_fabric->owner); | ||
| 102 | if (err) | ||
| 103 | return err; | ||
| 104 | |||
| 105 | fabric = new_fabric; | ||
| 106 | |||
| 107 | attach: | ||
| 108 | list_for_each_entry(c, &codec_list, list) { | ||
| 109 | if (c->fabric != fabric) | ||
| 110 | attach_codec_to_fabric(c); | ||
| 111 | } | ||
| 112 | return err; | ||
| 113 | } | ||
| 114 | EXPORT_SYMBOL_GPL(aoa_fabric_register); | ||
| 115 | |||
| 116 | void aoa_fabric_unregister(struct aoa_fabric *old_fabric) | ||
| 117 | { | ||
| 118 | struct aoa_codec *c; | ||
| 119 | |||
| 120 | if (fabric != old_fabric) | ||
| 121 | return; | ||
| 122 | |||
| 123 | list_for_each_entry(c, &codec_list, list) { | ||
| 124 | if (c->fabric) | ||
| 125 | aoa_fabric_unlink_codec(c); | ||
| 126 | } | ||
| 127 | |||
| 128 | aoa_alsa_cleanup(); | ||
| 129 | |||
| 130 | fabric = NULL; | ||
| 131 | } | ||
| 132 | EXPORT_SYMBOL_GPL(aoa_fabric_unregister); | ||
| 133 | |||
| 134 | void aoa_fabric_unlink_codec(struct aoa_codec *codec) | ||
| 135 | { | ||
| 136 | if (!codec->fabric) { | ||
| 137 | printk(KERN_ERR "snd-aoa: fabric unassigned " | ||
| 138 | "in aoa_fabric_unlink_codec\n"); | ||
| 139 | dump_stack(); | ||
| 140 | return; | ||
| 141 | } | ||
| 142 | if (codec->exit) | ||
| 143 | codec->exit(codec); | ||
| 144 | if (codec->fabric->remove_codec) | ||
| 145 | codec->fabric->remove_codec(codec); | ||
| 146 | codec->fabric = NULL; | ||
| 147 | module_put(codec->owner); | ||
| 148 | } | ||
| 149 | EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec); | ||
| 150 | |||
| 151 | static int __init aoa_init(void) | ||
| 152 | { | ||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | static void __exit aoa_exit(void) | ||
| 157 | { | ||
| 158 | aoa_alsa_cleanup(); | ||
| 159 | } | ||
| 160 | |||
| 161 | module_init(aoa_init); | ||
| 162 | module_exit(aoa_exit); | ||
diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c new file mode 100644 index 000000000000..2c6eb7784cc9 --- /dev/null +++ b/sound/aoa/core/snd-aoa-gpio-feature.c | |||
| @@ -0,0 +1,399 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio feature call GPIO control | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | * | ||
| 8 | * This file contains the GPIO control routines for | ||
| 9 | * direct (through feature calls) access to the GPIO | ||
| 10 | * registers. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <asm/pmac_feature.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include "../aoa.h" | ||
| 16 | |||
| 17 | /* TODO: these are 20 global variables | ||
| 18 | * that aren't used on most machines... | ||
| 19 | * Move them into a dynamically allocated | ||
| 20 | * structure and use that. | ||
| 21 | */ | ||
| 22 | |||
| 23 | /* these are the GPIO numbers (register addresses as offsets into | ||
| 24 | * the GPIO space) */ | ||
| 25 | static int headphone_mute_gpio; | ||
| 26 | static int amp_mute_gpio; | ||
| 27 | static int lineout_mute_gpio; | ||
| 28 | static int hw_reset_gpio; | ||
| 29 | static int lineout_detect_gpio; | ||
| 30 | static int headphone_detect_gpio; | ||
| 31 | static int linein_detect_gpio; | ||
| 32 | |||
| 33 | /* see the SWITCH_GPIO macro */ | ||
| 34 | static int headphone_mute_gpio_activestate; | ||
| 35 | static int amp_mute_gpio_activestate; | ||
| 36 | static int lineout_mute_gpio_activestate; | ||
| 37 | static int hw_reset_gpio_activestate; | ||
| 38 | static int lineout_detect_gpio_activestate; | ||
| 39 | static int headphone_detect_gpio_activestate; | ||
| 40 | static int linein_detect_gpio_activestate; | ||
| 41 | |||
| 42 | /* node pointers that we save when getting the GPIO number | ||
| 43 | * to get the interrupt later */ | ||
| 44 | static struct device_node *lineout_detect_node; | ||
| 45 | static struct device_node *linein_detect_node; | ||
| 46 | static struct device_node *headphone_detect_node; | ||
| 47 | |||
| 48 | static int lineout_detect_irq; | ||
| 49 | static int linein_detect_irq; | ||
| 50 | static int headphone_detect_irq; | ||
| 51 | |||
| 52 | static struct device_node *get_gpio(char *name, | ||
| 53 | char *altname, | ||
| 54 | int *gpioptr, | ||
| 55 | int *gpioactiveptr) | ||
| 56 | { | ||
| 57 | struct device_node *np, *gpio; | ||
| 58 | u32 *reg; | ||
| 59 | char *audio_gpio; | ||
| 60 | |||
| 61 | *gpioptr = -1; | ||
| 62 | |||
| 63 | /* check if we can get it the easy way ... */ | ||
| 64 | np = of_find_node_by_name(NULL, name); | ||
| 65 | if (!np) { | ||
| 66 | /* some machines have only gpioX/extint-gpioX nodes, | ||
| 67 | * and an audio-gpio property saying what it is ... | ||
| 68 | * So what we have to do is enumerate all children | ||
| 69 | * of the gpio node and check them all. */ | ||
| 70 | gpio = of_find_node_by_name(NULL, "gpio"); | ||
| 71 | if (!gpio) | ||
| 72 | return NULL; | ||
| 73 | while ((np = of_get_next_child(gpio, np))) { | ||
| 74 | audio_gpio = get_property(np, "audio-gpio", NULL); | ||
| 75 | if (!audio_gpio) | ||
| 76 | continue; | ||
| 77 | if (strcmp(audio_gpio, name) == 0) | ||
| 78 | break; | ||
| 79 | if (altname && (strcmp(audio_gpio, altname) == 0)) | ||
| 80 | break; | ||
| 81 | } | ||
| 82 | /* still not found, assume not there */ | ||
| 83 | if (!np) | ||
| 84 | return NULL; | ||
| 85 | } | ||
| 86 | |||
| 87 | reg = (u32 *)get_property(np, "reg", NULL); | ||
| 88 | if (!reg) | ||
| 89 | return NULL; | ||
| 90 | |||
| 91 | *gpioptr = *reg; | ||
| 92 | |||
| 93 | /* this is a hack, usually the GPIOs 'reg' property | ||
| 94 | * should have the offset based from the GPIO space | ||
| 95 | * which is at 0x50, but apparently not always... */ | ||
| 96 | if (*gpioptr < 0x50) | ||
| 97 | *gpioptr += 0x50; | ||
| 98 | |||
| 99 | reg = (u32 *)get_property(np, "audio-gpio-active-state", NULL); | ||
| 100 | if (!reg) | ||
| 101 | /* Apple seems to default to 1, but | ||
| 102 | * that doesn't seem right at least on most | ||
| 103 | * machines. So until proven that the opposite | ||
| 104 | * is necessary, we default to 0 | ||
| 105 | * (which, incidentally, snd-powermac also does...) */ | ||
| 106 | *gpioactiveptr = 0; | ||
| 107 | else | ||
| 108 | *gpioactiveptr = *reg; | ||
| 109 | |||
| 110 | return np; | ||
| 111 | } | ||
| 112 | |||
| 113 | static void get_irq(struct device_node * np, int *irqptr) | ||
| 114 | { | ||
| 115 | *irqptr = -1; | ||
| 116 | if (!np) | ||
| 117 | return; | ||
| 118 | if (np->n_intrs != 1) | ||
| 119 | return; | ||
| 120 | *irqptr = np->intrs[0].line; | ||
| 121 | } | ||
| 122 | |||
| 123 | /* 0x4 is outenable, 0x1 is out, thus 4 or 5 */ | ||
| 124 | #define SWITCH_GPIO(name, v, on) \ | ||
| 125 | (((v)&~1) | ((on)? \ | ||
| 126 | (name##_gpio_activestate==0?4:5): \ | ||
| 127 | (name##_gpio_activestate==0?5:4))) | ||
| 128 | |||
| 129 | #define FTR_GPIO(name, bit) \ | ||
| 130 | static void ftr_gpio_set_##name(struct gpio_runtime *rt, int on)\ | ||
| 131 | { \ | ||
| 132 | int v; \ | ||
| 133 | \ | ||
| 134 | if (unlikely(!rt)) return; \ | ||
| 135 | \ | ||
| 136 | if (name##_mute_gpio < 0) \ | ||
| 137 | return; \ | ||
| 138 | \ | ||
| 139 | v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, \ | ||
| 140 | name##_mute_gpio, \ | ||
| 141 | 0); \ | ||
| 142 | \ | ||
| 143 | /* muted = !on... */ \ | ||
| 144 | v = SWITCH_GPIO(name##_mute, v, !on); \ | ||
| 145 | \ | ||
| 146 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, \ | ||
| 147 | name##_mute_gpio, v); \ | ||
| 148 | \ | ||
| 149 | rt->implementation_private &= ~(1<<bit); \ | ||
| 150 | rt->implementation_private |= (!!on << bit); \ | ||
| 151 | } \ | ||
| 152 | static int ftr_gpio_get_##name(struct gpio_runtime *rt) \ | ||
| 153 | { \ | ||
| 154 | if (unlikely(!rt)) return 0; \ | ||
| 155 | return (rt->implementation_private>>bit)&1; \ | ||
| 156 | } | ||
| 157 | |||
| 158 | FTR_GPIO(headphone, 0); | ||
| 159 | FTR_GPIO(amp, 1); | ||
| 160 | FTR_GPIO(lineout, 2); | ||
| 161 | |||
| 162 | static void ftr_gpio_set_hw_reset(struct gpio_runtime *rt, int on) | ||
| 163 | { | ||
| 164 | int v; | ||
| 165 | |||
| 166 | if (unlikely(!rt)) return; | ||
| 167 | if (hw_reset_gpio < 0) | ||
| 168 | return; | ||
| 169 | |||
| 170 | v = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, | ||
| 171 | hw_reset_gpio, 0); | ||
| 172 | v = SWITCH_GPIO(hw_reset, v, on); | ||
| 173 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, | ||
| 174 | hw_reset_gpio, v); | ||
| 175 | } | ||
| 176 | |||
| 177 | static void ftr_gpio_all_amps_off(struct gpio_runtime *rt) | ||
| 178 | { | ||
| 179 | int saved; | ||
| 180 | |||
| 181 | if (unlikely(!rt)) return; | ||
| 182 | saved = rt->implementation_private; | ||
| 183 | ftr_gpio_set_headphone(rt, 0); | ||
| 184 | ftr_gpio_set_amp(rt, 0); | ||
| 185 | ftr_gpio_set_lineout(rt, 0); | ||
| 186 | rt->implementation_private = saved; | ||
| 187 | } | ||
| 188 | |||
| 189 | static void ftr_gpio_all_amps_restore(struct gpio_runtime *rt) | ||
| 190 | { | ||
| 191 | int s; | ||
| 192 | |||
| 193 | if (unlikely(!rt)) return; | ||
| 194 | s = rt->implementation_private; | ||
| 195 | ftr_gpio_set_headphone(rt, (s>>0)&1); | ||
| 196 | ftr_gpio_set_amp(rt, (s>>1)&1); | ||
| 197 | ftr_gpio_set_lineout(rt, (s>>2)&1); | ||
| 198 | } | ||
| 199 | |||
| 200 | static void ftr_handle_notify(void *data) | ||
| 201 | { | ||
| 202 | struct gpio_notification *notif = data; | ||
| 203 | |||
| 204 | mutex_lock(¬if->mutex); | ||
| 205 | if (notif->notify) | ||
| 206 | notif->notify(notif->data); | ||
| 207 | mutex_unlock(¬if->mutex); | ||
| 208 | } | ||
| 209 | |||
| 210 | static void ftr_gpio_init(struct gpio_runtime *rt) | ||
| 211 | { | ||
| 212 | get_gpio("headphone-mute", NULL, | ||
| 213 | &headphone_mute_gpio, | ||
| 214 | &headphone_mute_gpio_activestate); | ||
| 215 | get_gpio("amp-mute", NULL, | ||
| 216 | &_mute_gpio, | ||
| 217 | &_mute_gpio_activestate); | ||
| 218 | get_gpio("lineout-mute", NULL, | ||
| 219 | &lineout_mute_gpio, | ||
| 220 | &lineout_mute_gpio_activestate); | ||
| 221 | get_gpio("hw-reset", "audio-hw-reset", | ||
| 222 | &hw_reset_gpio, | ||
| 223 | &hw_reset_gpio_activestate); | ||
| 224 | |||
| 225 | headphone_detect_node = get_gpio("headphone-detect", NULL, | ||
| 226 | &headphone_detect_gpio, | ||
| 227 | &headphone_detect_gpio_activestate); | ||
| 228 | /* go Apple, and thanks for giving these different names | ||
| 229 | * across the board... */ | ||
| 230 | lineout_detect_node = get_gpio("lineout-detect", "line-output-detect", | ||
| 231 | &lineout_detect_gpio, | ||
| 232 | &lineout_detect_gpio_activestate); | ||
| 233 | linein_detect_node = get_gpio("linein-detect", "line-input-detect", | ||
| 234 | &linein_detect_gpio, | ||
| 235 | &linein_detect_gpio_activestate); | ||
| 236 | |||
| 237 | get_irq(headphone_detect_node, &headphone_detect_irq); | ||
| 238 | get_irq(lineout_detect_node, &lineout_detect_irq); | ||
| 239 | get_irq(linein_detect_node, &linein_detect_irq); | ||
| 240 | |||
| 241 | ftr_gpio_all_amps_off(rt); | ||
| 242 | rt->implementation_private = 0; | ||
| 243 | INIT_WORK(&rt->headphone_notify.work, ftr_handle_notify, | ||
| 244 | &rt->headphone_notify); | ||
| 245 | INIT_WORK(&rt->line_in_notify.work, ftr_handle_notify, | ||
| 246 | &rt->line_in_notify); | ||
| 247 | INIT_WORK(&rt->line_out_notify.work, ftr_handle_notify, | ||
| 248 | &rt->line_out_notify); | ||
| 249 | mutex_init(&rt->headphone_notify.mutex); | ||
| 250 | mutex_init(&rt->line_in_notify.mutex); | ||
| 251 | mutex_init(&rt->line_out_notify.mutex); | ||
| 252 | } | ||
| 253 | |||
| 254 | static void ftr_gpio_exit(struct gpio_runtime *rt) | ||
| 255 | { | ||
| 256 | ftr_gpio_all_amps_off(rt); | ||
| 257 | rt->implementation_private = 0; | ||
| 258 | if (rt->headphone_notify.notify) | ||
| 259 | free_irq(headphone_detect_irq, &rt->headphone_notify); | ||
| 260 | if (rt->line_in_notify.gpio_private) | ||
| 261 | free_irq(linein_detect_irq, &rt->line_in_notify); | ||
| 262 | if (rt->line_out_notify.gpio_private) | ||
| 263 | free_irq(lineout_detect_irq, &rt->line_out_notify); | ||
| 264 | cancel_delayed_work(&rt->headphone_notify.work); | ||
| 265 | cancel_delayed_work(&rt->line_in_notify.work); | ||
| 266 | cancel_delayed_work(&rt->line_out_notify.work); | ||
| 267 | flush_scheduled_work(); | ||
| 268 | mutex_destroy(&rt->headphone_notify.mutex); | ||
| 269 | mutex_destroy(&rt->line_in_notify.mutex); | ||
| 270 | mutex_destroy(&rt->line_out_notify.mutex); | ||
| 271 | } | ||
| 272 | |||
| 273 | static irqreturn_t ftr_handle_notify_irq(int xx, | ||
| 274 | void *data, | ||
| 275 | struct pt_regs *regs) | ||
| 276 | { | ||
| 277 | struct gpio_notification *notif = data; | ||
| 278 | |||
| 279 | schedule_work(¬if->work); | ||
| 280 | |||
| 281 | return IRQ_HANDLED; | ||
| 282 | } | ||
| 283 | |||
| 284 | static int ftr_set_notify(struct gpio_runtime *rt, | ||
| 285 | enum notify_type type, | ||
| 286 | notify_func_t notify, | ||
| 287 | void *data) | ||
| 288 | { | ||
| 289 | struct gpio_notification *notif; | ||
| 290 | notify_func_t old; | ||
| 291 | int irq; | ||
| 292 | char *name; | ||
| 293 | int err = -EBUSY; | ||
| 294 | |||
| 295 | switch (type) { | ||
| 296 | case AOA_NOTIFY_HEADPHONE: | ||
| 297 | notif = &rt->headphone_notify; | ||
| 298 | name = "headphone-detect"; | ||
| 299 | irq = headphone_detect_irq; | ||
| 300 | break; | ||
| 301 | case AOA_NOTIFY_LINE_IN: | ||
| 302 | notif = &rt->line_in_notify; | ||
| 303 | name = "linein-detect"; | ||
| 304 | irq = linein_detect_irq; | ||
| 305 | break; | ||
| 306 | case AOA_NOTIFY_LINE_OUT: | ||
| 307 | notif = &rt->line_out_notify; | ||
| 308 | name = "lineout-detect"; | ||
| 309 | irq = lineout_detect_irq; | ||
| 310 | break; | ||
| 311 | default: | ||
| 312 | return -EINVAL; | ||
| 313 | } | ||
| 314 | |||
| 315 | if (irq == -1) | ||
| 316 | return -ENODEV; | ||
| 317 | |||
| 318 | mutex_lock(¬if->mutex); | ||
| 319 | |||
| 320 | old = notif->notify; | ||
| 321 | |||
| 322 | if (!old && !notify) { | ||
| 323 | err = 0; | ||
| 324 | goto out_unlock; | ||
| 325 | } | ||
| 326 | |||
| 327 | if (old && notify) { | ||
| 328 | if (old == notify && notif->data == data) | ||
| 329 | err = 0; | ||
| 330 | goto out_unlock; | ||
| 331 | } | ||
| 332 | |||
| 333 | if (old && !notify) | ||
| 334 | free_irq(irq, notif); | ||
| 335 | |||
| 336 | if (!old && notify) { | ||
| 337 | err = request_irq(irq, ftr_handle_notify_irq, 0, name, notif); | ||
| 338 | if (err) | ||
| 339 | goto out_unlock; | ||
| 340 | } | ||
| 341 | |||
| 342 | notif->notify = notify; | ||
| 343 | notif->data = data; | ||
| 344 | |||
| 345 | err = 0; | ||
| 346 | out_unlock: | ||
| 347 | mutex_unlock(¬if->mutex); | ||
| 348 | return err; | ||
| 349 | } | ||
| 350 | |||
| 351 | static int ftr_get_detect(struct gpio_runtime *rt, | ||
| 352 | enum notify_type type) | ||
| 353 | { | ||
| 354 | int gpio, ret, active; | ||
| 355 | |||
| 356 | switch (type) { | ||
| 357 | case AOA_NOTIFY_HEADPHONE: | ||
| 358 | gpio = headphone_detect_gpio; | ||
| 359 | active = headphone_detect_gpio_activestate; | ||
| 360 | break; | ||
| 361 | case AOA_NOTIFY_LINE_IN: | ||
| 362 | gpio = linein_detect_gpio; | ||
| 363 | active = linein_detect_gpio_activestate; | ||
| 364 | break; | ||
| 365 | case AOA_NOTIFY_LINE_OUT: | ||
| 366 | gpio = lineout_detect_gpio; | ||
| 367 | active = lineout_detect_gpio_activestate; | ||
| 368 | break; | ||
| 369 | default: | ||
| 370 | return -EINVAL; | ||
| 371 | } | ||
| 372 | |||
| 373 | if (gpio == -1) | ||
| 374 | return -ENODEV; | ||
| 375 | |||
| 376 | ret = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio, 0); | ||
| 377 | if (ret < 0) | ||
| 378 | return ret; | ||
| 379 | return ((ret >> 1) & 1) == active; | ||
| 380 | } | ||
| 381 | |||
| 382 | static struct gpio_methods methods = { | ||
| 383 | .init = ftr_gpio_init, | ||
| 384 | .exit = ftr_gpio_exit, | ||
| 385 | .all_amps_off = ftr_gpio_all_amps_off, | ||
| 386 | .all_amps_restore = ftr_gpio_all_amps_restore, | ||
| 387 | .set_headphone = ftr_gpio_set_headphone, | ||
| 388 | .set_speakers = ftr_gpio_set_amp, | ||
| 389 | .set_lineout = ftr_gpio_set_lineout, | ||
| 390 | .set_hw_reset = ftr_gpio_set_hw_reset, | ||
| 391 | .get_headphone = ftr_gpio_get_headphone, | ||
| 392 | .get_speakers = ftr_gpio_get_amp, | ||
| 393 | .get_lineout = ftr_gpio_get_lineout, | ||
| 394 | .set_notify = ftr_set_notify, | ||
| 395 | .get_detect = ftr_get_detect, | ||
| 396 | }; | ||
| 397 | |||
| 398 | struct gpio_methods *ftr_gpio_methods = &methods; | ||
| 399 | EXPORT_SYMBOL_GPL(ftr_gpio_methods); | ||
diff --git a/sound/aoa/core/snd-aoa-gpio-pmf.c b/sound/aoa/core/snd-aoa-gpio-pmf.c new file mode 100644 index 000000000000..0e9b9bb2a6de --- /dev/null +++ b/sound/aoa/core/snd-aoa-gpio-pmf.c | |||
| @@ -0,0 +1,246 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio pmf GPIOs | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <asm/pmac_feature.h> | ||
| 10 | #include <asm/pmac_pfunc.h> | ||
| 11 | #include "../aoa.h" | ||
| 12 | |||
| 13 | #define PMF_GPIO(name, bit) \ | ||
| 14 | static void pmf_gpio_set_##name(struct gpio_runtime *rt, int on)\ | ||
| 15 | { \ | ||
| 16 | struct pmf_args args = { .count = 1, .u[0].v = !on }; \ | ||
| 17 | \ | ||
| 18 | if (unlikely(!rt)) return; \ | ||
| 19 | pmf_call_function(rt->node, #name "-mute", &args); \ | ||
| 20 | rt->implementation_private &= ~(1<<bit); \ | ||
| 21 | rt->implementation_private |= (!!on << bit); \ | ||
| 22 | } \ | ||
| 23 | static int pmf_gpio_get_##name(struct gpio_runtime *rt) \ | ||
| 24 | { \ | ||
| 25 | if (unlikely(!rt)) return 0; \ | ||
| 26 | return (rt->implementation_private>>bit)&1; \ | ||
| 27 | } | ||
| 28 | |||
| 29 | PMF_GPIO(headphone, 0); | ||
| 30 | PMF_GPIO(amp, 1); | ||
| 31 | PMF_GPIO(lineout, 2); | ||
| 32 | |||
| 33 | static void pmf_gpio_set_hw_reset(struct gpio_runtime *rt, int on) | ||
| 34 | { | ||
| 35 | struct pmf_args args = { .count = 1, .u[0].v = !!on }; | ||
| 36 | |||
| 37 | if (unlikely(!rt)) return; | ||
| 38 | pmf_call_function(rt->node, "hw-reset", &args); | ||
| 39 | } | ||
| 40 | |||
| 41 | static void pmf_gpio_all_amps_off(struct gpio_runtime *rt) | ||
| 42 | { | ||
| 43 | int saved; | ||
| 44 | |||
| 45 | if (unlikely(!rt)) return; | ||
| 46 | saved = rt->implementation_private; | ||
| 47 | pmf_gpio_set_headphone(rt, 0); | ||
| 48 | pmf_gpio_set_amp(rt, 0); | ||
| 49 | pmf_gpio_set_lineout(rt, 0); | ||
| 50 | rt->implementation_private = saved; | ||
| 51 | } | ||
| 52 | |||
| 53 | static void pmf_gpio_all_amps_restore(struct gpio_runtime *rt) | ||
| 54 | { | ||
| 55 | int s; | ||
| 56 | |||
| 57 | if (unlikely(!rt)) return; | ||
| 58 | s = rt->implementation_private; | ||
| 59 | pmf_gpio_set_headphone(rt, (s>>0)&1); | ||
| 60 | pmf_gpio_set_amp(rt, (s>>1)&1); | ||
| 61 | pmf_gpio_set_lineout(rt, (s>>2)&1); | ||
| 62 | } | ||
| 63 | |||
| 64 | static void pmf_handle_notify(void *data) | ||
| 65 | { | ||
| 66 | struct gpio_notification *notif = data; | ||
| 67 | |||
| 68 | mutex_lock(¬if->mutex); | ||
| 69 | if (notif->notify) | ||
| 70 | notif->notify(notif->data); | ||
| 71 | mutex_unlock(¬if->mutex); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void pmf_gpio_init(struct gpio_runtime *rt) | ||
| 75 | { | ||
| 76 | pmf_gpio_all_amps_off(rt); | ||
| 77 | rt->implementation_private = 0; | ||
| 78 | INIT_WORK(&rt->headphone_notify.work, pmf_handle_notify, | ||
| 79 | &rt->headphone_notify); | ||
| 80 | INIT_WORK(&rt->line_in_notify.work, pmf_handle_notify, | ||
| 81 | &rt->line_in_notify); | ||
| 82 | INIT_WORK(&rt->line_out_notify.work, pmf_handle_notify, | ||
| 83 | &rt->line_out_notify); | ||
| 84 | mutex_init(&rt->headphone_notify.mutex); | ||
| 85 | mutex_init(&rt->line_in_notify.mutex); | ||
| 86 | mutex_init(&rt->line_out_notify.mutex); | ||
| 87 | } | ||
| 88 | |||
| 89 | static void pmf_gpio_exit(struct gpio_runtime *rt) | ||
| 90 | { | ||
| 91 | pmf_gpio_all_amps_off(rt); | ||
| 92 | rt->implementation_private = 0; | ||
| 93 | |||
| 94 | if (rt->headphone_notify.gpio_private) | ||
| 95 | pmf_unregister_irq_client(rt->headphone_notify.gpio_private); | ||
| 96 | if (rt->line_in_notify.gpio_private) | ||
| 97 | pmf_unregister_irq_client(rt->line_in_notify.gpio_private); | ||
| 98 | if (rt->line_out_notify.gpio_private) | ||
| 99 | pmf_unregister_irq_client(rt->line_out_notify.gpio_private); | ||
| 100 | |||
| 101 | /* make sure no work is pending before freeing | ||
| 102 | * all things */ | ||
| 103 | cancel_delayed_work(&rt->headphone_notify.work); | ||
| 104 | cancel_delayed_work(&rt->line_in_notify.work); | ||
| 105 | cancel_delayed_work(&rt->line_out_notify.work); | ||
| 106 | flush_scheduled_work(); | ||
| 107 | |||
| 108 | mutex_destroy(&rt->headphone_notify.mutex); | ||
| 109 | mutex_destroy(&rt->line_in_notify.mutex); | ||
| 110 | mutex_destroy(&rt->line_out_notify.mutex); | ||
| 111 | |||
| 112 | if (rt->headphone_notify.gpio_private) | ||
| 113 | kfree(rt->headphone_notify.gpio_private); | ||
| 114 | if (rt->line_in_notify.gpio_private) | ||
| 115 | kfree(rt->line_in_notify.gpio_private); | ||
| 116 | if (rt->line_out_notify.gpio_private) | ||
| 117 | kfree(rt->line_out_notify.gpio_private); | ||
| 118 | } | ||
| 119 | |||
| 120 | static void pmf_handle_notify_irq(void *data) | ||
| 121 | { | ||
| 122 | struct gpio_notification *notif = data; | ||
| 123 | |||
| 124 | schedule_work(¬if->work); | ||
| 125 | } | ||
| 126 | |||
| 127 | static int pmf_set_notify(struct gpio_runtime *rt, | ||
| 128 | enum notify_type type, | ||
| 129 | notify_func_t notify, | ||
| 130 | void *data) | ||
| 131 | { | ||
| 132 | struct gpio_notification *notif; | ||
| 133 | notify_func_t old; | ||
| 134 | struct pmf_irq_client *irq_client; | ||
| 135 | char *name; | ||
| 136 | int err = -EBUSY; | ||
| 137 | |||
| 138 | switch (type) { | ||
| 139 | case AOA_NOTIFY_HEADPHONE: | ||
| 140 | notif = &rt->headphone_notify; | ||
| 141 | name = "headphone-detect"; | ||
| 142 | break; | ||
| 143 | case AOA_NOTIFY_LINE_IN: | ||
| 144 | notif = &rt->line_in_notify; | ||
| 145 | name = "linein-detect"; | ||
| 146 | break; | ||
| 147 | case AOA_NOTIFY_LINE_OUT: | ||
| 148 | notif = &rt->line_out_notify; | ||
| 149 | name = "lineout-detect"; | ||
| 150 | break; | ||
| 151 | default: | ||
| 152 | return -EINVAL; | ||
| 153 | } | ||
| 154 | |||
| 155 | mutex_lock(¬if->mutex); | ||
| 156 | |||
| 157 | old = notif->notify; | ||
| 158 | |||
| 159 | if (!old && !notify) { | ||
| 160 | err = 0; | ||
| 161 | goto out_unlock; | ||
| 162 | } | ||
| 163 | |||
| 164 | if (old && notify) { | ||
| 165 | if (old == notify && notif->data == data) | ||
| 166 | err = 0; | ||
| 167 | goto out_unlock; | ||
| 168 | } | ||
| 169 | |||
| 170 | if (old && !notify) { | ||
| 171 | irq_client = notif->gpio_private; | ||
| 172 | pmf_unregister_irq_client(irq_client); | ||
| 173 | kfree(irq_client); | ||
| 174 | notif->gpio_private = NULL; | ||
| 175 | } | ||
| 176 | if (!old && notify) { | ||
| 177 | irq_client = kzalloc(sizeof(struct pmf_irq_client), | ||
| 178 | GFP_KERNEL); | ||
| 179 | irq_client->data = notif; | ||
| 180 | irq_client->handler = pmf_handle_notify_irq; | ||
| 181 | irq_client->owner = THIS_MODULE; | ||
| 182 | err = pmf_register_irq_client(rt->node, | ||
| 183 | name, | ||
| 184 | irq_client); | ||
| 185 | if (err) { | ||
| 186 | printk(KERN_ERR "snd-aoa: gpio layer failed to" | ||
| 187 | " register %s irq (%d)\n", name, err); | ||
| 188 | kfree(irq_client); | ||
| 189 | goto out_unlock; | ||
| 190 | } | ||
| 191 | notif->gpio_private = irq_client; | ||
| 192 | } | ||
| 193 | notif->notify = notify; | ||
| 194 | notif->data = data; | ||
| 195 | |||
| 196 | err = 0; | ||
| 197 | out_unlock: | ||
| 198 | mutex_unlock(¬if->mutex); | ||
| 199 | return err; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int pmf_get_detect(struct gpio_runtime *rt, | ||
| 203 | enum notify_type type) | ||
| 204 | { | ||
| 205 | char *name; | ||
| 206 | int err = -EBUSY, ret; | ||
| 207 | struct pmf_args args = { .count = 1, .u[0].p = &ret }; | ||
| 208 | |||
| 209 | switch (type) { | ||
| 210 | case AOA_NOTIFY_HEADPHONE: | ||
| 211 | name = "headphone-detect"; | ||
| 212 | break; | ||
| 213 | case AOA_NOTIFY_LINE_IN: | ||
| 214 | name = "linein-detect"; | ||
| 215 | break; | ||
| 216 | case AOA_NOTIFY_LINE_OUT: | ||
| 217 | name = "lineout-detect"; | ||
| 218 | break; | ||
| 219 | default: | ||
| 220 | return -EINVAL; | ||
| 221 | } | ||
| 222 | |||
| 223 | err = pmf_call_function(rt->node, name, &args); | ||
| 224 | if (err) | ||
| 225 | return err; | ||
| 226 | return ret; | ||
| 227 | } | ||
| 228 | |||
| 229 | static struct gpio_methods methods = { | ||
| 230 | .init = pmf_gpio_init, | ||
| 231 | .exit = pmf_gpio_exit, | ||
| 232 | .all_amps_off = pmf_gpio_all_amps_off, | ||
| 233 | .all_amps_restore = pmf_gpio_all_amps_restore, | ||
| 234 | .set_headphone = pmf_gpio_set_headphone, | ||
| 235 | .set_speakers = pmf_gpio_set_amp, | ||
| 236 | .set_lineout = pmf_gpio_set_lineout, | ||
| 237 | .set_hw_reset = pmf_gpio_set_hw_reset, | ||
| 238 | .get_headphone = pmf_gpio_get_headphone, | ||
| 239 | .get_speakers = pmf_gpio_get_amp, | ||
| 240 | .get_lineout = pmf_gpio_get_lineout, | ||
| 241 | .set_notify = pmf_set_notify, | ||
| 242 | .get_detect = pmf_get_detect, | ||
| 243 | }; | ||
| 244 | |||
| 245 | struct gpio_methods *pmf_gpio_methods = &methods; | ||
| 246 | EXPORT_SYMBOL_GPL(pmf_gpio_methods); | ||
diff --git a/sound/aoa/fabrics/Kconfig b/sound/aoa/fabrics/Kconfig new file mode 100644 index 000000000000..c3bc7705c86a --- /dev/null +++ b/sound/aoa/fabrics/Kconfig | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | config SND_AOA_FABRIC_LAYOUT | ||
| 2 | tristate "layout-id fabric" | ||
| 3 | depends SND_AOA | ||
| 4 | select SND_AOA_SOUNDBUS | ||
| 5 | select SND_AOA_SOUNDBUS_I2S | ||
| 6 | ---help--- | ||
| 7 | This enables the layout-id fabric for the Apple Onboard | ||
| 8 | Audio driver, the module holding it all together | ||
| 9 | based on the device-tree's layout-id property. | ||
| 10 | |||
| 11 | If you are unsure and have a later Apple machine, | ||
| 12 | compile it as a module. | ||
diff --git a/sound/aoa/fabrics/Makefile b/sound/aoa/fabrics/Makefile new file mode 100644 index 000000000000..55fc5e7e52cf --- /dev/null +++ b/sound/aoa/fabrics/Makefile | |||
| @@ -0,0 +1 @@ | |||
| obj-$(CONFIG_SND_AOA_FABRIC_LAYOUT) += snd-aoa-fabric-layout.o | |||
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c new file mode 100644 index 000000000000..04a7238e9494 --- /dev/null +++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c | |||
| @@ -0,0 +1,1109 @@ | |||
| 1 | /* | ||
| 2 | * Apple Onboard Audio driver -- layout fabric | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | * | ||
| 8 | * | ||
| 9 | * This fabric module looks for sound codecs | ||
| 10 | * based on the layout-id property in the device tree. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <asm/prom.h> | ||
| 15 | #include <linux/list.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include "../aoa.h" | ||
| 18 | #include "../soundbus/soundbus.h" | ||
| 19 | |||
| 20 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
| 21 | MODULE_LICENSE("GPL"); | ||
| 22 | MODULE_DESCRIPTION("Layout-ID fabric for snd-aoa"); | ||
| 23 | |||
| 24 | #define MAX_CODECS_PER_BUS 2 | ||
| 25 | |||
| 26 | /* These are the connections the layout fabric | ||
| 27 | * knows about. It doesn't really care about the | ||
| 28 | * input ones, but I thought I'd separate them | ||
| 29 | * to give them proper names. The thing is that | ||
| 30 | * Apple usually will distinguish the active output | ||
| 31 | * by GPIOs, while the active input is set directly | ||
| 32 | * on the codec. Hence we here tell the codec what | ||
| 33 | * we think is connected. This information is hard- | ||
| 34 | * coded below ... */ | ||
| 35 | #define CC_SPEAKERS (1<<0) | ||
| 36 | #define CC_HEADPHONE (1<<1) | ||
| 37 | #define CC_LINEOUT (1<<2) | ||
| 38 | #define CC_DIGITALOUT (1<<3) | ||
| 39 | #define CC_LINEIN (1<<4) | ||
| 40 | #define CC_MICROPHONE (1<<5) | ||
| 41 | #define CC_DIGITALIN (1<<6) | ||
| 42 | /* pretty bogus but users complain... | ||
| 43 | * This is a flag saying that the LINEOUT | ||
| 44 | * should be renamed to HEADPHONE. | ||
| 45 | * be careful with input detection! */ | ||
| 46 | #define CC_LINEOUT_LABELLED_HEADPHONE (1<<7) | ||
| 47 | |||
| 48 | struct codec_connection { | ||
| 49 | /* CC_ flags from above */ | ||
| 50 | int connected; | ||
| 51 | /* codec dependent bit to be set in the aoa_codec.connected field. | ||
| 52 | * This intentionally doesn't have any generic flags because the | ||
| 53 | * fabric has to know the codec anyway and all codecs might have | ||
| 54 | * different connectors */ | ||
| 55 | int codec_bit; | ||
| 56 | }; | ||
| 57 | |||
| 58 | struct codec_connect_info { | ||
| 59 | char *name; | ||
| 60 | struct codec_connection *connections; | ||
| 61 | }; | ||
| 62 | |||
| 63 | #define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0) | ||
| 64 | |||
| 65 | struct layout { | ||
| 66 | unsigned int layout_id; | ||
| 67 | struct codec_connect_info codecs[MAX_CODECS_PER_BUS]; | ||
| 68 | int flags; | ||
| 69 | |||
| 70 | /* if busname is not assigned, we use 'Master' below, | ||
| 71 | * so that our layout table doesn't need to be filled | ||
| 72 | * too much. | ||
| 73 | * We only assign these two if we expect to find more | ||
| 74 | * than one soundbus, i.e. on those machines with | ||
| 75 | * multiple layout-ids */ | ||
| 76 | char *busname; | ||
| 77 | int pcmid; | ||
| 78 | }; | ||
| 79 | |||
| 80 | MODULE_ALIAS("sound-layout-41"); | ||
| 81 | MODULE_ALIAS("sound-layout-45"); | ||
| 82 | MODULE_ALIAS("sound-layout-51"); | ||
| 83 | MODULE_ALIAS("sound-layout-58"); | ||
| 84 | MODULE_ALIAS("sound-layout-60"); | ||
| 85 | MODULE_ALIAS("sound-layout-61"); | ||
| 86 | MODULE_ALIAS("sound-layout-64"); | ||
| 87 | MODULE_ALIAS("sound-layout-65"); | ||
| 88 | MODULE_ALIAS("sound-layout-68"); | ||
| 89 | MODULE_ALIAS("sound-layout-69"); | ||
| 90 | MODULE_ALIAS("sound-layout-70"); | ||
| 91 | MODULE_ALIAS("sound-layout-72"); | ||
| 92 | MODULE_ALIAS("sound-layout-80"); | ||
| 93 | MODULE_ALIAS("sound-layout-82"); | ||
| 94 | MODULE_ALIAS("sound-layout-84"); | ||
| 95 | MODULE_ALIAS("sound-layout-86"); | ||
| 96 | MODULE_ALIAS("sound-layout-92"); | ||
| 97 | |||
| 98 | /* onyx with all but microphone connected */ | ||
| 99 | static struct codec_connection onyx_connections_nomic[] = { | ||
| 100 | { | ||
| 101 | .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT, | ||
| 102 | .codec_bit = 0, | ||
| 103 | }, | ||
| 104 | { | ||
| 105 | .connected = CC_DIGITALOUT, | ||
| 106 | .codec_bit = 1, | ||
| 107 | }, | ||
| 108 | { | ||
| 109 | .connected = CC_LINEIN, | ||
| 110 | .codec_bit = 2, | ||
| 111 | }, | ||
| 112 | {} /* terminate array by .connected == 0 */ | ||
| 113 | }; | ||
| 114 | |||
| 115 | /* onyx on machines without headphone */ | ||
| 116 | static struct codec_connection onyx_connections_noheadphones[] = { | ||
| 117 | { | ||
| 118 | .connected = CC_SPEAKERS | CC_LINEOUT | | ||
| 119 | CC_LINEOUT_LABELLED_HEADPHONE, | ||
| 120 | .codec_bit = 0, | ||
| 121 | }, | ||
| 122 | { | ||
| 123 | .connected = CC_DIGITALOUT, | ||
| 124 | .codec_bit = 1, | ||
| 125 | }, | ||
| 126 | /* FIXME: are these correct? probably not for all the machines | ||
| 127 | * below ... If not this will need separating. */ | ||
| 128 | { | ||
| 129 | .connected = CC_LINEIN, | ||
| 130 | .codec_bit = 2, | ||
| 131 | }, | ||
| 132 | { | ||
| 133 | .connected = CC_MICROPHONE, | ||
| 134 | .codec_bit = 3, | ||
| 135 | }, | ||
| 136 | {} /* terminate array by .connected == 0 */ | ||
| 137 | }; | ||
| 138 | |||
| 139 | /* onyx on machines with real line-out */ | ||
| 140 | static struct codec_connection onyx_connections_reallineout[] = { | ||
| 141 | { | ||
| 142 | .connected = CC_SPEAKERS | CC_LINEOUT | CC_HEADPHONE, | ||
| 143 | .codec_bit = 0, | ||
| 144 | }, | ||
| 145 | { | ||
| 146 | .connected = CC_DIGITALOUT, | ||
| 147 | .codec_bit = 1, | ||
| 148 | }, | ||
| 149 | { | ||
| 150 | .connected = CC_LINEIN, | ||
| 151 | .codec_bit = 2, | ||
| 152 | }, | ||
| 153 | {} /* terminate array by .connected == 0 */ | ||
| 154 | }; | ||
| 155 | |||
| 156 | /* tas on machines without line out */ | ||
| 157 | static struct codec_connection tas_connections_nolineout[] = { | ||
| 158 | { | ||
| 159 | .connected = CC_SPEAKERS | CC_HEADPHONE, | ||
| 160 | .codec_bit = 0, | ||
| 161 | }, | ||
| 162 | { | ||
| 163 | .connected = CC_LINEIN, | ||
| 164 | .codec_bit = 2, | ||
| 165 | }, | ||
| 166 | { | ||
| 167 | .connected = CC_MICROPHONE, | ||
| 168 | .codec_bit = 3, | ||
| 169 | }, | ||
| 170 | {} /* terminate array by .connected == 0 */ | ||
| 171 | }; | ||
| 172 | |||
| 173 | /* tas on machines with neither line out nor line in */ | ||
| 174 | static struct codec_connection tas_connections_noline[] = { | ||
| 175 | { | ||
| 176 | .connected = CC_SPEAKERS | CC_HEADPHONE, | ||
| 177 | .codec_bit = 0, | ||
| 178 | }, | ||
| 179 | { | ||
| 180 | .connected = CC_MICROPHONE, | ||
| 181 | .codec_bit = 3, | ||
| 182 | }, | ||
| 183 | {} /* terminate array by .connected == 0 */ | ||
| 184 | }; | ||
| 185 | |||
| 186 | /* tas on machines without microphone */ | ||
| 187 | static struct codec_connection tas_connections_nomic[] = { | ||
| 188 | { | ||
| 189 | .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT, | ||
| 190 | .codec_bit = 0, | ||
| 191 | }, | ||
| 192 | { | ||
| 193 | .connected = CC_LINEIN, | ||
| 194 | .codec_bit = 2, | ||
| 195 | }, | ||
| 196 | {} /* terminate array by .connected == 0 */ | ||
| 197 | }; | ||
| 198 | |||
| 199 | /* tas on machines with everything connected */ | ||
| 200 | static struct codec_connection tas_connections_all[] = { | ||
| 201 | { | ||
| 202 | .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT, | ||
| 203 | .codec_bit = 0, | ||
| 204 | }, | ||
| 205 | { | ||
| 206 | .connected = CC_LINEIN, | ||
| 207 | .codec_bit = 2, | ||
| 208 | }, | ||
| 209 | { | ||
| 210 | .connected = CC_MICROPHONE, | ||
| 211 | .codec_bit = 3, | ||
| 212 | }, | ||
| 213 | {} /* terminate array by .connected == 0 */ | ||
| 214 | }; | ||
| 215 | |||
| 216 | static struct codec_connection toonie_connections[] = { | ||
| 217 | { | ||
| 218 | .connected = CC_SPEAKERS | CC_HEADPHONE, | ||
| 219 | .codec_bit = 0, | ||
| 220 | }, | ||
| 221 | {} /* terminate array by .connected == 0 */ | ||
| 222 | }; | ||
| 223 | |||
| 224 | static struct codec_connection topaz_input[] = { | ||
| 225 | { | ||
| 226 | .connected = CC_DIGITALIN, | ||
| 227 | .codec_bit = 0, | ||
| 228 | }, | ||
| 229 | {} /* terminate array by .connected == 0 */ | ||
| 230 | }; | ||
| 231 | |||
| 232 | static struct codec_connection topaz_output[] = { | ||
| 233 | { | ||
| 234 | .connected = CC_DIGITALOUT, | ||
| 235 | .codec_bit = 1, | ||
| 236 | }, | ||
| 237 | {} /* terminate array by .connected == 0 */ | ||
| 238 | }; | ||
| 239 | |||
| 240 | static struct codec_connection topaz_inout[] = { | ||
| 241 | { | ||
| 242 | .connected = CC_DIGITALIN, | ||
| 243 | .codec_bit = 0, | ||
| 244 | }, | ||
| 245 | { | ||
| 246 | .connected = CC_DIGITALOUT, | ||
| 247 | .codec_bit = 1, | ||
| 248 | }, | ||
| 249 | {} /* terminate array by .connected == 0 */ | ||
| 250 | }; | ||
| 251 | |||
| 252 | static struct layout layouts[] = { | ||
| 253 | /* last PowerBooks (15" Oct 2005) */ | ||
| 254 | { .layout_id = 82, | ||
| 255 | .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF, | ||
| 256 | .codecs[0] = { | ||
| 257 | .name = "onyx", | ||
| 258 | .connections = onyx_connections_noheadphones, | ||
| 259 | }, | ||
| 260 | .codecs[1] = { | ||
| 261 | .name = "topaz", | ||
| 262 | .connections = topaz_input, | ||
| 263 | }, | ||
| 264 | }, | ||
| 265 | /* PowerMac9,1 */ | ||
| 266 | { .layout_id = 60, | ||
| 267 | .codecs[0] = { | ||
| 268 | .name = "onyx", | ||
| 269 | .connections = onyx_connections_reallineout, | ||
| 270 | }, | ||
| 271 | }, | ||
| 272 | /* PowerMac9,1 */ | ||
| 273 | { .layout_id = 61, | ||
| 274 | .codecs[0] = { | ||
| 275 | .name = "topaz", | ||
| 276 | .connections = topaz_input, | ||
| 277 | }, | ||
| 278 | }, | ||
| 279 | /* PowerBook5,7 */ | ||
| 280 | { .layout_id = 64, | ||
| 281 | .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF, | ||
| 282 | .codecs[0] = { | ||
| 283 | .name = "onyx", | ||
| 284 | .connections = onyx_connections_noheadphones, | ||
| 285 | }, | ||
| 286 | }, | ||
| 287 | /* PowerBook5,7 */ | ||
| 288 | { .layout_id = 65, | ||
| 289 | .codecs[0] = { | ||
| 290 | .name = "topaz", | ||
| 291 | .connections = topaz_input, | ||
| 292 | }, | ||
| 293 | }, | ||
| 294 | /* PowerBook5,9 [17" Oct 2005] */ | ||
| 295 | { .layout_id = 84, | ||
| 296 | .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF, | ||
| 297 | .codecs[0] = { | ||
| 298 | .name = "onyx", | ||
| 299 | .connections = onyx_connections_noheadphones, | ||
| 300 | }, | ||
| 301 | .codecs[1] = { | ||
| 302 | .name = "topaz", | ||
| 303 | .connections = topaz_input, | ||
| 304 | }, | ||
| 305 | }, | ||
| 306 | /* PowerMac8,1 */ | ||
| 307 | { .layout_id = 45, | ||
| 308 | .codecs[0] = { | ||
| 309 | .name = "onyx", | ||
| 310 | .connections = onyx_connections_noheadphones, | ||
| 311 | }, | ||
| 312 | .codecs[1] = { | ||
| 313 | .name = "topaz", | ||
| 314 | .connections = topaz_input, | ||
| 315 | }, | ||
| 316 | }, | ||
| 317 | /* Quad PowerMac (analog in, analog/digital out) */ | ||
| 318 | { .layout_id = 68, | ||
| 319 | .codecs[0] = { | ||
| 320 | .name = "onyx", | ||
| 321 | .connections = onyx_connections_nomic, | ||
| 322 | }, | ||
| 323 | }, | ||
| 324 | /* Quad PowerMac (digital in) */ | ||
| 325 | { .layout_id = 69, | ||
| 326 | .codecs[0] = { | ||
| 327 | .name = "topaz", | ||
| 328 | .connections = topaz_input, | ||
| 329 | }, | ||
| 330 | .busname = "digital in", .pcmid = 1 }, | ||
| 331 | /* Early 2005 PowerBook (PowerBook 5,6) */ | ||
| 332 | { .layout_id = 70, | ||
| 333 | .codecs[0] = { | ||
| 334 | .name = "tas", | ||
| 335 | .connections = tas_connections_nolineout, | ||
| 336 | }, | ||
| 337 | }, | ||
| 338 | /* PowerBook 5,4 */ | ||
| 339 | { .layout_id = 51, | ||
| 340 | .codecs[0] = { | ||
| 341 | .name = "tas", | ||
| 342 | .connections = tas_connections_nolineout, | ||
| 343 | }, | ||
| 344 | }, | ||
| 345 | /* PowerBook6,7 */ | ||
| 346 | { .layout_id = 80, | ||
| 347 | .codecs[0] = { | ||
| 348 | .name = "tas", | ||
| 349 | .connections = tas_connections_noline, | ||
| 350 | }, | ||
| 351 | }, | ||
| 352 | /* PowerBook6,8 */ | ||
| 353 | { .layout_id = 72, | ||
| 354 | .codecs[0] = { | ||
| 355 | .name = "tas", | ||
| 356 | .connections = tas_connections_nolineout, | ||
| 357 | }, | ||
| 358 | }, | ||
| 359 | /* PowerMac8,2 */ | ||
| 360 | { .layout_id = 86, | ||
| 361 | .codecs[0] = { | ||
| 362 | .name = "onyx", | ||
| 363 | .connections = onyx_connections_nomic, | ||
| 364 | }, | ||
| 365 | .codecs[1] = { | ||
| 366 | .name = "topaz", | ||
| 367 | .connections = topaz_input, | ||
| 368 | }, | ||
| 369 | }, | ||
| 370 | /* PowerBook6,7 */ | ||
| 371 | { .layout_id = 92, | ||
| 372 | .codecs[0] = { | ||
| 373 | .name = "tas", | ||
| 374 | .connections = tas_connections_nolineout, | ||
| 375 | }, | ||
| 376 | }, | ||
| 377 | /* PowerMac10,1 (Mac Mini) */ | ||
| 378 | { .layout_id = 58, | ||
| 379 | .codecs[0] = { | ||
| 380 | .name = "toonie", | ||
| 381 | .connections = toonie_connections, | ||
| 382 | }, | ||
| 383 | }, | ||
| 384 | /* unknown, untested, but this comes from Apple */ | ||
| 385 | { .layout_id = 41, | ||
| 386 | .codecs[0] = { | ||
| 387 | .name = "tas", | ||
| 388 | .connections = tas_connections_all, | ||
| 389 | }, | ||
| 390 | }, | ||
| 391 | { .layout_id = 36, | ||
| 392 | .codecs[0] = { | ||
| 393 | .name = "tas", | ||
| 394 | .connections = tas_connections_nomic, | ||
| 395 | }, | ||
| 396 | .codecs[1] = { | ||
| 397 | .name = "topaz", | ||
| 398 | .connections = topaz_inout, | ||
| 399 | }, | ||
| 400 | }, | ||
| 401 | { .layout_id = 47, | ||
| 402 | .codecs[0] = { | ||
| 403 | .name = "onyx", | ||
| 404 | .connections = onyx_connections_noheadphones, | ||
| 405 | }, | ||
| 406 | }, | ||
| 407 | { .layout_id = 48, | ||
| 408 | .codecs[0] = { | ||
| 409 | .name = "topaz", | ||
| 410 | .connections = topaz_input, | ||
| 411 | }, | ||
| 412 | }, | ||
| 413 | { .layout_id = 49, | ||
| 414 | .codecs[0] = { | ||
| 415 | .name = "onyx", | ||
| 416 | .connections = onyx_connections_nomic, | ||
| 417 | }, | ||
| 418 | }, | ||
| 419 | { .layout_id = 50, | ||
| 420 | .codecs[0] = { | ||
| 421 | .name = "topaz", | ||
| 422 | .connections = topaz_input, | ||
| 423 | }, | ||
| 424 | }, | ||
| 425 | { .layout_id = 56, | ||
| 426 | .codecs[0] = { | ||
| 427 | .name = "onyx", | ||
| 428 | .connections = onyx_connections_noheadphones, | ||
| 429 | }, | ||
| 430 | }, | ||
| 431 | { .layout_id = 57, | ||
| 432 | .codecs[0] = { | ||
| 433 | .name = "topaz", | ||
| 434 | .connections = topaz_input, | ||
| 435 | }, | ||
| 436 | }, | ||
| 437 | { .layout_id = 62, | ||
| 438 | .codecs[0] = { | ||
| 439 | .name = "onyx", | ||
| 440 | .connections = onyx_connections_noheadphones, | ||
| 441 | }, | ||
| 442 | .codecs[1] = { | ||
| 443 | .name = "topaz", | ||
| 444 | .connections = topaz_output, | ||
| 445 | }, | ||
| 446 | }, | ||
| 447 | { .layout_id = 66, | ||
| 448 | .codecs[0] = { | ||
| 449 | .name = "onyx", | ||
| 450 | .connections = onyx_connections_noheadphones, | ||
| 451 | }, | ||
| 452 | }, | ||
| 453 | { .layout_id = 67, | ||
| 454 | .codecs[0] = { | ||
| 455 | .name = "topaz", | ||
| 456 | .connections = topaz_input, | ||
| 457 | }, | ||
| 458 | }, | ||
| 459 | { .layout_id = 76, | ||
| 460 | .codecs[0] = { | ||
| 461 | .name = "tas", | ||
| 462 | .connections = tas_connections_nomic, | ||
| 463 | }, | ||
| 464 | .codecs[1] = { | ||
| 465 | .name = "topaz", | ||
| 466 | .connections = topaz_inout, | ||
| 467 | }, | ||
| 468 | }, | ||
| 469 | { .layout_id = 90, | ||
| 470 | .codecs[0] = { | ||
| 471 | .name = "tas", | ||
| 472 | .connections = tas_connections_noline, | ||
| 473 | }, | ||
| 474 | }, | ||
| 475 | { .layout_id = 94, | ||
| 476 | .codecs[0] = { | ||
| 477 | .name = "onyx", | ||
| 478 | /* but it has an external mic?? how to select? */ | ||
| 479 | .connections = onyx_connections_noheadphones, | ||
| 480 | }, | ||
| 481 | }, | ||
| 482 | { .layout_id = 96, | ||
| 483 | .codecs[0] = { | ||
| 484 | .name = "onyx", | ||
| 485 | .connections = onyx_connections_noheadphones, | ||
| 486 | }, | ||
| 487 | }, | ||
| 488 | { .layout_id = 98, | ||
| 489 | .codecs[0] = { | ||
| 490 | .name = "toonie", | ||
| 491 | .connections = toonie_connections, | ||
| 492 | }, | ||
| 493 | }, | ||
| 494 | { .layout_id = 100, | ||
| 495 | .codecs[0] = { | ||
| 496 | .name = "topaz", | ||
| 497 | .connections = topaz_input, | ||
| 498 | }, | ||
| 499 | .codecs[1] = { | ||
| 500 | .name = "onyx", | ||
| 501 | .connections = onyx_connections_noheadphones, | ||
| 502 | }, | ||
| 503 | }, | ||
| 504 | {} | ||
| 505 | }; | ||
| 506 | |||
| 507 | static struct layout *find_layout_by_id(unsigned int id) | ||
| 508 | { | ||
| 509 | struct layout *l; | ||
| 510 | |||
| 511 | l = layouts; | ||
| 512 | while (l->layout_id) { | ||
| 513 | if (l->layout_id == id) | ||
| 514 | return l; | ||
| 515 | l++; | ||
| 516 | } | ||
| 517 | return NULL; | ||
| 518 | } | ||
| 519 | |||
| 520 | static void use_layout(struct layout *l) | ||
| 521 | { | ||
| 522 | int i; | ||
| 523 | |||
| 524 | for (i=0; i<MAX_CODECS_PER_BUS; i++) { | ||
| 525 | if (l->codecs[i].name) { | ||
| 526 | request_module("snd-aoa-codec-%s", l->codecs[i].name); | ||
| 527 | } | ||
| 528 | } | ||
| 529 | /* now we wait for the codecs to call us back */ | ||
| 530 | } | ||
| 531 | |||
| 532 | struct layout_dev; | ||
| 533 | |||
| 534 | struct layout_dev_ptr { | ||
| 535 | struct layout_dev *ptr; | ||
| 536 | }; | ||
| 537 | |||
| 538 | struct layout_dev { | ||
| 539 | struct list_head list; | ||
| 540 | struct soundbus_dev *sdev; | ||
| 541 | struct device_node *sound; | ||
| 542 | struct aoa_codec *codecs[MAX_CODECS_PER_BUS]; | ||
| 543 | struct layout *layout; | ||
| 544 | struct gpio_runtime gpio; | ||
| 545 | |||
| 546 | /* we need these for headphone/lineout detection */ | ||
| 547 | struct snd_kcontrol *headphone_ctrl; | ||
| 548 | struct snd_kcontrol *lineout_ctrl; | ||
| 549 | struct snd_kcontrol *speaker_ctrl; | ||
| 550 | struct snd_kcontrol *headphone_detected_ctrl; | ||
| 551 | struct snd_kcontrol *lineout_detected_ctrl; | ||
| 552 | |||
| 553 | struct layout_dev_ptr selfptr_headphone; | ||
| 554 | struct layout_dev_ptr selfptr_lineout; | ||
| 555 | |||
| 556 | u32 have_lineout_detect:1, | ||
| 557 | have_headphone_detect:1, | ||
| 558 | switch_on_headphone:1, | ||
| 559 | switch_on_lineout:1; | ||
| 560 | }; | ||
| 561 | |||
| 562 | static LIST_HEAD(layouts_list); | ||
| 563 | static int layouts_list_items; | ||
| 564 | /* this can go away but only if we allow multiple cards, | ||
| 565 | * make the fabric handle all the card stuff, etc... */ | ||
| 566 | static struct layout_dev *layout_device; | ||
| 567 | |||
| 568 | static int control_info(struct snd_kcontrol *kcontrol, | ||
| 569 | struct snd_ctl_elem_info *uinfo) | ||
| 570 | { | ||
| 571 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
| 572 | uinfo->count = 1; | ||
| 573 | uinfo->value.integer.min = 0; | ||
| 574 | uinfo->value.integer.max = 1; | ||
| 575 | return 0; | ||
| 576 | } | ||
| 577 | |||
| 578 | #define AMP_CONTROL(n, description) \ | ||
| 579 | static int n##_control_get(struct snd_kcontrol *kcontrol, \ | ||
| 580 | struct snd_ctl_elem_value *ucontrol) \ | ||
| 581 | { \ | ||
| 582 | struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \ | ||
| 583 | if (gpio->methods && gpio->methods->get_##n) \ | ||
| 584 | ucontrol->value.integer.value[0] = \ | ||
| 585 | gpio->methods->get_##n(gpio); \ | ||
| 586 | return 0; \ | ||
| 587 | } \ | ||
| 588 | static int n##_control_put(struct snd_kcontrol *kcontrol, \ | ||
| 589 | struct snd_ctl_elem_value *ucontrol) \ | ||
| 590 | { \ | ||
| 591 | struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \ | ||
| 592 | if (gpio->methods && gpio->methods->get_##n) \ | ||
| 593 | gpio->methods->set_##n(gpio, \ | ||
| 594 | ucontrol->value.integer.value[0]); \ | ||
| 595 | return 1; \ | ||
| 596 | } \ | ||
| 597 | static struct snd_kcontrol_new n##_ctl = { \ | ||
| 598 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
| 599 | .name = description, \ | ||
| 600 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
| 601 | .info = control_info, \ | ||
| 602 | .get = n##_control_get, \ | ||
| 603 | .put = n##_control_put, \ | ||
| 604 | } | ||
| 605 | |||
| 606 | AMP_CONTROL(headphone, "Headphone Switch"); | ||
| 607 | AMP_CONTROL(speakers, "Speakers Switch"); | ||
| 608 | AMP_CONTROL(lineout, "Line-Out Switch"); | ||
| 609 | |||
| 610 | static int detect_choice_get(struct snd_kcontrol *kcontrol, | ||
| 611 | struct snd_ctl_elem_value *ucontrol) | ||
| 612 | { | ||
| 613 | struct layout_dev *ldev = snd_kcontrol_chip(kcontrol); | ||
| 614 | |||
| 615 | switch (kcontrol->private_value) { | ||
| 616 | case 0: | ||
| 617 | ucontrol->value.integer.value[0] = ldev->switch_on_headphone; | ||
| 618 | break; | ||
| 619 | case 1: | ||
| 620 | ucontrol->value.integer.value[0] = ldev->switch_on_lineout; | ||
| 621 | break; | ||
| 622 | default: | ||
| 623 | return -ENODEV; | ||
| 624 | } | ||
| 625 | return 0; | ||
| 626 | } | ||
| 627 | |||
| 628 | static int detect_choice_put(struct snd_kcontrol *kcontrol, | ||
| 629 | struct snd_ctl_elem_value *ucontrol) | ||
| 630 | { | ||
| 631 | struct layout_dev *ldev = snd_kcontrol_chip(kcontrol); | ||
| 632 | |||
| 633 | switch (kcontrol->private_value) { | ||
| 634 | case 0: | ||
| 635 | ldev->switch_on_headphone = !!ucontrol->value.integer.value[0]; | ||
| 636 | break; | ||
| 637 | case 1: | ||
| 638 | ldev->switch_on_lineout = !!ucontrol->value.integer.value[0]; | ||
| 639 | break; | ||
| 640 | default: | ||
| 641 | return -ENODEV; | ||
| 642 | } | ||
| 643 | return 1; | ||
| 644 | } | ||
| 645 | |||
| 646 | static struct snd_kcontrol_new headphone_detect_choice = { | ||
| 647 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 648 | .name = "Headphone Detect Autoswitch", | ||
| 649 | .info = control_info, | ||
| 650 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 651 | .get = detect_choice_get, | ||
| 652 | .put = detect_choice_put, | ||
| 653 | .private_value = 0, | ||
| 654 | }; | ||
| 655 | |||
| 656 | static struct snd_kcontrol_new lineout_detect_choice = { | ||
| 657 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 658 | .name = "Line-Out Detect Autoswitch", | ||
| 659 | .info = control_info, | ||
| 660 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
| 661 | .get = detect_choice_get, | ||
| 662 | .put = detect_choice_put, | ||
| 663 | .private_value = 1, | ||
| 664 | }; | ||
| 665 | |||
| 666 | static int detected_get(struct snd_kcontrol *kcontrol, | ||
| 667 | struct snd_ctl_elem_value *ucontrol) | ||
| 668 | { | ||
| 669 | struct layout_dev *ldev = snd_kcontrol_chip(kcontrol); | ||
| 670 | int v; | ||
| 671 | |||
| 672 | switch (kcontrol->private_value) { | ||
| 673 | case 0: | ||
| 674 | v = ldev->gpio.methods->get_detect(&ldev->gpio, | ||
| 675 | AOA_NOTIFY_HEADPHONE); | ||
| 676 | break; | ||
| 677 | case 1: | ||
| 678 | v = ldev->gpio.methods->get_detect(&ldev->gpio, | ||
| 679 | AOA_NOTIFY_LINE_OUT); | ||
| 680 | break; | ||
| 681 | default: | ||
| 682 | return -ENODEV; | ||
| 683 | } | ||
| 684 | ucontrol->value.integer.value[0] = v; | ||
| 685 | return 0; | ||
| 686 | } | ||
| 687 | |||
| 688 | static struct snd_kcontrol_new headphone_detected = { | ||
| 689 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 690 | .name = "Headphone Detected", | ||
| 691 | .info = control_info, | ||
| 692 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
| 693 | .get = detected_get, | ||
| 694 | .private_value = 0, | ||
| 695 | }; | ||
| 696 | |||
| 697 | static struct snd_kcontrol_new lineout_detected = { | ||
| 698 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 699 | .name = "Line-Out Detected", | ||
| 700 | .info = control_info, | ||
| 701 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
| 702 | .get = detected_get, | ||
| 703 | .private_value = 1, | ||
| 704 | }; | ||
| 705 | |||
| 706 | static int check_codec(struct aoa_codec *codec, | ||
| 707 | struct layout_dev *ldev, | ||
| 708 | struct codec_connect_info *cci) | ||
| 709 | { | ||
| 710 | u32 *ref; | ||
| 711 | char propname[32]; | ||
| 712 | struct codec_connection *cc; | ||
| 713 | |||
| 714 | /* if the codec has a 'codec' node, we require a reference */ | ||
| 715 | if (codec->node && (strcmp(codec->node->name, "codec") == 0)) { | ||
| 716 | snprintf(propname, sizeof(propname), | ||
| 717 | "platform-%s-codec-ref", codec->name); | ||
| 718 | ref = (u32*)get_property(ldev->sound, propname, NULL); | ||
| 719 | if (!ref) { | ||
| 720 | printk(KERN_INFO "snd-aoa-fabric-layout: " | ||
| 721 | "required property %s not present\n", propname); | ||
| 722 | return -ENODEV; | ||
| 723 | } | ||
| 724 | if (*ref != codec->node->linux_phandle) { | ||
| 725 | printk(KERN_INFO "snd-aoa-fabric-layout: " | ||
| 726 | "%s doesn't match!\n", propname); | ||
| 727 | return -ENODEV; | ||
| 728 | } | ||
| 729 | } else { | ||
| 730 | if (layouts_list_items != 1) { | ||
| 731 | printk(KERN_INFO "snd-aoa-fabric-layout: " | ||
| 732 | "more than one soundbus, but no references.\n"); | ||
| 733 | return -ENODEV; | ||
| 734 | } | ||
| 735 | } | ||
| 736 | codec->soundbus_dev = ldev->sdev; | ||
| 737 | codec->gpio = &ldev->gpio; | ||
| 738 | |||
| 739 | cc = cci->connections; | ||
| 740 | if (!cc) | ||
| 741 | return -EINVAL; | ||
| 742 | |||
| 743 | printk(KERN_INFO "snd-aoa-fabric-layout: can use this codec\n"); | ||
| 744 | |||
| 745 | codec->connected = 0; | ||
| 746 | codec->fabric_data = cc; | ||
| 747 | |||
| 748 | while (cc->connected) { | ||
| 749 | codec->connected |= 1<<cc->codec_bit; | ||
| 750 | cc++; | ||
| 751 | } | ||
| 752 | |||
| 753 | return 0; | ||
| 754 | } | ||
| 755 | |||
| 756 | static int layout_found_codec(struct aoa_codec *codec) | ||
| 757 | { | ||
| 758 | struct layout_dev *ldev; | ||
| 759 | int i; | ||
| 760 | |||
| 761 | list_for_each_entry(ldev, &layouts_list, list) { | ||
| 762 | for (i=0; i<MAX_CODECS_PER_BUS; i++) { | ||
| 763 | if (!ldev->layout->codecs[i].name) | ||
| 764 | continue; | ||
| 765 | if (strcmp(ldev->layout->codecs[i].name, codec->name) == 0) { | ||
| 766 | if (check_codec(codec, | ||
| 767 | ldev, | ||
| 768 | &ldev->layout->codecs[i]) == 0) | ||
| 769 | return 0; | ||
| 770 | } | ||
| 771 | } | ||
| 772 | } | ||
| 773 | return -ENODEV; | ||
| 774 | } | ||
| 775 | |||
| 776 | static void layout_remove_codec(struct aoa_codec *codec) | ||
| 777 | { | ||
| 778 | int i; | ||
| 779 | /* here remove the codec from the layout dev's | ||
| 780 | * codec reference */ | ||
| 781 | |||
| 782 | codec->soundbus_dev = NULL; | ||
| 783 | codec->gpio = NULL; | ||
| 784 | for (i=0; i<MAX_CODECS_PER_BUS; i++) { | ||
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 788 | static void layout_notify(void *data) | ||
| 789 | { | ||
| 790 | struct layout_dev_ptr *dptr = data; | ||
| 791 | struct layout_dev *ldev; | ||
| 792 | int v, update; | ||
| 793 | struct snd_kcontrol *detected, *c; | ||
| 794 | struct snd_card *card = aoa_get_card(); | ||
| 795 | |||
| 796 | ldev = dptr->ptr; | ||
| 797 | if (data == &ldev->selfptr_headphone) { | ||
| 798 | v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_HEADPHONE); | ||
| 799 | detected = ldev->headphone_detected_ctrl; | ||
| 800 | update = ldev->switch_on_headphone; | ||
| 801 | if (update) { | ||
| 802 | ldev->gpio.methods->set_speakers(&ldev->gpio, !v); | ||
| 803 | ldev->gpio.methods->set_headphone(&ldev->gpio, v); | ||
| 804 | ldev->gpio.methods->set_lineout(&ldev->gpio, 0); | ||
| 805 | } | ||
| 806 | } else if (data == &ldev->selfptr_lineout) { | ||
| 807 | v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_LINE_OUT); | ||
| 808 | detected = ldev->lineout_detected_ctrl; | ||
| 809 | update = ldev->switch_on_lineout; | ||
| 810 | if (update) { | ||
| 811 | ldev->gpio.methods->set_speakers(&ldev->gpio, !v); | ||
| 812 | ldev->gpio.methods->set_headphone(&ldev->gpio, 0); | ||
| 813 | ldev->gpio.methods->set_lineout(&ldev->gpio, v); | ||
| 814 | } | ||
| 815 | } else | ||
| 816 | return; | ||
| 817 | |||
| 818 | if (detected) | ||
| 819 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &detected->id); | ||
| 820 | if (update) { | ||
| 821 | c = ldev->headphone_ctrl; | ||
| 822 | if (c) | ||
| 823 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id); | ||
| 824 | c = ldev->speaker_ctrl; | ||
| 825 | if (c) | ||
| 826 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id); | ||
| 827 | c = ldev->lineout_ctrl; | ||
| 828 | if (c) | ||
| 829 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id); | ||
| 830 | } | ||
| 831 | } | ||
| 832 | |||
| 833 | static void layout_attached_codec(struct aoa_codec *codec) | ||
| 834 | { | ||
| 835 | struct codec_connection *cc; | ||
| 836 | struct snd_kcontrol *ctl; | ||
| 837 | int headphones, lineout; | ||
| 838 | struct layout_dev *ldev = layout_device; | ||
| 839 | |||
| 840 | /* need to add this codec to our codec array! */ | ||
| 841 | |||
| 842 | cc = codec->fabric_data; | ||
| 843 | |||
| 844 | headphones = codec->gpio->methods->get_detect(codec->gpio, | ||
| 845 | AOA_NOTIFY_HEADPHONE); | ||
| 846 | lineout = codec->gpio->methods->get_detect(codec->gpio, | ||
| 847 | AOA_NOTIFY_LINE_OUT); | ||
| 848 | |||
| 849 | while (cc->connected) { | ||
| 850 | if (cc->connected & CC_SPEAKERS) { | ||
| 851 | if (headphones <= 0 && lineout <= 0) | ||
| 852 | ldev->gpio.methods->set_speakers(codec->gpio, 1); | ||
| 853 | ctl = snd_ctl_new1(&speakers_ctl, codec->gpio); | ||
| 854 | ldev->speaker_ctrl = ctl; | ||
| 855 | aoa_snd_ctl_add(ctl); | ||
| 856 | } | ||
| 857 | if (cc->connected & CC_HEADPHONE) { | ||
| 858 | if (headphones == 1) | ||
| 859 | ldev->gpio.methods->set_headphone(codec->gpio, 1); | ||
| 860 | ctl = snd_ctl_new1(&headphone_ctl, codec->gpio); | ||
| 861 | ldev->headphone_ctrl = ctl; | ||
| 862 | aoa_snd_ctl_add(ctl); | ||
| 863 | ldev->have_headphone_detect = | ||
| 864 | !ldev->gpio.methods | ||
| 865 | ->set_notify(&ldev->gpio, | ||
| 866 | AOA_NOTIFY_HEADPHONE, | ||
| 867 | layout_notify, | ||
| 868 | &ldev->selfptr_headphone); | ||
| 869 | if (ldev->have_headphone_detect) { | ||
| 870 | ctl = snd_ctl_new1(&headphone_detect_choice, | ||
| 871 | ldev); | ||
| 872 | aoa_snd_ctl_add(ctl); | ||
| 873 | ctl = snd_ctl_new1(&headphone_detected, | ||
| 874 | ldev); | ||
| 875 | ldev->headphone_detected_ctrl = ctl; | ||
| 876 | aoa_snd_ctl_add(ctl); | ||
| 877 | } | ||
| 878 | } | ||
| 879 | if (cc->connected & CC_LINEOUT) { | ||
| 880 | if (lineout == 1) | ||
| 881 | ldev->gpio.methods->set_lineout(codec->gpio, 1); | ||
| 882 | ctl = snd_ctl_new1(&lineout_ctl, codec->gpio); | ||
| 883 | if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) | ||
| 884 | strlcpy(ctl->id.name, | ||
| 885 | "Headphone Switch", sizeof(ctl->id.name)); | ||
| 886 | ldev->lineout_ctrl = ctl; | ||
| 887 | aoa_snd_ctl_add(ctl); | ||
| 888 | ldev->have_lineout_detect = | ||
| 889 | !ldev->gpio.methods | ||
| 890 | ->set_notify(&ldev->gpio, | ||
| 891 | AOA_NOTIFY_LINE_OUT, | ||
| 892 | layout_notify, | ||
| 893 | &ldev->selfptr_lineout); | ||
| 894 | if (ldev->have_lineout_detect) { | ||
| 895 | ctl = snd_ctl_new1(&lineout_detect_choice, | ||
| 896 | ldev); | ||
| 897 | if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) | ||
| 898 | strlcpy(ctl->id.name, | ||
| 899 | "Headphone Detect Autoswitch", | ||
| 900 | sizeof(ctl->id.name)); | ||
| 901 | aoa_snd_ctl_add(ctl); | ||
| 902 | ctl = snd_ctl_new1(&lineout_detected, | ||
| 903 | ldev); | ||
| 904 | if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE) | ||
| 905 | strlcpy(ctl->id.name, | ||
| 906 | "Headphone Detected", | ||
| 907 | sizeof(ctl->id.name)); | ||
| 908 | ldev->lineout_detected_ctrl = ctl; | ||
| 909 | aoa_snd_ctl_add(ctl); | ||
| 910 | } | ||
| 911 | } | ||
| 912 | cc++; | ||
| 913 | } | ||
| 914 | /* now update initial state */ | ||
| 915 | if (ldev->have_headphone_detect) | ||
| 916 | layout_notify(&ldev->selfptr_headphone); | ||
| 917 | if (ldev->have_lineout_detect) | ||
| 918 | layout_notify(&ldev->selfptr_lineout); | ||
| 919 | } | ||
| 920 | |||
| 921 | static struct aoa_fabric layout_fabric = { | ||
| 922 | .name = "SoundByLayout", | ||
| 923 | .owner = THIS_MODULE, | ||
| 924 | .found_codec = layout_found_codec, | ||
| 925 | .remove_codec = layout_remove_codec, | ||
| 926 | .attached_codec = layout_attached_codec, | ||
| 927 | }; | ||
| 928 | |||
| 929 | static int aoa_fabric_layout_probe(struct soundbus_dev *sdev) | ||
| 930 | { | ||
| 931 | struct device_node *sound = NULL; | ||
| 932 | unsigned int *layout_id; | ||
| 933 | struct layout *layout; | ||
| 934 | struct layout_dev *ldev = NULL; | ||
| 935 | int err; | ||
| 936 | |||
| 937 | /* hm, currently we can only have one ... */ | ||
| 938 | if (layout_device) | ||
| 939 | return -ENODEV; | ||
| 940 | |||
| 941 | /* by breaking out we keep a reference */ | ||
| 942 | while ((sound = of_get_next_child(sdev->ofdev.node, sound))) { | ||
| 943 | if (sound->type && strcasecmp(sound->type, "soundchip") == 0) | ||
| 944 | break; | ||
| 945 | } | ||
| 946 | if (!sound) return -ENODEV; | ||
| 947 | |||
| 948 | layout_id = (unsigned int *) get_property(sound, "layout-id", NULL); | ||
| 949 | if (!layout_id) | ||
| 950 | goto outnodev; | ||
| 951 | printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d ", *layout_id); | ||
| 952 | |||
| 953 | layout = find_layout_by_id(*layout_id); | ||
| 954 | if (!layout) { | ||
| 955 | printk("(no idea how to handle)\n"); | ||
| 956 | goto outnodev; | ||
| 957 | } | ||
| 958 | |||
| 959 | ldev = kzalloc(sizeof(struct layout_dev), GFP_KERNEL); | ||
| 960 | if (!ldev) | ||
| 961 | goto outnodev; | ||
| 962 | |||
| 963 | layout_device = ldev; | ||
| 964 | ldev->sdev = sdev; | ||
| 965 | ldev->sound = sound; | ||
| 966 | ldev->layout = layout; | ||
| 967 | ldev->gpio.node = sound->parent; | ||
| 968 | switch (layout->layout_id) { | ||
| 969 | case 41: /* that unknown machine no one seems to have */ | ||
| 970 | case 51: /* PowerBook5,4 */ | ||
| 971 | case 58: /* Mac Mini */ | ||
| 972 | ldev->gpio.methods = ftr_gpio_methods; | ||
| 973 | break; | ||
| 974 | default: | ||
| 975 | ldev->gpio.methods = pmf_gpio_methods; | ||
| 976 | } | ||
| 977 | ldev->selfptr_headphone.ptr = ldev; | ||
| 978 | ldev->selfptr_lineout.ptr = ldev; | ||
| 979 | sdev->ofdev.dev.driver_data = ldev; | ||
| 980 | |||
| 981 | printk("(using)\n"); | ||
| 982 | list_add(&ldev->list, &layouts_list); | ||
| 983 | layouts_list_items++; | ||
| 984 | |||
| 985 | /* assign these before registering ourselves, so | ||
| 986 | * callbacks that are done during registration | ||
| 987 | * already have the values */ | ||
| 988 | sdev->pcmid = ldev->layout->pcmid; | ||
| 989 | if (ldev->layout->busname) { | ||
| 990 | sdev->pcmname = ldev->layout->busname; | ||
| 991 | } else { | ||
| 992 | sdev->pcmname = "Master"; | ||
| 993 | } | ||
| 994 | |||
| 995 | ldev->gpio.methods->init(&ldev->gpio); | ||
| 996 | |||
| 997 | err = aoa_fabric_register(&layout_fabric); | ||
| 998 | if (err && err != -EALREADY) { | ||
| 999 | printk(KERN_INFO "snd-aoa-fabric-layout: can't use," | ||
| 1000 | " another fabric is active!\n"); | ||
| 1001 | goto outlistdel; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | use_layout(layout); | ||
| 1005 | ldev->switch_on_headphone = 1; | ||
| 1006 | ldev->switch_on_lineout = 1; | ||
| 1007 | return 0; | ||
| 1008 | outlistdel: | ||
| 1009 | /* we won't be using these then... */ | ||
| 1010 | ldev->gpio.methods->exit(&ldev->gpio); | ||
| 1011 | /* reset if we didn't use it */ | ||
| 1012 | sdev->pcmname = NULL; | ||
| 1013 | sdev->pcmid = -1; | ||
| 1014 | list_del(&ldev->list); | ||
| 1015 | layouts_list_items--; | ||
| 1016 | outnodev: | ||
| 1017 | if (sound) of_node_put(sound); | ||
| 1018 | layout_device = NULL; | ||
| 1019 | if (ldev) kfree(ldev); | ||
| 1020 | return -ENODEV; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | static int aoa_fabric_layout_remove(struct soundbus_dev *sdev) | ||
| 1024 | { | ||
| 1025 | struct layout_dev *ldev = sdev->ofdev.dev.driver_data; | ||
| 1026 | int i; | ||
| 1027 | |||
| 1028 | for (i=0; i<MAX_CODECS_PER_BUS; i++) { | ||
| 1029 | if (ldev->codecs[i]) { | ||
| 1030 | aoa_fabric_unlink_codec(ldev->codecs[i]); | ||
| 1031 | } | ||
| 1032 | ldev->codecs[i] = NULL; | ||
| 1033 | } | ||
| 1034 | list_del(&ldev->list); | ||
| 1035 | layouts_list_items--; | ||
| 1036 | of_node_put(ldev->sound); | ||
| 1037 | |||
| 1038 | ldev->gpio.methods->set_notify(&ldev->gpio, | ||
| 1039 | AOA_NOTIFY_HEADPHONE, | ||
| 1040 | NULL, | ||
| 1041 | NULL); | ||
| 1042 | ldev->gpio.methods->set_notify(&ldev->gpio, | ||
| 1043 | AOA_NOTIFY_LINE_OUT, | ||
| 1044 | NULL, | ||
| 1045 | NULL); | ||
| 1046 | |||
| 1047 | ldev->gpio.methods->exit(&ldev->gpio); | ||
| 1048 | layout_device = NULL; | ||
| 1049 | kfree(ldev); | ||
| 1050 | sdev->pcmid = -1; | ||
| 1051 | sdev->pcmname = NULL; | ||
| 1052 | return 0; | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | #ifdef CONFIG_PM | ||
| 1056 | static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state) | ||
| 1057 | { | ||
| 1058 | struct layout_dev *ldev = sdev->ofdev.dev.driver_data; | ||
| 1059 | |||
| 1060 | printk("aoa_fabric_layout_suspend()\n"); | ||
| 1061 | |||
| 1062 | if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) | ||
| 1063 | ldev->gpio.methods->all_amps_off(&ldev->gpio); | ||
| 1064 | |||
| 1065 | return 0; | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | static int aoa_fabric_layout_resume(struct soundbus_dev *sdev) | ||
| 1069 | { | ||
| 1070 | struct layout_dev *ldev = sdev->ofdev.dev.driver_data; | ||
| 1071 | |||
| 1072 | printk("aoa_fabric_layout_resume()\n"); | ||
| 1073 | |||
| 1074 | if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off) | ||
| 1075 | ldev->gpio.methods->all_amps_restore(&ldev->gpio); | ||
| 1076 | |||
| 1077 | return 0; | ||
| 1078 | } | ||
| 1079 | #endif | ||
| 1080 | |||
| 1081 | static struct soundbus_driver aoa_soundbus_driver = { | ||
| 1082 | .name = "snd_aoa_soundbus_drv", | ||
| 1083 | .owner = THIS_MODULE, | ||
| 1084 | .probe = aoa_fabric_layout_probe, | ||
| 1085 | .remove = aoa_fabric_layout_remove, | ||
| 1086 | #ifdef CONFIG_PM | ||
| 1087 | .suspend = aoa_fabric_layout_suspend, | ||
| 1088 | .resume = aoa_fabric_layout_resume, | ||
| 1089 | #endif | ||
| 1090 | }; | ||
| 1091 | |||
| 1092 | static int __init aoa_fabric_layout_init(void) | ||
| 1093 | { | ||
| 1094 | int err; | ||
| 1095 | |||
| 1096 | err = soundbus_register_driver(&aoa_soundbus_driver); | ||
| 1097 | if (err) | ||
| 1098 | return err; | ||
| 1099 | return 0; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | static void __exit aoa_fabric_layout_exit(void) | ||
| 1103 | { | ||
| 1104 | soundbus_unregister_driver(&aoa_soundbus_driver); | ||
| 1105 | aoa_fabric_unregister(&layout_fabric); | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | module_init(aoa_fabric_layout_init); | ||
| 1109 | module_exit(aoa_fabric_layout_exit); | ||
diff --git a/sound/aoa/soundbus/Kconfig b/sound/aoa/soundbus/Kconfig new file mode 100644 index 000000000000..d532d27a9f54 --- /dev/null +++ b/sound/aoa/soundbus/Kconfig | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | config SND_AOA_SOUNDBUS | ||
| 2 | tristate "Apple Soundbus support" | ||
| 3 | depends on SOUND && SND_PCM && EXPERIMENTAL | ||
| 4 | ---help--- | ||
| 5 | This option enables the generic driver for the soundbus | ||
| 6 | support on Apple machines. | ||
| 7 | |||
| 8 | It is required for the sound bus implementations. | ||
| 9 | |||
| 10 | config SND_AOA_SOUNDBUS_I2S | ||
| 11 | tristate "I2S bus support" | ||
| 12 | depends on SND_AOA_SOUNDBUS && PCI | ||
| 13 | ---help--- | ||
| 14 | This option enables support for Apple I2S busses. | ||
diff --git a/sound/aoa/soundbus/Makefile b/sound/aoa/soundbus/Makefile new file mode 100644 index 000000000000..0e61f5aa06b5 --- /dev/null +++ b/sound/aoa/soundbus/Makefile | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | obj-$(CONFIG_SND_AOA_SOUNDBUS) += snd-aoa-soundbus.o | ||
| 2 | snd-aoa-soundbus-objs := core.o sysfs.o | ||
| 3 | obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += i2sbus/ | ||
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c new file mode 100644 index 000000000000..abe84a76c835 --- /dev/null +++ b/sound/aoa/soundbus/core.c | |||
| @@ -0,0 +1,250 @@ | |||
| 1 | /* | ||
| 2 | * soundbus | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include "soundbus.h" | ||
| 11 | |||
| 12 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
| 13 | MODULE_LICENSE("GPL"); | ||
| 14 | MODULE_DESCRIPTION("Apple Soundbus"); | ||
| 15 | |||
| 16 | struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev) | ||
| 17 | { | ||
| 18 | struct device *tmp; | ||
| 19 | |||
| 20 | if (!dev) | ||
| 21 | return NULL; | ||
| 22 | tmp = get_device(&dev->ofdev.dev); | ||
| 23 | if (tmp) | ||
| 24 | return to_soundbus_device(tmp); | ||
| 25 | else | ||
| 26 | return NULL; | ||
| 27 | } | ||
| 28 | EXPORT_SYMBOL_GPL(soundbus_dev_get); | ||
| 29 | |||
| 30 | void soundbus_dev_put(struct soundbus_dev *dev) | ||
| 31 | { | ||
| 32 | if (dev) | ||
| 33 | put_device(&dev->ofdev.dev); | ||
| 34 | } | ||
| 35 | EXPORT_SYMBOL_GPL(soundbus_dev_put); | ||
| 36 | |||
| 37 | static int soundbus_probe(struct device *dev) | ||
| 38 | { | ||
| 39 | int error = -ENODEV; | ||
| 40 | struct soundbus_driver *drv; | ||
| 41 | struct soundbus_dev *soundbus_dev; | ||
| 42 | |||
| 43 | drv = to_soundbus_driver(dev->driver); | ||
| 44 | soundbus_dev = to_soundbus_device(dev); | ||
| 45 | |||
| 46 | if (!drv->probe) | ||
| 47 | return error; | ||
| 48 | |||
| 49 | soundbus_dev_get(soundbus_dev); | ||
| 50 | |||
| 51 | error = drv->probe(soundbus_dev); | ||
| 52 | if (error) | ||
| 53 | soundbus_dev_put(soundbus_dev); | ||
| 54 | |||
| 55 | return error; | ||
| 56 | } | ||
| 57 | |||
| 58 | |||
| 59 | static int soundbus_uevent(struct device *dev, char **envp, int num_envp, | ||
| 60 | char *buffer, int buffer_size) | ||
| 61 | { | ||
| 62 | struct soundbus_dev * soundbus_dev; | ||
| 63 | struct of_device * of; | ||
| 64 | char *scratch, *compat, *compat2; | ||
| 65 | int i = 0; | ||
| 66 | int length, cplen, cplen2, seen = 0; | ||
| 67 | |||
| 68 | if (!dev) | ||
| 69 | return -ENODEV; | ||
| 70 | |||
| 71 | soundbus_dev = to_soundbus_device(dev); | ||
| 72 | if (!soundbus_dev) | ||
| 73 | return -ENODEV; | ||
| 74 | |||
| 75 | of = &soundbus_dev->ofdev; | ||
| 76 | |||
| 77 | /* stuff we want to pass to /sbin/hotplug */ | ||
| 78 | envp[i++] = scratch = buffer; | ||
| 79 | length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name); | ||
| 80 | ++length; | ||
| 81 | buffer_size -= length; | ||
| 82 | if ((buffer_size <= 0) || (i >= num_envp)) | ||
| 83 | return -ENOMEM; | ||
| 84 | scratch += length; | ||
| 85 | |||
| 86 | envp[i++] = scratch; | ||
| 87 | length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type); | ||
| 88 | ++length; | ||
| 89 | buffer_size -= length; | ||
| 90 | if ((buffer_size <= 0) || (i >= num_envp)) | ||
| 91 | return -ENOMEM; | ||
| 92 | scratch += length; | ||
| 93 | |||
| 94 | /* Since the compatible field can contain pretty much anything | ||
| 95 | * it's not really legal to split it out with commas. We split it | ||
| 96 | * up using a number of environment variables instead. */ | ||
| 97 | |||
| 98 | compat = (char *) get_property(of->node, "compatible", &cplen); | ||
| 99 | compat2 = compat; | ||
| 100 | cplen2= cplen; | ||
| 101 | while (compat && cplen > 0) { | ||
| 102 | envp[i++] = scratch; | ||
| 103 | length = scnprintf (scratch, buffer_size, | ||
| 104 | "OF_COMPATIBLE_%d=%s", seen, compat); | ||
| 105 | ++length; | ||
| 106 | buffer_size -= length; | ||
| 107 | if ((buffer_size <= 0) || (i >= num_envp)) | ||
| 108 | return -ENOMEM; | ||
| 109 | scratch += length; | ||
| 110 | length = strlen (compat) + 1; | ||
| 111 | compat += length; | ||
| 112 | cplen -= length; | ||
| 113 | seen++; | ||
| 114 | } | ||
| 115 | |||
| 116 | envp[i++] = scratch; | ||
| 117 | length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen); | ||
| 118 | ++length; | ||
| 119 | buffer_size -= length; | ||
| 120 | if ((buffer_size <= 0) || (i >= num_envp)) | ||
| 121 | return -ENOMEM; | ||
| 122 | scratch += length; | ||
| 123 | |||
| 124 | envp[i++] = scratch; | ||
| 125 | length = scnprintf (scratch, buffer_size, "MODALIAS=%s", | ||
| 126 | soundbus_dev->modalias); | ||
| 127 | |||
| 128 | buffer_size -= length; | ||
| 129 | if ((buffer_size <= 0) || (i >= num_envp)) | ||
| 130 | return -ENOMEM; | ||
| 131 | |||
| 132 | envp[i] = NULL; | ||
| 133 | |||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | static int soundbus_device_remove(struct device *dev) | ||
| 138 | { | ||
| 139 | struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); | ||
| 140 | struct soundbus_driver * drv = to_soundbus_driver(dev->driver); | ||
| 141 | |||
| 142 | if (dev->driver && drv->remove) | ||
| 143 | drv->remove(soundbus_dev); | ||
| 144 | soundbus_dev_put(soundbus_dev); | ||
| 145 | |||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | static void soundbus_device_shutdown(struct device *dev) | ||
| 150 | { | ||
| 151 | struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); | ||
| 152 | struct soundbus_driver * drv = to_soundbus_driver(dev->driver); | ||
| 153 | |||
| 154 | if (dev->driver && drv->shutdown) | ||
| 155 | drv->shutdown(soundbus_dev); | ||
| 156 | } | ||
| 157 | |||
| 158 | #ifdef CONFIG_PM | ||
| 159 | |||
| 160 | static int soundbus_device_suspend(struct device *dev, pm_message_t state) | ||
| 161 | { | ||
| 162 | struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); | ||
| 163 | struct soundbus_driver * drv = to_soundbus_driver(dev->driver); | ||
| 164 | |||
| 165 | if (dev->driver && drv->suspend) | ||
| 166 | return drv->suspend(soundbus_dev, state); | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | static int soundbus_device_resume(struct device * dev) | ||
| 171 | { | ||
| 172 | struct soundbus_dev * soundbus_dev = to_soundbus_device(dev); | ||
| 173 | struct soundbus_driver * drv = to_soundbus_driver(dev->driver); | ||
| 174 | |||
| 175 | if (dev->driver && drv->resume) | ||
| 176 | return drv->resume(soundbus_dev); | ||
| 177 | return 0; | ||
| 178 | } | ||
| 179 | |||
| 180 | #endif /* CONFIG_PM */ | ||
| 181 | |||
| 182 | extern struct device_attribute soundbus_dev_attrs[]; | ||
| 183 | |||
| 184 | static struct bus_type soundbus_bus_type = { | ||
| 185 | .name = "aoa-soundbus", | ||
| 186 | .probe = soundbus_probe, | ||
| 187 | .uevent = soundbus_uevent, | ||
| 188 | .remove = soundbus_device_remove, | ||
| 189 | .shutdown = soundbus_device_shutdown, | ||
| 190 | #ifdef CONFIG_PM | ||
| 191 | .suspend = soundbus_device_suspend, | ||
| 192 | .resume = soundbus_device_resume, | ||
| 193 | #endif | ||
| 194 | .dev_attrs = soundbus_dev_attrs, | ||
| 195 | }; | ||
| 196 | |||
| 197 | static int __init soundbus_init(void) | ||
| 198 | { | ||
| 199 | return bus_register(&soundbus_bus_type); | ||
| 200 | } | ||
| 201 | |||
| 202 | static void __exit soundbus_exit(void) | ||
| 203 | { | ||
| 204 | bus_unregister(&soundbus_bus_type); | ||
| 205 | } | ||
| 206 | |||
| 207 | int soundbus_add_one(struct soundbus_dev *dev) | ||
| 208 | { | ||
| 209 | static int devcount; | ||
| 210 | |||
| 211 | /* sanity checks */ | ||
| 212 | if (!dev->attach_codec || | ||
| 213 | !dev->ofdev.node || | ||
| 214 | dev->pcmname || | ||
| 215 | dev->pcmid != -1) { | ||
| 216 | printk(KERN_ERR "soundbus: adding device failed sanity check!\n"); | ||
| 217 | return -EINVAL; | ||
| 218 | } | ||
| 219 | |||
| 220 | snprintf(dev->ofdev.dev.bus_id, BUS_ID_SIZE, "soundbus:%x", ++devcount); | ||
| 221 | dev->ofdev.dev.bus = &soundbus_bus_type; | ||
| 222 | return of_device_register(&dev->ofdev); | ||
| 223 | } | ||
| 224 | EXPORT_SYMBOL_GPL(soundbus_add_one); | ||
| 225 | |||
| 226 | void soundbus_remove_one(struct soundbus_dev *dev) | ||
| 227 | { | ||
| 228 | of_device_unregister(&dev->ofdev); | ||
| 229 | } | ||
| 230 | EXPORT_SYMBOL_GPL(soundbus_remove_one); | ||
| 231 | |||
| 232 | int soundbus_register_driver(struct soundbus_driver *drv) | ||
| 233 | { | ||
| 234 | /* initialize common driver fields */ | ||
| 235 | drv->driver.name = drv->name; | ||
| 236 | drv->driver.bus = &soundbus_bus_type; | ||
| 237 | |||
| 238 | /* register with core */ | ||
| 239 | return driver_register(&drv->driver); | ||
| 240 | } | ||
| 241 | EXPORT_SYMBOL_GPL(soundbus_register_driver); | ||
| 242 | |||
| 243 | void soundbus_unregister_driver(struct soundbus_driver *drv) | ||
| 244 | { | ||
| 245 | driver_unregister(&drv->driver); | ||
| 246 | } | ||
| 247 | EXPORT_SYMBOL_GPL(soundbus_unregister_driver); | ||
| 248 | |||
| 249 | module_init(soundbus_init); | ||
| 250 | module_exit(soundbus_exit); | ||
diff --git a/sound/aoa/soundbus/i2sbus/Makefile b/sound/aoa/soundbus/i2sbus/Makefile new file mode 100644 index 000000000000..e57a5cf65655 --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/Makefile | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | obj-$(CONFIG_SND_AOA_SOUNDBUS_I2S) += snd-aoa-i2sbus.o | ||
| 2 | snd-aoa-i2sbus-objs := i2sbus-core.o i2sbus-pcm.o i2sbus-control.o | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.c b/sound/aoa/soundbus/i2sbus/i2sbus-control.c new file mode 100644 index 000000000000..f50407952d3c --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-control.c | |||
| @@ -0,0 +1,192 @@ | |||
| 1 | /* | ||
| 2 | * i2sbus driver -- bus control routines | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <asm/io.h> | ||
| 10 | #include <linux/delay.h> | ||
| 11 | #include <asm/prom.h> | ||
| 12 | #include <asm/macio.h> | ||
| 13 | #include <asm/pmac_feature.h> | ||
| 14 | #include <asm/pmac_pfunc.h> | ||
| 15 | #include "i2sbus.h" | ||
| 16 | |||
| 17 | int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c) | ||
| 18 | { | ||
| 19 | *c = kzalloc(sizeof(struct i2sbus_control), GFP_KERNEL); | ||
| 20 | if (!*c) | ||
| 21 | return -ENOMEM; | ||
| 22 | |||
| 23 | INIT_LIST_HEAD(&(*c)->list); | ||
| 24 | |||
| 25 | if (of_address_to_resource(dev->ofdev.node, 0, &(*c)->rsrc)) | ||
| 26 | goto err; | ||
| 27 | /* we really should be using feature calls instead of mapping | ||
| 28 | * these registers. It's safe for now since no one else is | ||
| 29 | * touching them... */ | ||
| 30 | (*c)->controlregs = ioremap((*c)->rsrc.start, | ||
| 31 | sizeof(struct i2s_control_regs)); | ||
| 32 | if (!(*c)->controlregs) | ||
| 33 | goto err; | ||
| 34 | |||
| 35 | return 0; | ||
| 36 | err: | ||
| 37 | kfree(*c); | ||
| 38 | *c = NULL; | ||
| 39 | return -ENODEV; | ||
| 40 | } | ||
| 41 | |||
| 42 | void i2sbus_control_destroy(struct i2sbus_control *c) | ||
| 43 | { | ||
| 44 | iounmap(c->controlregs); | ||
| 45 | kfree(c); | ||
| 46 | } | ||
| 47 | |||
| 48 | /* this is serialised externally */ | ||
| 49 | int i2sbus_control_add_dev(struct i2sbus_control *c, | ||
| 50 | struct i2sbus_dev *i2sdev) | ||
| 51 | { | ||
| 52 | struct device_node *np; | ||
| 53 | |||
| 54 | np = i2sdev->sound.ofdev.node; | ||
| 55 | i2sdev->enable = pmf_find_function(np, "enable"); | ||
| 56 | i2sdev->cell_enable = pmf_find_function(np, "cell-enable"); | ||
| 57 | i2sdev->clock_enable = pmf_find_function(np, "clock-enable"); | ||
| 58 | i2sdev->cell_disable = pmf_find_function(np, "cell-disable"); | ||
| 59 | i2sdev->clock_disable = pmf_find_function(np, "clock-disable"); | ||
| 60 | |||
| 61 | /* if the bus number is not 0 or 1 we absolutely need to use | ||
| 62 | * the platform functions -- there's nothing in Darwin that | ||
| 63 | * would allow seeing a system behind what the FCRs are then, | ||
| 64 | * and I don't want to go parsing a bunch of platform functions | ||
| 65 | * by hand to try finding a system... */ | ||
| 66 | if (i2sdev->bus_number != 0 && i2sdev->bus_number != 1 && | ||
| 67 | (!i2sdev->enable || | ||
| 68 | !i2sdev->cell_enable || !i2sdev->clock_enable || | ||
| 69 | !i2sdev->cell_disable || !i2sdev->clock_disable)) { | ||
| 70 | pmf_put_function(i2sdev->enable); | ||
| 71 | pmf_put_function(i2sdev->cell_enable); | ||
| 72 | pmf_put_function(i2sdev->clock_enable); | ||
| 73 | pmf_put_function(i2sdev->cell_disable); | ||
| 74 | pmf_put_function(i2sdev->clock_disable); | ||
| 75 | return -ENODEV; | ||
| 76 | } | ||
| 77 | |||
| 78 | list_add(&i2sdev->item, &c->list); | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | void i2sbus_control_remove_dev(struct i2sbus_control *c, | ||
| 84 | struct i2sbus_dev *i2sdev) | ||
| 85 | { | ||
| 86 | /* this is serialised externally */ | ||
| 87 | list_del(&i2sdev->item); | ||
| 88 | if (list_empty(&c->list)) | ||
| 89 | i2sbus_control_destroy(c); | ||
| 90 | } | ||
| 91 | |||
| 92 | int i2sbus_control_enable(struct i2sbus_control *c, | ||
| 93 | struct i2sbus_dev *i2sdev) | ||
| 94 | { | ||
| 95 | struct pmf_args args = { .count = 0 }; | ||
| 96 | int cc; | ||
| 97 | |||
| 98 | if (i2sdev->enable) | ||
| 99 | return pmf_call_one(i2sdev->enable, &args); | ||
| 100 | |||
| 101 | switch (i2sdev->bus_number) { | ||
| 102 | case 0: | ||
| 103 | cc = in_le32(&c->controlregs->cell_control); | ||
| 104 | out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_0_ENABLE); | ||
| 105 | break; | ||
| 106 | case 1: | ||
| 107 | cc = in_le32(&c->controlregs->cell_control); | ||
| 108 | out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_1_ENABLE); | ||
| 109 | break; | ||
| 110 | default: | ||
| 111 | return -ENODEV; | ||
| 112 | } | ||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | int i2sbus_control_cell(struct i2sbus_control *c, | ||
| 117 | struct i2sbus_dev *i2sdev, | ||
| 118 | int enable) | ||
| 119 | { | ||
| 120 | struct pmf_args args = { .count = 0 }; | ||
| 121 | int cc; | ||
| 122 | |||
| 123 | switch (enable) { | ||
| 124 | case 0: | ||
| 125 | if (i2sdev->cell_disable) | ||
| 126 | return pmf_call_one(i2sdev->cell_disable, &args); | ||
| 127 | break; | ||
| 128 | case 1: | ||
| 129 | if (i2sdev->cell_enable) | ||
| 130 | return pmf_call_one(i2sdev->cell_enable, &args); | ||
| 131 | break; | ||
| 132 | default: | ||
| 133 | printk(KERN_ERR "i2sbus: INVALID CELL ENABLE VALUE\n"); | ||
| 134 | return -ENODEV; | ||
| 135 | } | ||
| 136 | switch (i2sdev->bus_number) { | ||
| 137 | case 0: | ||
| 138 | cc = in_le32(&c->controlregs->cell_control); | ||
| 139 | cc &= ~CTRL_CLOCK_CELL_0_ENABLE; | ||
| 140 | cc |= enable * CTRL_CLOCK_CELL_0_ENABLE; | ||
| 141 | out_le32(&c->controlregs->cell_control, cc); | ||
| 142 | break; | ||
| 143 | case 1: | ||
| 144 | cc = in_le32(&c->controlregs->cell_control); | ||
| 145 | cc &= ~CTRL_CLOCK_CELL_1_ENABLE; | ||
| 146 | cc |= enable * CTRL_CLOCK_CELL_1_ENABLE; | ||
| 147 | out_le32(&c->controlregs->cell_control, cc); | ||
| 148 | break; | ||
| 149 | default: | ||
| 150 | return -ENODEV; | ||
| 151 | } | ||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 155 | int i2sbus_control_clock(struct i2sbus_control *c, | ||
| 156 | struct i2sbus_dev *i2sdev, | ||
| 157 | int enable) | ||
| 158 | { | ||
| 159 | struct pmf_args args = { .count = 0 }; | ||
| 160 | int cc; | ||
| 161 | |||
| 162 | switch (enable) { | ||
| 163 | case 0: | ||
| 164 | if (i2sdev->clock_disable) | ||
| 165 | return pmf_call_one(i2sdev->clock_disable, &args); | ||
| 166 | break; | ||
| 167 | case 1: | ||
| 168 | if (i2sdev->clock_enable) | ||
| 169 | return pmf_call_one(i2sdev->clock_enable, &args); | ||
| 170 | break; | ||
| 171 | default: | ||
| 172 | printk(KERN_ERR "i2sbus: INVALID CLOCK ENABLE VALUE\n"); | ||
| 173 | return -ENODEV; | ||
| 174 | } | ||
| 175 | switch (i2sdev->bus_number) { | ||
| 176 | case 0: | ||
| 177 | cc = in_le32(&c->controlregs->cell_control); | ||
| 178 | cc &= ~CTRL_CLOCK_CLOCK_0_ENABLE; | ||
| 179 | cc |= enable * CTRL_CLOCK_CLOCK_0_ENABLE; | ||
| 180 | out_le32(&c->controlregs->cell_control, cc); | ||
| 181 | break; | ||
| 182 | case 1: | ||
| 183 | cc = in_le32(&c->controlregs->cell_control); | ||
| 184 | cc &= ~CTRL_CLOCK_CLOCK_1_ENABLE; | ||
| 185 | cc |= enable * CTRL_CLOCK_CLOCK_1_ENABLE; | ||
| 186 | out_le32(&c->controlregs->cell_control, cc); | ||
| 187 | break; | ||
| 188 | default: | ||
| 189 | return -ENODEV; | ||
| 190 | } | ||
| 191 | return 0; | ||
| 192 | } | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-control.h b/sound/aoa/soundbus/i2sbus/i2sbus-control.h new file mode 100644 index 000000000000..bb05550f730b --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-control.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | * i2sbus driver -- bus register definitions | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | #ifndef __I2SBUS_CONTROLREGS_H | ||
| 9 | #define __I2SBUS_CONTROLREGS_H | ||
| 10 | |||
| 11 | /* i2s control registers, at least what we know about them */ | ||
| 12 | |||
| 13 | #define __PAD(m,n) u8 __pad##m[n] | ||
| 14 | #define _PAD(line, n) __PAD(line, n) | ||
| 15 | #define PAD(n) _PAD(__LINE__, (n)) | ||
| 16 | struct i2s_control_regs { | ||
| 17 | PAD(0x38); | ||
| 18 | __le32 fcr0; /* 0x38 (unknown) */ | ||
| 19 | __le32 cell_control; /* 0x3c (fcr1) */ | ||
| 20 | __le32 fcr2; /* 0x40 (unknown) */ | ||
| 21 | __le32 fcr3; /* 0x44 (fcr3) */ | ||
| 22 | __le32 clock_control; /* 0x48 (unknown) */ | ||
| 23 | PAD(4); | ||
| 24 | /* total size: 0x50 bytes */ | ||
| 25 | } __attribute__((__packed__)); | ||
| 26 | |||
| 27 | #define CTRL_CLOCK_CELL_0_ENABLE (1<<10) | ||
| 28 | #define CTRL_CLOCK_CLOCK_0_ENABLE (1<<12) | ||
| 29 | #define CTRL_CLOCK_SWRESET_0 (1<<11) | ||
| 30 | #define CTRL_CLOCK_INTF_0_ENABLE (1<<13) | ||
| 31 | |||
| 32 | #define CTRL_CLOCK_CELL_1_ENABLE (1<<17) | ||
| 33 | #define CTRL_CLOCK_CLOCK_1_ENABLE (1<<18) | ||
| 34 | #define CTRL_CLOCK_SWRESET_1 (1<<19) | ||
| 35 | #define CTRL_CLOCK_INTF_1_ENABLE (1<<20) | ||
| 36 | |||
| 37 | #endif /* __I2SBUS_CONTROLREGS_H */ | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c new file mode 100644 index 000000000000..f268dacdaa00 --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c | |||
| @@ -0,0 +1,387 @@ | |||
| 1 | /* | ||
| 2 | * i2sbus driver | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <asm/macio.h> | ||
| 11 | #include <asm/dbdma.h> | ||
| 12 | #include <linux/pci.h> | ||
| 13 | #include <linux/interrupt.h> | ||
| 14 | #include <sound/driver.h> | ||
| 15 | #include <sound/core.h> | ||
| 16 | #include <linux/dma-mapping.h> | ||
| 17 | #include "../soundbus.h" | ||
| 18 | #include "i2sbus.h" | ||
| 19 | |||
| 20 | MODULE_LICENSE("GPL"); | ||
| 21 | MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); | ||
| 22 | MODULE_DESCRIPTION("Apple Soundbus: I2S support"); | ||
| 23 | /* for auto-loading, declare that we handle this weird | ||
| 24 | * string that macio puts into the relevant device */ | ||
| 25 | MODULE_ALIAS("of:Ni2sTi2sC"); | ||
| 26 | |||
| 27 | static struct of_device_id i2sbus_match[] = { | ||
| 28 | { .name = "i2s" }, | ||
| 29 | { } | ||
| 30 | }; | ||
| 31 | |||
| 32 | static int alloc_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, | ||
| 33 | struct dbdma_command_mem *r, | ||
| 34 | int numcmds) | ||
| 35 | { | ||
| 36 | /* one more for rounding */ | ||
| 37 | r->size = (numcmds+1) * sizeof(struct dbdma_cmd); | ||
| 38 | /* We use the PCI APIs for now until the generic one gets fixed | ||
| 39 | * enough or until we get some macio-specific versions | ||
| 40 | */ | ||
| 41 | r->space = dma_alloc_coherent( | ||
| 42 | &macio_get_pci_dev(i2sdev->macio)->dev, | ||
| 43 | r->size, | ||
| 44 | &r->bus_addr, | ||
| 45 | GFP_KERNEL); | ||
| 46 | |||
| 47 | if (!r->space) return -ENOMEM; | ||
| 48 | |||
| 49 | memset(r->space, 0, r->size); | ||
| 50 | r->cmds = (void*)DBDMA_ALIGN(r->space); | ||
| 51 | r->bus_cmd_start = r->bus_addr + | ||
| 52 | (dma_addr_t)((char*)r->cmds - (char*)r->space); | ||
| 53 | |||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | |||
| 57 | static void free_dbdma_descriptor_ring(struct i2sbus_dev *i2sdev, | ||
| 58 | struct dbdma_command_mem *r) | ||
| 59 | { | ||
| 60 | if (!r->space) return; | ||
| 61 | |||
| 62 | dma_free_coherent(&macio_get_pci_dev(i2sdev->macio)->dev, | ||
| 63 | r->size, r->space, r->bus_addr); | ||
| 64 | } | ||
| 65 | |||
| 66 | static void i2sbus_release_dev(struct device *dev) | ||
| 67 | { | ||
| 68 | struct i2sbus_dev *i2sdev; | ||
| 69 | int i; | ||
| 70 | |||
| 71 | i2sdev = container_of(dev, struct i2sbus_dev, sound.ofdev.dev); | ||
| 72 | |||
| 73 | if (i2sdev->intfregs) iounmap(i2sdev->intfregs); | ||
| 74 | if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma); | ||
| 75 | if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma); | ||
| 76 | for (i=0;i<3;i++) | ||
| 77 | if (i2sdev->allocated_resource[i]) | ||
| 78 | release_and_free_resource(i2sdev->allocated_resource[i]); | ||
| 79 | free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring); | ||
| 80 | free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring); | ||
| 81 | for (i=0;i<3;i++) | ||
| 82 | free_irq(i2sdev->interrupts[i], i2sdev); | ||
| 83 | i2sbus_control_remove_dev(i2sdev->control, i2sdev); | ||
| 84 | mutex_destroy(&i2sdev->lock); | ||
| 85 | kfree(i2sdev); | ||
| 86 | } | ||
| 87 | |||
| 88 | static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs) | ||
| 89 | { | ||
| 90 | struct i2sbus_dev *dev = devid; | ||
| 91 | u32 intreg; | ||
| 92 | |||
| 93 | spin_lock(&dev->low_lock); | ||
| 94 | intreg = in_le32(&dev->intfregs->intr_ctl); | ||
| 95 | |||
| 96 | /* acknowledge interrupt reasons */ | ||
| 97 | out_le32(&dev->intfregs->intr_ctl, intreg); | ||
| 98 | |||
| 99 | spin_unlock(&dev->low_lock); | ||
| 100 | |||
| 101 | return IRQ_HANDLED; | ||
| 102 | } | ||
| 103 | |||
| 104 | static int force; | ||
| 105 | module_param(force, int, 0444); | ||
| 106 | MODULE_PARM_DESC(force, "Force loading i2sbus even when" | ||
| 107 | " no layout-id property is present"); | ||
| 108 | |||
| 109 | /* FIXME: look at device node refcounting */ | ||
| 110 | static int i2sbus_add_dev(struct macio_dev *macio, | ||
| 111 | struct i2sbus_control *control, | ||
| 112 | struct device_node *np) | ||
| 113 | { | ||
| 114 | struct i2sbus_dev *dev; | ||
| 115 | struct device_node *child = NULL, *sound = NULL; | ||
| 116 | int i; | ||
| 117 | static const char *rnames[] = { "i2sbus: %s (control)", | ||
| 118 | "i2sbus: %s (tx)", | ||
| 119 | "i2sbus: %s (rx)" }; | ||
| 120 | static irqreturn_t (*ints[])(int irq, void *devid, | ||
| 121 | struct pt_regs *regs) = { | ||
| 122 | i2sbus_bus_intr, | ||
| 123 | i2sbus_tx_intr, | ||
| 124 | i2sbus_rx_intr | ||
| 125 | }; | ||
| 126 | |||
| 127 | if (strlen(np->name) != 5) | ||
| 128 | return 0; | ||
| 129 | if (strncmp(np->name, "i2s-", 4)) | ||
| 130 | return 0; | ||
| 131 | |||
| 132 | if (np->n_intrs != 3) | ||
| 133 | return 0; | ||
| 134 | |||
| 135 | dev = kzalloc(sizeof(struct i2sbus_dev), GFP_KERNEL); | ||
| 136 | if (!dev) | ||
| 137 | return 0; | ||
| 138 | |||
| 139 | i = 0; | ||
| 140 | while ((child = of_get_next_child(np, child))) { | ||
| 141 | if (strcmp(child->name, "sound") == 0) { | ||
| 142 | i++; | ||
| 143 | sound = child; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | if (i == 1) { | ||
| 147 | u32 *layout_id; | ||
| 148 | layout_id = (u32*) get_property(sound, "layout-id", NULL); | ||
| 149 | if (layout_id) { | ||
| 150 | snprintf(dev->sound.modalias, 32, | ||
| 151 | "sound-layout-%d", *layout_id); | ||
| 152 | force = 1; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | /* for the time being, until we can handle non-layout-id | ||
| 156 | * things in some fabric, refuse to attach if there is no | ||
| 157 | * layout-id property or we haven't been forced to attach. | ||
| 158 | * When there are two i2s busses and only one has a layout-id, | ||
| 159 | * then this depends on the order, but that isn't important | ||
| 160 | * either as the second one in that case is just a modem. */ | ||
| 161 | if (!force) { | ||
| 162 | kfree(dev); | ||
| 163 | return -ENODEV; | ||
| 164 | } | ||
| 165 | |||
| 166 | mutex_init(&dev->lock); | ||
| 167 | spin_lock_init(&dev->low_lock); | ||
| 168 | dev->sound.ofdev.node = np; | ||
| 169 | dev->sound.ofdev.dma_mask = macio->ofdev.dma_mask; | ||
| 170 | dev->sound.ofdev.dev.dma_mask = &dev->sound.ofdev.dma_mask; | ||
| 171 | dev->sound.ofdev.dev.parent = &macio->ofdev.dev; | ||
| 172 | dev->sound.ofdev.dev.release = i2sbus_release_dev; | ||
| 173 | dev->sound.attach_codec = i2sbus_attach_codec; | ||
| 174 | dev->sound.detach_codec = i2sbus_detach_codec; | ||
| 175 | dev->sound.pcmid = -1; | ||
| 176 | dev->macio = macio; | ||
| 177 | dev->control = control; | ||
| 178 | dev->bus_number = np->name[4] - 'a'; | ||
| 179 | INIT_LIST_HEAD(&dev->sound.codec_list); | ||
| 180 | |||
| 181 | for (i=0;i<3;i++) { | ||
| 182 | dev->interrupts[i] = -1; | ||
| 183 | snprintf(dev->rnames[i], sizeof(dev->rnames[i]), rnames[i], np->name); | ||
| 184 | } | ||
| 185 | for (i=0;i<3;i++) { | ||
| 186 | if (request_irq(np->intrs[i].line, ints[i], 0, dev->rnames[i], dev)) | ||
| 187 | goto err; | ||
| 188 | dev->interrupts[i] = np->intrs[i].line; | ||
| 189 | } | ||
| 190 | |||
| 191 | for (i=0;i<3;i++) { | ||
| 192 | if (of_address_to_resource(np, i, &dev->resources[i])) | ||
| 193 | goto err; | ||
| 194 | /* if only we could use our resource dev->resources[i]... | ||
| 195 | * but request_resource doesn't know about parents and | ||
| 196 | * contained resources... */ | ||
| 197 | dev->allocated_resource[i] = | ||
| 198 | request_mem_region(dev->resources[i].start, | ||
| 199 | dev->resources[i].end - | ||
| 200 | dev->resources[i].start + 1, | ||
| 201 | dev->rnames[i]); | ||
| 202 | if (!dev->allocated_resource[i]) { | ||
| 203 | printk(KERN_ERR "i2sbus: failed to claim resource %d!\n", i); | ||
| 204 | goto err; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | /* should do sanity checking here about length of them */ | ||
| 208 | dev->intfregs = ioremap(dev->resources[0].start, | ||
| 209 | dev->resources[0].end-dev->resources[0].start+1); | ||
| 210 | dev->out.dbdma = ioremap(dev->resources[1].start, | ||
| 211 | dev->resources[1].end-dev->resources[1].start+1); | ||
| 212 | dev->in.dbdma = ioremap(dev->resources[2].start, | ||
| 213 | dev->resources[2].end-dev->resources[2].start+1); | ||
| 214 | if (!dev->intfregs || !dev->out.dbdma || !dev->in.dbdma) | ||
| 215 | goto err; | ||
| 216 | |||
| 217 | if (alloc_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring, | ||
| 218 | MAX_DBDMA_COMMANDS)) | ||
| 219 | goto err; | ||
| 220 | if (alloc_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring, | ||
| 221 | MAX_DBDMA_COMMANDS)) | ||
| 222 | goto err; | ||
| 223 | |||
| 224 | if (i2sbus_control_add_dev(dev->control, dev)) { | ||
| 225 | printk(KERN_ERR "i2sbus: control layer didn't like bus\n"); | ||
| 226 | goto err; | ||
| 227 | } | ||
| 228 | |||
| 229 | if (soundbus_add_one(&dev->sound)) { | ||
| 230 | printk(KERN_DEBUG "i2sbus: device registration error!\n"); | ||
| 231 | goto err; | ||
| 232 | } | ||
| 233 | |||
| 234 | /* enable this cell */ | ||
| 235 | i2sbus_control_cell(dev->control, dev, 1); | ||
| 236 | i2sbus_control_enable(dev->control, dev); | ||
| 237 | i2sbus_control_clock(dev->control, dev, 1); | ||
| 238 | |||
| 239 | return 1; | ||
| 240 | err: | ||
| 241 | for (i=0;i<3;i++) | ||
| 242 | if (dev->interrupts[i] != -1) | ||
| 243 | free_irq(dev->interrupts[i], dev); | ||
| 244 | free_dbdma_descriptor_ring(dev, &dev->out.dbdma_ring); | ||
| 245 | free_dbdma_descriptor_ring(dev, &dev->in.dbdma_ring); | ||
| 246 | if (dev->intfregs) iounmap(dev->intfregs); | ||
| 247 | if (dev->out.dbdma) iounmap(dev->out.dbdma); | ||
| 248 | if (dev->in.dbdma) iounmap(dev->in.dbdma); | ||
| 249 | for (i=0;i<3;i++) | ||
| 250 | if (dev->allocated_resource[i]) | ||
| 251 | release_and_free_resource(dev->allocated_resource[i]); | ||
| 252 | mutex_destroy(&dev->lock); | ||
| 253 | kfree(dev); | ||
| 254 | return 0; | ||
| 255 | } | ||
| 256 | |||
| 257 | static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match) | ||
| 258 | { | ||
| 259 | struct device_node *np = NULL; | ||
| 260 | int got = 0, err; | ||
| 261 | struct i2sbus_control *control = NULL; | ||
| 262 | |||
| 263 | err = i2sbus_control_init(dev, &control); | ||
| 264 | if (err) | ||
| 265 | return err; | ||
| 266 | if (!control) { | ||
| 267 | printk(KERN_ERR "i2sbus_control_init API breakage\n"); | ||
| 268 | return -ENODEV; | ||
| 269 | } | ||
| 270 | |||
| 271 | while ((np = of_get_next_child(dev->ofdev.node, np))) { | ||
| 272 | if (device_is_compatible(np, "i2sbus") || | ||
| 273 | device_is_compatible(np, "i2s-modem")) { | ||
| 274 | got += i2sbus_add_dev(dev, control, np); | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | if (!got) { | ||
| 279 | /* found none, clean up */ | ||
| 280 | i2sbus_control_destroy(control); | ||
| 281 | return -ENODEV; | ||
| 282 | } | ||
| 283 | |||
| 284 | dev->ofdev.dev.driver_data = control; | ||
| 285 | |||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | static int i2sbus_remove(struct macio_dev* dev) | ||
| 290 | { | ||
| 291 | struct i2sbus_control *control = dev->ofdev.dev.driver_data; | ||
| 292 | struct i2sbus_dev *i2sdev, *tmp; | ||
| 293 | |||
| 294 | list_for_each_entry_safe(i2sdev, tmp, &control->list, item) | ||
| 295 | soundbus_remove_one(&i2sdev->sound); | ||
| 296 | |||
| 297 | return 0; | ||
| 298 | } | ||
| 299 | |||
| 300 | #ifdef CONFIG_PM | ||
| 301 | static int i2sbus_suspend(struct macio_dev* dev, pm_message_t state) | ||
| 302 | { | ||
| 303 | struct i2sbus_control *control = dev->ofdev.dev.driver_data; | ||
| 304 | struct codec_info_item *cii; | ||
| 305 | struct i2sbus_dev* i2sdev; | ||
| 306 | int err, ret = 0; | ||
| 307 | |||
| 308 | list_for_each_entry(i2sdev, &control->list, item) { | ||
| 309 | /* Notify Alsa */ | ||
| 310 | if (i2sdev->sound.pcm) { | ||
| 311 | /* Suspend PCM streams */ | ||
| 312 | snd_pcm_suspend_all(i2sdev->sound.pcm); | ||
| 313 | /* Probably useless as we handle | ||
| 314 | * power transitions ourselves */ | ||
| 315 | snd_power_change_state(i2sdev->sound.pcm->card, | ||
| 316 | SNDRV_CTL_POWER_D3hot); | ||
| 317 | } | ||
| 318 | /* Notify codecs */ | ||
| 319 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
| 320 | err = 0; | ||
| 321 | if (cii->codec->suspend) | ||
| 322 | err = cii->codec->suspend(cii, state); | ||
| 323 | if (err) | ||
| 324 | ret = err; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | return ret; | ||
| 328 | } | ||
| 329 | |||
| 330 | static int i2sbus_resume(struct macio_dev* dev) | ||
| 331 | { | ||
| 332 | struct i2sbus_control *control = dev->ofdev.dev.driver_data; | ||
| 333 | struct codec_info_item *cii; | ||
| 334 | struct i2sbus_dev* i2sdev; | ||
| 335 | int err, ret = 0; | ||
| 336 | |||
| 337 | list_for_each_entry(i2sdev, &control->list, item) { | ||
| 338 | /* Notify codecs so they can re-initialize */ | ||
| 339 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
| 340 | err = 0; | ||
| 341 | if (cii->codec->resume) | ||
| 342 | err = cii->codec->resume(cii); | ||
| 343 | if (err) | ||
| 344 | ret = err; | ||
| 345 | } | ||
| 346 | /* Notify Alsa */ | ||
| 347 | if (i2sdev->sound.pcm) { | ||
| 348 | /* Same comment as above, probably useless */ | ||
| 349 | snd_power_change_state(i2sdev->sound.pcm->card, | ||
| 350 | SNDRV_CTL_POWER_D0); | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 354 | return ret; | ||
| 355 | } | ||
| 356 | #endif /* CONFIG_PM */ | ||
| 357 | |||
| 358 | static int i2sbus_shutdown(struct macio_dev* dev) | ||
| 359 | { | ||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | |||
| 363 | static struct macio_driver i2sbus_drv = { | ||
| 364 | .name = "soundbus-i2s", | ||
| 365 | .owner = THIS_MODULE, | ||
| 366 | .match_table = i2sbus_match, | ||
| 367 | .probe = i2sbus_probe, | ||
| 368 | .remove = i2sbus_remove, | ||
| 369 | #ifdef CONFIG_PM | ||
| 370 | .suspend = i2sbus_suspend, | ||
| 371 | .resume = i2sbus_resume, | ||
| 372 | #endif | ||
| 373 | .shutdown = i2sbus_shutdown, | ||
| 374 | }; | ||
| 375 | |||
| 376 | static int __init soundbus_i2sbus_init(void) | ||
| 377 | { | ||
| 378 | return macio_register_driver(&i2sbus_drv); | ||
| 379 | } | ||
| 380 | |||
| 381 | static void __exit soundbus_i2sbus_exit(void) | ||
| 382 | { | ||
| 383 | macio_unregister_driver(&i2sbus_drv); | ||
| 384 | } | ||
| 385 | |||
| 386 | module_init(soundbus_i2sbus_init); | ||
| 387 | module_exit(soundbus_i2sbus_exit); | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-interface.h b/sound/aoa/soundbus/i2sbus/i2sbus-interface.h new file mode 100644 index 000000000000..c6b5f5452d20 --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-interface.h | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* | ||
| 2 | * i2sbus driver -- interface register definitions | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | #ifndef __I2SBUS_INTERFACE_H | ||
| 9 | #define __I2SBUS_INTERFACE_H | ||
| 10 | |||
| 11 | /* i2s bus control registers, at least what we know about them */ | ||
| 12 | |||
| 13 | #define __PAD(m,n) u8 __pad##m[n] | ||
| 14 | #define _PAD(line, n) __PAD(line, n) | ||
| 15 | #define PAD(n) _PAD(__LINE__, (n)) | ||
| 16 | struct i2s_interface_regs { | ||
| 17 | __le32 intr_ctl; /* 0x00 */ | ||
| 18 | PAD(12); | ||
| 19 | __le32 serial_format; /* 0x10 */ | ||
| 20 | PAD(12); | ||
| 21 | __le32 codec_msg_out; /* 0x20 */ | ||
| 22 | PAD(12); | ||
| 23 | __le32 codec_msg_in; /* 0x30 */ | ||
| 24 | PAD(12); | ||
| 25 | __le32 frame_count; /* 0x40 */ | ||
| 26 | PAD(12); | ||
| 27 | __le32 frame_match; /* 0x50 */ | ||
| 28 | PAD(12); | ||
| 29 | __le32 data_word_sizes; /* 0x60 */ | ||
| 30 | PAD(12); | ||
| 31 | __le32 peak_level_sel; /* 0x70 */ | ||
| 32 | PAD(12); | ||
| 33 | __le32 peak_level_in0; /* 0x80 */ | ||
| 34 | PAD(12); | ||
| 35 | __le32 peak_level_in1; /* 0x90 */ | ||
| 36 | PAD(12); | ||
| 37 | /* total size: 0x100 bytes */ | ||
| 38 | } __attribute__((__packed__)); | ||
| 39 | |||
| 40 | /* interrupt register is just a bitfield with | ||
| 41 | * interrupt enable and pending bits */ | ||
| 42 | #define I2S_REG_INTR_CTL 0x00 | ||
| 43 | # define I2S_INT_FRAME_COUNT (1<<31) | ||
| 44 | # define I2S_PENDING_FRAME_COUNT (1<<30) | ||
| 45 | # define I2S_INT_MESSAGE_FLAG (1<<29) | ||
| 46 | # define I2S_PENDING_MESSAGE_FLAG (1<<28) | ||
| 47 | # define I2S_INT_NEW_PEAK (1<<27) | ||
| 48 | # define I2S_PENDING_NEW_PEAK (1<<26) | ||
| 49 | # define I2S_INT_CLOCKS_STOPPED (1<<25) | ||
| 50 | # define I2S_PENDING_CLOCKS_STOPPED (1<<24) | ||
| 51 | # define I2S_INT_EXTERNAL_SYNC_ERROR (1<<23) | ||
| 52 | # define I2S_PENDING_EXTERNAL_SYNC_ERROR (1<<22) | ||
| 53 | # define I2S_INT_EXTERNAL_SYNC_OK (1<<21) | ||
| 54 | # define I2S_PENDING_EXTERNAL_SYNC_OK (1<<20) | ||
| 55 | # define I2S_INT_NEW_SAMPLE_RATE (1<<19) | ||
| 56 | # define I2S_PENDING_NEW_SAMPLE_RATE (1<<18) | ||
| 57 | # define I2S_INT_STATUS_FLAG (1<<17) | ||
| 58 | # define I2S_PENDING_STATUS_FLAG (1<<16) | ||
| 59 | |||
| 60 | /* serial format register is more interesting :) | ||
| 61 | * It contains: | ||
| 62 | * - clock source | ||
| 63 | * - MClk divisor | ||
| 64 | * - SClk divisor | ||
| 65 | * - SClk master flag | ||
| 66 | * - serial format (sony, i2s 64x, i2s 32x, dav, silabs) | ||
| 67 | * - external sample frequency interrupt (don't understand) | ||
| 68 | * - external sample frequency | ||
| 69 | */ | ||
| 70 | #define I2S_REG_SERIAL_FORMAT 0x10 | ||
| 71 | /* clock source. You get either 18.432, 45.1584 or 49.1520 MHz */ | ||
| 72 | # define I2S_SF_CLOCK_SOURCE_SHIFT 30 | ||
| 73 | # define I2S_SF_CLOCK_SOURCE_MASK (3<<I2S_SF_CLOCK_SOURCE_SHIFT) | ||
| 74 | # define I2S_SF_CLOCK_SOURCE_18MHz (0<<I2S_SF_CLOCK_SOURCE_SHIFT) | ||
| 75 | # define I2S_SF_CLOCK_SOURCE_45MHz (1<<I2S_SF_CLOCK_SOURCE_SHIFT) | ||
| 76 | # define I2S_SF_CLOCK_SOURCE_49MHz (2<<I2S_SF_CLOCK_SOURCE_SHIFT) | ||
| 77 | /* also, let's define the exact clock speeds here, in Hz */ | ||
| 78 | #define I2S_CLOCK_SPEED_18MHz 18432000 | ||
| 79 | #define I2S_CLOCK_SPEED_45MHz 45158400 | ||
| 80 | #define I2S_CLOCK_SPEED_49MHz 49152000 | ||
| 81 | /* MClk is the clock that drives the codec, usually called its 'system clock'. | ||
| 82 | * It is derived by taking only every 'divisor' tick of the clock. | ||
| 83 | */ | ||
| 84 | # define I2S_SF_MCLKDIV_SHIFT 24 | ||
| 85 | # define I2S_SF_MCLKDIV_MASK (0x1F<<I2S_SF_MCLKDIV_SHIFT) | ||
| 86 | # define I2S_SF_MCLKDIV_1 (0x14<<I2S_SF_MCLKDIV_SHIFT) | ||
| 87 | # define I2S_SF_MCLKDIV_3 (0x13<<I2S_SF_MCLKDIV_SHIFT) | ||
| 88 | # define I2S_SF_MCLKDIV_5 (0x12<<I2S_SF_MCLKDIV_SHIFT) | ||
| 89 | # define I2S_SF_MCLKDIV_14 (0x0E<<I2S_SF_MCLKDIV_SHIFT) | ||
| 90 | # define I2S_SF_MCLKDIV_OTHER(div) (((div/2-1)<<I2S_SF_MCLKDIV_SHIFT)&I2S_SF_MCLKDIV_MASK) | ||
| 91 | static inline int i2s_sf_mclkdiv(int div, int *out) | ||
| 92 | { | ||
| 93 | int d; | ||
| 94 | |||
| 95 | switch(div) { | ||
| 96 | case 1: *out |= I2S_SF_MCLKDIV_1; return 0; | ||
| 97 | case 3: *out |= I2S_SF_MCLKDIV_3; return 0; | ||
| 98 | case 5: *out |= I2S_SF_MCLKDIV_5; return 0; | ||
| 99 | case 14: *out |= I2S_SF_MCLKDIV_14; return 0; | ||
| 100 | default: | ||
| 101 | if (div%2) return -1; | ||
| 102 | d = div/2-1; | ||
| 103 | if (d == 0x14 || d == 0x13 || d == 0x12 || d == 0x0E) | ||
| 104 | return -1; | ||
| 105 | *out |= I2S_SF_MCLKDIV_OTHER(div); | ||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | /* SClk is the clock that drives the i2s wire bus. Note that it is | ||
| 110 | * derived from the MClk above by taking only every 'divisor' tick | ||
| 111 | * of MClk. | ||
| 112 | */ | ||
| 113 | # define I2S_SF_SCLKDIV_SHIFT 20 | ||
| 114 | # define I2S_SF_SCLKDIV_MASK (0xF<<I2S_SF_SCLKDIV_SHIFT) | ||
| 115 | # define I2S_SF_SCLKDIV_1 (8<<I2S_SF_SCLKDIV_SHIFT) | ||
| 116 | # define I2S_SF_SCLKDIV_3 (9<<I2S_SF_SCLKDIV_SHIFT) | ||
| 117 | # define I2S_SF_SCLKDIV_OTHER(div) (((div/2-1)<<I2S_SF_SCLKDIV_SHIFT)&I2S_SF_SCLKDIV_MASK) | ||
| 118 | static inline int i2s_sf_sclkdiv(int div, int *out) | ||
| 119 | { | ||
| 120 | int d; | ||
| 121 | |||
| 122 | switch(div) { | ||
| 123 | case 1: *out |= I2S_SF_SCLKDIV_1; return 0; | ||
| 124 | case 3: *out |= I2S_SF_SCLKDIV_3; return 0; | ||
| 125 | default: | ||
| 126 | if (div%2) return -1; | ||
| 127 | d = div/2-1; | ||
| 128 | if (d == 8 || d == 9) return -1; | ||
| 129 | *out |= I2S_SF_SCLKDIV_OTHER(div); | ||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | # define I2S_SF_SCLK_MASTER (1<<19) | ||
| 134 | /* serial format is the way the data is put to the i2s wire bus */ | ||
| 135 | # define I2S_SF_SERIAL_FORMAT_SHIFT 16 | ||
| 136 | # define I2S_SF_SERIAL_FORMAT_MASK (7<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
| 137 | # define I2S_SF_SERIAL_FORMAT_SONY (0<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
| 138 | # define I2S_SF_SERIAL_FORMAT_I2S_64X (1<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
| 139 | # define I2S_SF_SERIAL_FORMAT_I2S_32X (2<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
| 140 | # define I2S_SF_SERIAL_FORMAT_I2S_DAV (4<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
| 141 | # define I2S_SF_SERIAL_FORMAT_I2S_SILABS (5<<I2S_SF_SERIAL_FORMAT_SHIFT) | ||
| 142 | /* unknown */ | ||
| 143 | # define I2S_SF_EXT_SAMPLE_FREQ_INT_SHIFT 12 | ||
| 144 | # define I2S_SF_EXT_SAMPLE_FREQ_INT_MASK (0xF<<I2S_SF_SAMPLE_FREQ_INT_SHIFT) | ||
| 145 | /* probably gives external frequency? */ | ||
| 146 | # define I2S_SF_EXT_SAMPLE_FREQ_MASK 0xFFF | ||
| 147 | |||
| 148 | /* used to send codec messages, but how isn't clear */ | ||
| 149 | #define I2S_REG_CODEC_MSG_OUT 0x20 | ||
| 150 | |||
| 151 | /* used to receive codec messages, but how isn't clear */ | ||
| 152 | #define I2S_REG_CODEC_MSG_IN 0x30 | ||
| 153 | |||
| 154 | /* frame count reg isn't clear to me yet, but probably useful */ | ||
| 155 | #define I2S_REG_FRAME_COUNT 0x40 | ||
| 156 | |||
| 157 | /* program to some value, and get interrupt if frame count reaches it */ | ||
| 158 | #define I2S_REG_FRAME_MATCH 0x50 | ||
| 159 | |||
| 160 | /* this register describes how the bus transfers data */ | ||
| 161 | #define I2S_REG_DATA_WORD_SIZES 0x60 | ||
| 162 | /* number of interleaved input channels */ | ||
| 163 | # define I2S_DWS_NUM_CHANNELS_IN_SHIFT 24 | ||
| 164 | # define I2S_DWS_NUM_CHANNELS_IN_MASK (0x1F<<I2S_DWS_NUM_CHANNELS_IN_SHIFT) | ||
| 165 | /* word size of input data */ | ||
| 166 | # define I2S_DWS_DATA_IN_SIZE_SHIFT 16 | ||
| 167 | # define I2S_DWS_DATA_IN_16BIT (0<<I2S_DWS_DATA_IN_SIZE_SHIFT) | ||
| 168 | # define I2S_DWS_DATA_IN_24BIT (3<<I2S_DWS_DATA_IN_SIZE_SHIFT) | ||
| 169 | /* number of interleaved output channels */ | ||
| 170 | # define I2S_DWS_NUM_CHANNELS_OUT_SHIFT 8 | ||
| 171 | # define I2S_DWS_NUM_CHANNELS_OUT_MASK (0x1F<<I2S_DWS_NUM_CHANNELS_OUT_SHIFT) | ||
| 172 | /* word size of output data */ | ||
| 173 | # define I2S_DWS_DATA_OUT_SIZE_SHIFT 0 | ||
| 174 | # define I2S_DWS_DATA_OUT_16BIT (0<<I2S_DWS_DATA_OUT_SIZE_SHIFT) | ||
| 175 | # define I2S_DWS_DATA_OUT_24BIT (3<<I2S_DWS_DATA_OUT_SIZE_SHIFT) | ||
| 176 | |||
| 177 | |||
| 178 | /* unknown */ | ||
| 179 | #define I2S_REG_PEAK_LEVEL_SEL 0x70 | ||
| 180 | |||
| 181 | /* unknown */ | ||
| 182 | #define I2S_REG_PEAK_LEVEL_IN0 0x80 | ||
| 183 | |||
| 184 | /* unknown */ | ||
| 185 | #define I2S_REG_PEAK_LEVEL_IN1 0x90 | ||
| 186 | |||
| 187 | #endif /* __I2SBUS_INTERFACE_H */ | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c new file mode 100644 index 000000000000..3049015a04f1 --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c | |||
| @@ -0,0 +1,1021 @@ | |||
| 1 | /* | ||
| 2 | * i2sbus driver -- pcm routines | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <asm/io.h> | ||
| 10 | #include <linux/delay.h> | ||
| 11 | /* So apparently there's a reason for requiring driver.h | ||
| 12 | * to be included first, even if I don't know it... */ | ||
| 13 | #include <sound/driver.h> | ||
| 14 | #include <sound/core.h> | ||
| 15 | #include <asm/macio.h> | ||
| 16 | #include <linux/pci.h> | ||
| 17 | #include "../soundbus.h" | ||
| 18 | #include "i2sbus.h" | ||
| 19 | |||
| 20 | static inline void get_pcm_info(struct i2sbus_dev *i2sdev, int in, | ||
| 21 | struct pcm_info **pi, struct pcm_info **other) | ||
| 22 | { | ||
| 23 | if (in) { | ||
| 24 | if (pi) | ||
| 25 | *pi = &i2sdev->in; | ||
| 26 | if (other) | ||
| 27 | *other = &i2sdev->out; | ||
| 28 | } else { | ||
| 29 | if (pi) | ||
| 30 | *pi = &i2sdev->out; | ||
| 31 | if (other) | ||
| 32 | *other = &i2sdev->in; | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | static int clock_and_divisors(int mclk, int sclk, int rate, int *out) | ||
| 37 | { | ||
| 38 | /* sclk must be derived from mclk! */ | ||
| 39 | if (mclk % sclk) | ||
| 40 | return -1; | ||
| 41 | /* derive sclk register value */ | ||
| 42 | if (i2s_sf_sclkdiv(mclk / sclk, out)) | ||
| 43 | return -1; | ||
| 44 | |||
| 45 | if (I2S_CLOCK_SPEED_18MHz % (rate * mclk) == 0) { | ||
| 46 | if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_18MHz / (rate * mclk), out)) { | ||
| 47 | *out |= I2S_SF_CLOCK_SOURCE_18MHz; | ||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | if (I2S_CLOCK_SPEED_45MHz % (rate * mclk) == 0) { | ||
| 52 | if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_45MHz / (rate * mclk), out)) { | ||
| 53 | *out |= I2S_SF_CLOCK_SOURCE_45MHz; | ||
| 54 | return 0; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | if (I2S_CLOCK_SPEED_49MHz % (rate * mclk) == 0) { | ||
| 58 | if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_49MHz / (rate * mclk), out)) { | ||
| 59 | *out |= I2S_SF_CLOCK_SOURCE_49MHz; | ||
| 60 | return 0; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | return -1; | ||
| 64 | } | ||
| 65 | |||
| 66 | #define CHECK_RATE(rate) \ | ||
| 67 | do { if (rates & SNDRV_PCM_RATE_ ##rate) { \ | ||
| 68 | int dummy; \ | ||
| 69 | if (clock_and_divisors(sysclock_factor, \ | ||
| 70 | bus_factor, rate, &dummy)) \ | ||
| 71 | rates &= ~SNDRV_PCM_RATE_ ##rate; \ | ||
| 72 | } } while (0) | ||
| 73 | |||
| 74 | static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) | ||
| 75 | { | ||
| 76 | struct pcm_info *pi, *other; | ||
| 77 | struct soundbus_dev *sdev; | ||
| 78 | int masks_inited = 0, err; | ||
| 79 | struct codec_info_item *cii, *rev; | ||
| 80 | struct snd_pcm_hardware *hw; | ||
| 81 | u64 formats = 0; | ||
| 82 | unsigned int rates = 0; | ||
| 83 | struct transfer_info v; | ||
| 84 | int result = 0; | ||
| 85 | int bus_factor = 0, sysclock_factor = 0; | ||
| 86 | int found_this; | ||
| 87 | |||
| 88 | mutex_lock(&i2sdev->lock); | ||
| 89 | |||
| 90 | get_pcm_info(i2sdev, in, &pi, &other); | ||
| 91 | |||
| 92 | hw = &pi->substream->runtime->hw; | ||
| 93 | sdev = &i2sdev->sound; | ||
| 94 | |||
| 95 | if (pi->active) { | ||
| 96 | /* alsa messed up */ | ||
| 97 | result = -EBUSY; | ||
| 98 | goto out_unlock; | ||
| 99 | } | ||
| 100 | |||
| 101 | /* we now need to assign the hw */ | ||
| 102 | list_for_each_entry(cii, &sdev->codec_list, list) { | ||
| 103 | struct transfer_info *ti = cii->codec->transfers; | ||
| 104 | bus_factor = cii->codec->bus_factor; | ||
| 105 | sysclock_factor = cii->codec->sysclock_factor; | ||
| 106 | while (ti->formats && ti->rates) { | ||
| 107 | v = *ti; | ||
| 108 | if (ti->transfer_in == in | ||
| 109 | && cii->codec->usable(cii, ti, &v)) { | ||
| 110 | if (masks_inited) { | ||
| 111 | formats &= v.formats; | ||
| 112 | rates &= v.rates; | ||
| 113 | } else { | ||
| 114 | formats = v.formats; | ||
| 115 | rates = v.rates; | ||
| 116 | masks_inited = 1; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | ti++; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | if (!masks_inited || !bus_factor || !sysclock_factor) { | ||
| 123 | result = -ENODEV; | ||
| 124 | goto out_unlock; | ||
| 125 | } | ||
| 126 | /* bus dependent stuff */ | ||
| 127 | hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | ||
| 128 | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME; | ||
| 129 | |||
| 130 | CHECK_RATE(5512); | ||
| 131 | CHECK_RATE(8000); | ||
| 132 | CHECK_RATE(11025); | ||
| 133 | CHECK_RATE(16000); | ||
| 134 | CHECK_RATE(22050); | ||
| 135 | CHECK_RATE(32000); | ||
| 136 | CHECK_RATE(44100); | ||
| 137 | CHECK_RATE(48000); | ||
| 138 | CHECK_RATE(64000); | ||
| 139 | CHECK_RATE(88200); | ||
| 140 | CHECK_RATE(96000); | ||
| 141 | CHECK_RATE(176400); | ||
| 142 | CHECK_RATE(192000); | ||
| 143 | hw->rates = rates; | ||
| 144 | |||
| 145 | /* well. the codec might want 24 bits only, and we'll | ||
| 146 | * ever only transfer 24 bits, but they are top-aligned! | ||
| 147 | * So for alsa, we claim that we're doing full 32 bit | ||
| 148 | * while in reality we'll ignore the lower 8 bits of | ||
| 149 | * that when doing playback (they're transferred as 0 | ||
| 150 | * as far as I know, no codecs we have are 32-bit capable | ||
| 151 | * so I can't really test) and when doing recording we'll | ||
| 152 | * always have those lower 8 bits recorded as 0 */ | ||
| 153 | if (formats & SNDRV_PCM_FMTBIT_S24_BE) | ||
| 154 | formats |= SNDRV_PCM_FMTBIT_S32_BE; | ||
| 155 | if (formats & SNDRV_PCM_FMTBIT_U24_BE) | ||
| 156 | formats |= SNDRV_PCM_FMTBIT_U32_BE; | ||
| 157 | /* now mask off what we can support. I suppose we could | ||
| 158 | * also support S24_3LE and some similar formats, but I | ||
| 159 | * doubt there's a codec that would be able to use that, | ||
| 160 | * so we don't support it here. */ | ||
| 161 | hw->formats = formats & (SNDRV_PCM_FMTBIT_S16_BE | | ||
| 162 | SNDRV_PCM_FMTBIT_U16_BE | | ||
| 163 | SNDRV_PCM_FMTBIT_S32_BE | | ||
| 164 | SNDRV_PCM_FMTBIT_U32_BE); | ||
| 165 | |||
| 166 | /* we need to set the highest and lowest rate possible. | ||
| 167 | * These are the highest and lowest rates alsa can | ||
| 168 | * support properly in its bitfield. | ||
| 169 | * Below, we'll use that to restrict to the rate | ||
| 170 | * currently in use (if any). */ | ||
| 171 | hw->rate_min = 5512; | ||
| 172 | hw->rate_max = 192000; | ||
| 173 | /* if the other stream is active, then we can only | ||
| 174 | * support what it is currently using. | ||
| 175 | * FIXME: I lied. This comment is wrong. We can support | ||
| 176 | * anything that works with the same serial format, ie. | ||
| 177 | * when recording 24 bit sound we can well play 16 bit | ||
| 178 | * sound at the same time iff using the same transfer mode. | ||
| 179 | */ | ||
| 180 | if (other->active) { | ||
| 181 | /* FIXME: is this guaranteed by the alsa api? */ | ||
| 182 | hw->formats &= (1ULL << i2sdev->format); | ||
| 183 | /* see above, restrict rates to the one we already have */ | ||
| 184 | hw->rate_min = i2sdev->rate; | ||
| 185 | hw->rate_max = i2sdev->rate; | ||
| 186 | } | ||
| 187 | |||
| 188 | hw->channels_min = 2; | ||
| 189 | hw->channels_max = 2; | ||
| 190 | /* these are somewhat arbitrary */ | ||
| 191 | hw->buffer_bytes_max = 131072; | ||
| 192 | hw->period_bytes_min = 256; | ||
| 193 | hw->period_bytes_max = 16384; | ||
| 194 | hw->periods_min = 3; | ||
| 195 | hw->periods_max = MAX_DBDMA_COMMANDS; | ||
| 196 | list_for_each_entry(cii, &sdev->codec_list, list) { | ||
| 197 | if (cii->codec->open) { | ||
| 198 | err = cii->codec->open(cii, pi->substream); | ||
| 199 | if (err) { | ||
| 200 | result = err; | ||
| 201 | /* unwind */ | ||
| 202 | found_this = 0; | ||
| 203 | list_for_each_entry_reverse(rev, | ||
| 204 | &sdev->codec_list, list) { | ||
| 205 | if (found_this && rev->codec->close) { | ||
| 206 | rev->codec->close(rev, | ||
| 207 | pi->substream); | ||
| 208 | } | ||
| 209 | if (rev == cii) | ||
| 210 | found_this = 1; | ||
| 211 | } | ||
| 212 | goto out_unlock; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | out_unlock: | ||
| 218 | mutex_unlock(&i2sdev->lock); | ||
| 219 | return result; | ||
| 220 | } | ||
| 221 | |||
| 222 | #undef CHECK_RATE | ||
| 223 | |||
| 224 | static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in) | ||
| 225 | { | ||
| 226 | struct codec_info_item *cii; | ||
| 227 | struct pcm_info *pi; | ||
| 228 | int err = 0, tmp; | ||
| 229 | |||
| 230 | mutex_lock(&i2sdev->lock); | ||
| 231 | |||
| 232 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
| 233 | |||
| 234 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
| 235 | if (cii->codec->close) { | ||
| 236 | tmp = cii->codec->close(cii, pi->substream); | ||
| 237 | if (tmp) | ||
| 238 | err = tmp; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | pi->substream = NULL; | ||
| 243 | pi->active = 0; | ||
| 244 | mutex_unlock(&i2sdev->lock); | ||
| 245 | return err; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int i2sbus_hw_params(struct snd_pcm_substream *substream, | ||
| 249 | struct snd_pcm_hw_params *params) | ||
| 250 | { | ||
| 251 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
| 252 | } | ||
| 253 | |||
| 254 | static int i2sbus_hw_free(struct snd_pcm_substream *substream) | ||
| 255 | { | ||
| 256 | snd_pcm_lib_free_pages(substream); | ||
| 257 | return 0; | ||
| 258 | } | ||
| 259 | |||
| 260 | static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) | ||
| 261 | { | ||
| 262 | /* whee. Hard work now. The user has selected a bitrate | ||
| 263 | * and bit format, so now we have to program our | ||
| 264 | * I2S controller appropriately. */ | ||
| 265 | struct snd_pcm_runtime *runtime; | ||
| 266 | struct dbdma_cmd *command; | ||
| 267 | int i, periodsize; | ||
| 268 | dma_addr_t offset; | ||
| 269 | struct bus_info bi; | ||
| 270 | struct codec_info_item *cii; | ||
| 271 | int sfr = 0; /* serial format register */ | ||
| 272 | int dws = 0; /* data word sizes reg */ | ||
| 273 | int input_16bit; | ||
| 274 | struct pcm_info *pi, *other; | ||
| 275 | int cnt; | ||
| 276 | int result = 0; | ||
| 277 | |||
| 278 | mutex_lock(&i2sdev->lock); | ||
| 279 | |||
| 280 | get_pcm_info(i2sdev, in, &pi, &other); | ||
| 281 | |||
| 282 | if (pi->dbdma_ring.running) { | ||
| 283 | result = -EBUSY; | ||
| 284 | goto out_unlock; | ||
| 285 | } | ||
| 286 | |||
| 287 | runtime = pi->substream->runtime; | ||
| 288 | pi->active = 1; | ||
| 289 | if (other->active && | ||
| 290 | ((i2sdev->format != runtime->format) | ||
| 291 | || (i2sdev->rate != runtime->rate))) { | ||
| 292 | result = -EINVAL; | ||
| 293 | goto out_unlock; | ||
| 294 | } | ||
| 295 | |||
| 296 | i2sdev->format = runtime->format; | ||
| 297 | i2sdev->rate = runtime->rate; | ||
| 298 | |||
| 299 | periodsize = snd_pcm_lib_period_bytes(pi->substream); | ||
| 300 | pi->current_period = 0; | ||
| 301 | |||
| 302 | /* generate dbdma command ring first */ | ||
| 303 | command = pi->dbdma_ring.cmds; | ||
| 304 | offset = runtime->dma_addr; | ||
| 305 | for (i = 0; i < pi->substream->runtime->periods; | ||
| 306 | i++, command++, offset += periodsize) { | ||
| 307 | memset(command, 0, sizeof(struct dbdma_cmd)); | ||
| 308 | command->command = | ||
| 309 | cpu_to_le16((in ? INPUT_MORE : OUTPUT_MORE) | INTR_ALWAYS); | ||
| 310 | command->phy_addr = cpu_to_le32(offset); | ||
| 311 | command->req_count = cpu_to_le16(periodsize); | ||
| 312 | command->xfer_status = cpu_to_le16(0); | ||
| 313 | } | ||
| 314 | /* last one branches back to first */ | ||
| 315 | command--; | ||
| 316 | command->command |= cpu_to_le16(BR_ALWAYS); | ||
| 317 | command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start); | ||
| 318 | |||
| 319 | /* ok, let's set the serial format and stuff */ | ||
| 320 | switch (runtime->format) { | ||
| 321 | /* 16 bit formats */ | ||
| 322 | case SNDRV_PCM_FORMAT_S16_BE: | ||
| 323 | case SNDRV_PCM_FORMAT_U16_BE: | ||
| 324 | /* FIXME: if we add different bus factors we need to | ||
| 325 | * do more here!! */ | ||
| 326 | bi.bus_factor = 0; | ||
| 327 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
| 328 | bi.bus_factor = cii->codec->bus_factor; | ||
| 329 | break; | ||
| 330 | } | ||
| 331 | if (!bi.bus_factor) { | ||
| 332 | result = -ENODEV; | ||
| 333 | goto out_unlock; | ||
| 334 | } | ||
| 335 | input_16bit = 1; | ||
| 336 | break; | ||
| 337 | case SNDRV_PCM_FORMAT_S32_BE: | ||
| 338 | case SNDRV_PCM_FORMAT_U32_BE: | ||
| 339 | /* force 64x bus speed, otherwise the data cannot be | ||
| 340 | * transferred quickly enough! */ | ||
| 341 | bi.bus_factor = 64; | ||
| 342 | input_16bit = 0; | ||
| 343 | break; | ||
| 344 | default: | ||
| 345 | result = -EINVAL; | ||
| 346 | goto out_unlock; | ||
| 347 | } | ||
| 348 | /* we assume all sysclocks are the same! */ | ||
| 349 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
| 350 | bi.sysclock_factor = cii->codec->sysclock_factor; | ||
| 351 | break; | ||
| 352 | } | ||
| 353 | |||
| 354 | if (clock_and_divisors(bi.sysclock_factor, | ||
| 355 | bi.bus_factor, | ||
| 356 | runtime->rate, | ||
| 357 | &sfr) < 0) { | ||
| 358 | result = -EINVAL; | ||
| 359 | goto out_unlock; | ||
| 360 | } | ||
| 361 | switch (bi.bus_factor) { | ||
| 362 | case 32: | ||
| 363 | sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X; | ||
| 364 | break; | ||
| 365 | case 64: | ||
| 366 | sfr |= I2S_SF_SERIAL_FORMAT_I2S_64X; | ||
| 367 | break; | ||
| 368 | } | ||
| 369 | /* FIXME: THIS ASSUMES MASTER ALL THE TIME */ | ||
| 370 | sfr |= I2S_SF_SCLK_MASTER; | ||
| 371 | |||
| 372 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
| 373 | int err = 0; | ||
| 374 | if (cii->codec->prepare) | ||
| 375 | err = cii->codec->prepare(cii, &bi, pi->substream); | ||
| 376 | if (err) { | ||
| 377 | result = err; | ||
| 378 | goto out_unlock; | ||
| 379 | } | ||
| 380 | } | ||
| 381 | /* codecs are fine with it, so set our clocks */ | ||
| 382 | if (input_16bit) | ||
| 383 | dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) | | ||
| 384 | (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) | | ||
| 385 | I2S_DWS_DATA_IN_16BIT | I2S_DWS_DATA_OUT_16BIT; | ||
| 386 | else | ||
| 387 | dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) | | ||
| 388 | (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) | | ||
| 389 | I2S_DWS_DATA_IN_24BIT | I2S_DWS_DATA_OUT_24BIT; | ||
| 390 | |||
| 391 | /* early exit if already programmed correctly */ | ||
| 392 | /* not locking these is fine since we touch them only in this function */ | ||
| 393 | if (in_le32(&i2sdev->intfregs->serial_format) == sfr | ||
| 394 | && in_le32(&i2sdev->intfregs->data_word_sizes) == dws) | ||
| 395 | goto out_unlock; | ||
| 396 | |||
| 397 | /* let's notify the codecs about clocks going away. | ||
| 398 | * For now we only do mastering on the i2s cell... */ | ||
| 399 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
| 400 | if (cii->codec->switch_clock) | ||
| 401 | cii->codec->switch_clock(cii, CLOCK_SWITCH_PREPARE_SLAVE); | ||
| 402 | |||
| 403 | i2sbus_control_enable(i2sdev->control, i2sdev); | ||
| 404 | i2sbus_control_cell(i2sdev->control, i2sdev, 1); | ||
| 405 | |||
| 406 | out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED); | ||
| 407 | |||
| 408 | i2sbus_control_clock(i2sdev->control, i2sdev, 0); | ||
| 409 | |||
| 410 | msleep(1); | ||
| 411 | |||
| 412 | /* wait for clock stopped. This can apparently take a while... */ | ||
| 413 | cnt = 100; | ||
| 414 | while (cnt-- && | ||
| 415 | !(in_le32(&i2sdev->intfregs->intr_ctl) & I2S_PENDING_CLOCKS_STOPPED)) { | ||
| 416 | msleep(5); | ||
| 417 | } | ||
| 418 | out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED); | ||
| 419 | |||
| 420 | /* not locking these is fine since we touch them only in this function */ | ||
| 421 | out_le32(&i2sdev->intfregs->serial_format, sfr); | ||
| 422 | out_le32(&i2sdev->intfregs->data_word_sizes, dws); | ||
| 423 | |||
| 424 | i2sbus_control_enable(i2sdev->control, i2sdev); | ||
| 425 | i2sbus_control_cell(i2sdev->control, i2sdev, 1); | ||
| 426 | i2sbus_control_clock(i2sdev->control, i2sdev, 1); | ||
| 427 | msleep(1); | ||
| 428 | |||
| 429 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
| 430 | if (cii->codec->switch_clock) | ||
| 431 | cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE); | ||
| 432 | |||
| 433 | out_unlock: | ||
| 434 | mutex_unlock(&i2sdev->lock); | ||
| 435 | return result; | ||
| 436 | } | ||
| 437 | |||
| 438 | static struct dbdma_cmd STOP_CMD = { | ||
| 439 | .command = __constant_cpu_to_le16(DBDMA_STOP), | ||
| 440 | }; | ||
| 441 | |||
| 442 | static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) | ||
| 443 | { | ||
| 444 | struct codec_info_item *cii; | ||
| 445 | struct pcm_info *pi; | ||
| 446 | int timeout; | ||
| 447 | struct dbdma_cmd tmp; | ||
| 448 | int result = 0; | ||
| 449 | unsigned long flags; | ||
| 450 | |||
| 451 | spin_lock_irqsave(&i2sdev->low_lock, flags); | ||
| 452 | |||
| 453 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
| 454 | |||
| 455 | switch (cmd) { | ||
| 456 | case SNDRV_PCM_TRIGGER_START: | ||
| 457 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 458 | if (pi->dbdma_ring.running) { | ||
| 459 | result = -EALREADY; | ||
| 460 | goto out_unlock; | ||
| 461 | } | ||
| 462 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
| 463 | if (cii->codec->start) | ||
| 464 | cii->codec->start(cii, pi->substream); | ||
| 465 | pi->dbdma_ring.running = 1; | ||
| 466 | |||
| 467 | /* reset dma engine */ | ||
| 468 | out_le32(&pi->dbdma->control, | ||
| 469 | 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); | ||
| 470 | timeout = 100; | ||
| 471 | while (in_le32(&pi->dbdma->status) & RUN && timeout--) | ||
| 472 | udelay(1); | ||
| 473 | if (timeout <= 0) { | ||
| 474 | printk(KERN_ERR | ||
| 475 | "i2sbus: error waiting for dma reset\n"); | ||
| 476 | result = -ENXIO; | ||
| 477 | goto out_unlock; | ||
| 478 | } | ||
| 479 | |||
| 480 | /* write dma command buffer address to the dbdma chip */ | ||
| 481 | out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); | ||
| 482 | /* post PCI write */ | ||
| 483 | mb(); | ||
| 484 | (void)in_le32(&pi->dbdma->status); | ||
| 485 | |||
| 486 | /* change first command to STOP */ | ||
| 487 | tmp = *pi->dbdma_ring.cmds; | ||
| 488 | *pi->dbdma_ring.cmds = STOP_CMD; | ||
| 489 | |||
| 490 | /* set running state, remember that the first command is STOP */ | ||
| 491 | out_le32(&pi->dbdma->control, RUN | (RUN << 16)); | ||
| 492 | timeout = 100; | ||
| 493 | /* wait for STOP to be executed */ | ||
| 494 | while (in_le32(&pi->dbdma->status) & ACTIVE && timeout--) | ||
| 495 | udelay(1); | ||
| 496 | if (timeout <= 0) { | ||
| 497 | printk(KERN_ERR "i2sbus: error waiting for dma stop\n"); | ||
| 498 | result = -ENXIO; | ||
| 499 | goto out_unlock; | ||
| 500 | } | ||
| 501 | /* again, write dma command buffer address to the dbdma chip, | ||
| 502 | * this time of the first real command */ | ||
| 503 | *pi->dbdma_ring.cmds = tmp; | ||
| 504 | out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); | ||
| 505 | /* post write */ | ||
| 506 | mb(); | ||
| 507 | (void)in_le32(&pi->dbdma->status); | ||
| 508 | |||
| 509 | /* reset dma engine again */ | ||
| 510 | out_le32(&pi->dbdma->control, | ||
| 511 | 0 | (RUN | PAUSE | FLUSH | WAKE) << 16); | ||
| 512 | timeout = 100; | ||
| 513 | while (in_le32(&pi->dbdma->status) & RUN && timeout--) | ||
| 514 | udelay(1); | ||
| 515 | if (timeout <= 0) { | ||
| 516 | printk(KERN_ERR | ||
| 517 | "i2sbus: error waiting for dma reset\n"); | ||
| 518 | result = -ENXIO; | ||
| 519 | goto out_unlock; | ||
| 520 | } | ||
| 521 | |||
| 522 | /* wake up the chip with the next descriptor */ | ||
| 523 | out_le32(&pi->dbdma->control, | ||
| 524 | (RUN | WAKE) | ((RUN | WAKE) << 16)); | ||
| 525 | /* get the frame count */ | ||
| 526 | pi->frame_count = in_le32(&i2sdev->intfregs->frame_count); | ||
| 527 | |||
| 528 | /* off you go! */ | ||
| 529 | break; | ||
| 530 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 531 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 532 | if (!pi->dbdma_ring.running) { | ||
| 533 | result = -EALREADY; | ||
| 534 | goto out_unlock; | ||
| 535 | } | ||
| 536 | |||
| 537 | /* turn off all relevant bits */ | ||
| 538 | out_le32(&pi->dbdma->control, | ||
| 539 | (RUN | WAKE | FLUSH | PAUSE) << 16); | ||
| 540 | { | ||
| 541 | /* FIXME: move to own function */ | ||
| 542 | int timeout = 5000; | ||
| 543 | while ((in_le32(&pi->dbdma->status) & RUN) | ||
| 544 | && --timeout > 0) | ||
| 545 | udelay(1); | ||
| 546 | if (!timeout) | ||
| 547 | printk(KERN_ERR | ||
| 548 | "i2sbus: timed out turning " | ||
| 549 | "off dbdma engine!\n"); | ||
| 550 | } | ||
| 551 | |||
| 552 | pi->dbdma_ring.running = 0; | ||
| 553 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
| 554 | if (cii->codec->stop) | ||
| 555 | cii->codec->stop(cii, pi->substream); | ||
| 556 | break; | ||
| 557 | default: | ||
| 558 | result = -EINVAL; | ||
| 559 | goto out_unlock; | ||
| 560 | } | ||
| 561 | |||
| 562 | out_unlock: | ||
| 563 | spin_unlock_irqrestore(&i2sdev->low_lock, flags); | ||
| 564 | return result; | ||
| 565 | } | ||
| 566 | |||
| 567 | static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in) | ||
| 568 | { | ||
| 569 | struct pcm_info *pi; | ||
| 570 | u32 fc; | ||
| 571 | |||
| 572 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
| 573 | |||
| 574 | fc = in_le32(&i2sdev->intfregs->frame_count); | ||
| 575 | fc = fc - pi->frame_count; | ||
| 576 | |||
| 577 | return (bytes_to_frames(pi->substream->runtime, | ||
| 578 | pi->current_period * | ||
| 579 | snd_pcm_lib_period_bytes(pi->substream)) | ||
| 580 | + fc) % pi->substream->runtime->buffer_size; | ||
| 581 | } | ||
| 582 | |||
| 583 | static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) | ||
| 584 | { | ||
| 585 | struct pcm_info *pi; | ||
| 586 | u32 fc; | ||
| 587 | u32 delta; | ||
| 588 | |||
| 589 | spin_lock(&i2sdev->low_lock); | ||
| 590 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
| 591 | |||
| 592 | if (!pi->dbdma_ring.running) { | ||
| 593 | /* there was still an interrupt pending | ||
| 594 | * while we stopped. or maybe another | ||
| 595 | * processor (not the one that was stopping | ||
| 596 | * the DMA engine) was spinning above | ||
| 597 | * waiting for the lock. */ | ||
| 598 | goto out_unlock; | ||
| 599 | } | ||
| 600 | |||
| 601 | fc = in_le32(&i2sdev->intfregs->frame_count); | ||
| 602 | /* a counter overflow does not change the calculation. */ | ||
| 603 | delta = fc - pi->frame_count; | ||
| 604 | |||
| 605 | /* update current_period */ | ||
| 606 | while (delta >= pi->substream->runtime->period_size) { | ||
| 607 | pi->current_period++; | ||
| 608 | delta = delta - pi->substream->runtime->period_size; | ||
| 609 | } | ||
| 610 | |||
| 611 | if (unlikely(delta)) { | ||
| 612 | /* Some interrupt came late, so check the dbdma. | ||
| 613 | * This special case exists to syncronize the frame_count with | ||
| 614 | * the dbdma transfer, but is hit every once in a while. */ | ||
| 615 | int period; | ||
| 616 | |||
| 617 | period = (in_le32(&pi->dbdma->cmdptr) | ||
| 618 | - pi->dbdma_ring.bus_cmd_start) | ||
| 619 | / sizeof(struct dbdma_cmd); | ||
| 620 | pi->current_period = pi->current_period | ||
| 621 | % pi->substream->runtime->periods; | ||
| 622 | |||
| 623 | while (pi->current_period != period) { | ||
| 624 | pi->current_period++; | ||
| 625 | pi->current_period %= pi->substream->runtime->periods; | ||
| 626 | /* Set delta to zero, as the frame_count value is too | ||
| 627 | * high (otherwise the code path will not be executed). | ||
| 628 | * This corrects the fact that the frame_count is too | ||
| 629 | * low at the beginning due to buffering. */ | ||
| 630 | delta = 0; | ||
| 631 | } | ||
| 632 | } | ||
| 633 | |||
| 634 | pi->frame_count = fc - delta; | ||
| 635 | pi->current_period %= pi->substream->runtime->periods; | ||
| 636 | |||
| 637 | spin_unlock(&i2sdev->low_lock); | ||
| 638 | /* may call _trigger again, hence needs to be unlocked */ | ||
| 639 | snd_pcm_period_elapsed(pi->substream); | ||
| 640 | return; | ||
| 641 | out_unlock: | ||
| 642 | spin_unlock(&i2sdev->low_lock); | ||
| 643 | } | ||
| 644 | |||
| 645 | irqreturn_t i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs) | ||
| 646 | { | ||
| 647 | handle_interrupt((struct i2sbus_dev *)devid, 0); | ||
| 648 | return IRQ_HANDLED; | ||
| 649 | } | ||
| 650 | |||
| 651 | irqreturn_t i2sbus_rx_intr(int irq, void *devid, struct pt_regs * regs) | ||
| 652 | { | ||
| 653 | handle_interrupt((struct i2sbus_dev *)devid, 1); | ||
| 654 | return IRQ_HANDLED; | ||
| 655 | } | ||
| 656 | |||
| 657 | static int i2sbus_playback_open(struct snd_pcm_substream *substream) | ||
| 658 | { | ||
| 659 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
| 660 | |||
| 661 | if (!i2sdev) | ||
| 662 | return -EINVAL; | ||
| 663 | i2sdev->out.substream = substream; | ||
| 664 | return i2sbus_pcm_open(i2sdev, 0); | ||
| 665 | } | ||
| 666 | |||
| 667 | static int i2sbus_playback_close(struct snd_pcm_substream *substream) | ||
| 668 | { | ||
| 669 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
| 670 | int err; | ||
| 671 | |||
| 672 | if (!i2sdev) | ||
| 673 | return -EINVAL; | ||
| 674 | if (i2sdev->out.substream != substream) | ||
| 675 | return -EINVAL; | ||
| 676 | err = i2sbus_pcm_close(i2sdev, 0); | ||
| 677 | if (!err) | ||
| 678 | i2sdev->out.substream = NULL; | ||
| 679 | return err; | ||
| 680 | } | ||
| 681 | |||
| 682 | static int i2sbus_playback_prepare(struct snd_pcm_substream *substream) | ||
| 683 | { | ||
| 684 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
| 685 | |||
| 686 | if (!i2sdev) | ||
| 687 | return -EINVAL; | ||
| 688 | if (i2sdev->out.substream != substream) | ||
| 689 | return -EINVAL; | ||
| 690 | return i2sbus_pcm_prepare(i2sdev, 0); | ||
| 691 | } | ||
| 692 | |||
| 693 | static int i2sbus_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 694 | { | ||
| 695 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
| 696 | |||
| 697 | if (!i2sdev) | ||
| 698 | return -EINVAL; | ||
| 699 | if (i2sdev->out.substream != substream) | ||
| 700 | return -EINVAL; | ||
| 701 | return i2sbus_pcm_trigger(i2sdev, 0, cmd); | ||
| 702 | } | ||
| 703 | |||
| 704 | static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream | ||
| 705 | *substream) | ||
| 706 | { | ||
| 707 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
| 708 | |||
| 709 | if (!i2sdev) | ||
| 710 | return -EINVAL; | ||
| 711 | if (i2sdev->out.substream != substream) | ||
| 712 | return 0; | ||
| 713 | return i2sbus_pcm_pointer(i2sdev, 0); | ||
| 714 | } | ||
| 715 | |||
| 716 | static struct snd_pcm_ops i2sbus_playback_ops = { | ||
| 717 | .open = i2sbus_playback_open, | ||
| 718 | .close = i2sbus_playback_close, | ||
| 719 | .ioctl = snd_pcm_lib_ioctl, | ||
| 720 | .hw_params = i2sbus_hw_params, | ||
| 721 | .hw_free = i2sbus_hw_free, | ||
| 722 | .prepare = i2sbus_playback_prepare, | ||
| 723 | .trigger = i2sbus_playback_trigger, | ||
| 724 | .pointer = i2sbus_playback_pointer, | ||
| 725 | }; | ||
| 726 | |||
| 727 | static int i2sbus_record_open(struct snd_pcm_substream *substream) | ||
| 728 | { | ||
| 729 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
| 730 | |||
| 731 | if (!i2sdev) | ||
| 732 | return -EINVAL; | ||
| 733 | i2sdev->in.substream = substream; | ||
| 734 | return i2sbus_pcm_open(i2sdev, 1); | ||
| 735 | } | ||
| 736 | |||
| 737 | static int i2sbus_record_close(struct snd_pcm_substream *substream) | ||
| 738 | { | ||
| 739 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
| 740 | int err; | ||
| 741 | |||
| 742 | if (!i2sdev) | ||
| 743 | return -EINVAL; | ||
| 744 | if (i2sdev->in.substream != substream) | ||
| 745 | return -EINVAL; | ||
| 746 | err = i2sbus_pcm_close(i2sdev, 1); | ||
| 747 | if (!err) | ||
| 748 | i2sdev->in.substream = NULL; | ||
| 749 | return err; | ||
| 750 | } | ||
| 751 | |||
| 752 | static int i2sbus_record_prepare(struct snd_pcm_substream *substream) | ||
| 753 | { | ||
| 754 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
| 755 | |||
| 756 | if (!i2sdev) | ||
| 757 | return -EINVAL; | ||
| 758 | if (i2sdev->in.substream != substream) | ||
| 759 | return -EINVAL; | ||
| 760 | return i2sbus_pcm_prepare(i2sdev, 1); | ||
| 761 | } | ||
| 762 | |||
| 763 | static int i2sbus_record_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 764 | { | ||
| 765 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
| 766 | |||
| 767 | if (!i2sdev) | ||
| 768 | return -EINVAL; | ||
| 769 | if (i2sdev->in.substream != substream) | ||
| 770 | return -EINVAL; | ||
| 771 | return i2sbus_pcm_trigger(i2sdev, 1, cmd); | ||
| 772 | } | ||
| 773 | |||
| 774 | static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream | ||
| 775 | *substream) | ||
| 776 | { | ||
| 777 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
| 778 | |||
| 779 | if (!i2sdev) | ||
| 780 | return -EINVAL; | ||
| 781 | if (i2sdev->in.substream != substream) | ||
| 782 | return 0; | ||
| 783 | return i2sbus_pcm_pointer(i2sdev, 1); | ||
| 784 | } | ||
| 785 | |||
| 786 | static struct snd_pcm_ops i2sbus_record_ops = { | ||
| 787 | .open = i2sbus_record_open, | ||
| 788 | .close = i2sbus_record_close, | ||
| 789 | .ioctl = snd_pcm_lib_ioctl, | ||
| 790 | .hw_params = i2sbus_hw_params, | ||
| 791 | .hw_free = i2sbus_hw_free, | ||
| 792 | .prepare = i2sbus_record_prepare, | ||
| 793 | .trigger = i2sbus_record_trigger, | ||
| 794 | .pointer = i2sbus_record_pointer, | ||
| 795 | }; | ||
| 796 | |||
| 797 | static void i2sbus_private_free(struct snd_pcm *pcm) | ||
| 798 | { | ||
| 799 | struct i2sbus_dev *i2sdev = snd_pcm_chip(pcm); | ||
| 800 | struct codec_info_item *p, *tmp; | ||
| 801 | |||
| 802 | i2sdev->sound.pcm = NULL; | ||
| 803 | i2sdev->out.created = 0; | ||
| 804 | i2sdev->in.created = 0; | ||
| 805 | list_for_each_entry_safe(p, tmp, &i2sdev->sound.codec_list, list) { | ||
| 806 | printk(KERN_ERR "i2sbus: a codec didn't unregister!\n"); | ||
| 807 | list_del(&p->list); | ||
| 808 | module_put(p->codec->owner); | ||
| 809 | kfree(p); | ||
| 810 | } | ||
| 811 | soundbus_dev_put(&i2sdev->sound); | ||
| 812 | module_put(THIS_MODULE); | ||
| 813 | } | ||
| 814 | |||
| 815 | /* FIXME: this function needs an error handling strategy with labels */ | ||
| 816 | int | ||
| 817 | i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | ||
| 818 | struct codec_info *ci, void *data) | ||
| 819 | { | ||
| 820 | int err, in = 0, out = 0; | ||
| 821 | struct transfer_info *tmp; | ||
| 822 | struct i2sbus_dev *i2sdev = soundbus_dev_to_i2sbus_dev(dev); | ||
| 823 | struct codec_info_item *cii; | ||
| 824 | |||
| 825 | if (!dev->pcmname || dev->pcmid == -1) { | ||
| 826 | printk(KERN_ERR "i2sbus: pcm name and id must be set!\n"); | ||
| 827 | return -EINVAL; | ||
| 828 | } | ||
| 829 | |||
| 830 | list_for_each_entry(cii, &dev->codec_list, list) { | ||
| 831 | if (cii->codec_data == data) | ||
| 832 | return -EALREADY; | ||
| 833 | } | ||
| 834 | |||
| 835 | if (!ci->transfers || !ci->transfers->formats | ||
| 836 | || !ci->transfers->rates || !ci->usable) | ||
| 837 | return -EINVAL; | ||
| 838 | |||
| 839 | /* we currently code the i2s transfer on the clock, and support only | ||
| 840 | * 32 and 64 */ | ||
| 841 | if (ci->bus_factor != 32 && ci->bus_factor != 64) | ||
| 842 | return -EINVAL; | ||
| 843 | |||
| 844 | /* If you want to fix this, you need to keep track of what transport infos | ||
| 845 | * are to be used, which codecs they belong to, and then fix all the | ||
| 846 | * sysclock/busclock stuff above to depend on which is usable */ | ||
| 847 | list_for_each_entry(cii, &dev->codec_list, list) { | ||
| 848 | if (cii->codec->sysclock_factor != ci->sysclock_factor) { | ||
| 849 | printk(KERN_DEBUG | ||
| 850 | "cannot yet handle multiple different sysclocks!\n"); | ||
| 851 | return -EINVAL; | ||
| 852 | } | ||
| 853 | if (cii->codec->bus_factor != ci->bus_factor) { | ||
| 854 | printk(KERN_DEBUG | ||
| 855 | "cannot yet handle multiple different bus clocks!\n"); | ||
| 856 | return -EINVAL; | ||
| 857 | } | ||
| 858 | } | ||
| 859 | |||
| 860 | tmp = ci->transfers; | ||
| 861 | while (tmp->formats && tmp->rates) { | ||
| 862 | if (tmp->transfer_in) | ||
| 863 | in = 1; | ||
| 864 | else | ||
| 865 | out = 1; | ||
| 866 | tmp++; | ||
| 867 | } | ||
| 868 | |||
| 869 | cii = kzalloc(sizeof(struct codec_info_item), GFP_KERNEL); | ||
| 870 | if (!cii) { | ||
| 871 | printk(KERN_DEBUG "i2sbus: failed to allocate cii\n"); | ||
| 872 | return -ENOMEM; | ||
| 873 | } | ||
| 874 | |||
| 875 | /* use the private data to point to the codec info */ | ||
| 876 | cii->sdev = soundbus_dev_get(dev); | ||
| 877 | cii->codec = ci; | ||
| 878 | cii->codec_data = data; | ||
| 879 | |||
| 880 | if (!cii->sdev) { | ||
| 881 | printk(KERN_DEBUG | ||
| 882 | "i2sbus: failed to get soundbus dev reference\n"); | ||
| 883 | kfree(cii); | ||
| 884 | return -ENODEV; | ||
| 885 | } | ||
| 886 | |||
| 887 | if (!try_module_get(THIS_MODULE)) { | ||
| 888 | printk(KERN_DEBUG "i2sbus: failed to get module reference!\n"); | ||
| 889 | soundbus_dev_put(dev); | ||
| 890 | kfree(cii); | ||
| 891 | return -EBUSY; | ||
| 892 | } | ||
| 893 | |||
| 894 | if (!try_module_get(ci->owner)) { | ||
| 895 | printk(KERN_DEBUG | ||
| 896 | "i2sbus: failed to get module reference to codec owner!\n"); | ||
| 897 | module_put(THIS_MODULE); | ||
| 898 | soundbus_dev_put(dev); | ||
| 899 | kfree(cii); | ||
| 900 | return -EBUSY; | ||
| 901 | } | ||
| 902 | |||
| 903 | if (!dev->pcm) { | ||
| 904 | err = snd_pcm_new(card, | ||
| 905 | dev->pcmname, | ||
| 906 | dev->pcmid, | ||
| 907 | 0, | ||
| 908 | 0, | ||
| 909 | &dev->pcm); | ||
| 910 | if (err) { | ||
| 911 | printk(KERN_DEBUG "i2sbus: failed to create pcm\n"); | ||
| 912 | kfree(cii); | ||
| 913 | module_put(ci->owner); | ||
| 914 | soundbus_dev_put(dev); | ||
| 915 | module_put(THIS_MODULE); | ||
| 916 | return err; | ||
| 917 | } | ||
| 918 | } | ||
| 919 | |||
| 920 | /* ALSA yet again sucks. | ||
| 921 | * If it is ever fixed, remove this line. See below. */ | ||
| 922 | out = in = 1; | ||
| 923 | |||
| 924 | if (!i2sdev->out.created && out) { | ||
| 925 | if (dev->pcm->card != card) { | ||
| 926 | /* eh? */ | ||
| 927 | printk(KERN_ERR | ||
| 928 | "Can't attach same bus to different cards!\n"); | ||
| 929 | module_put(ci->owner); | ||
| 930 | kfree(cii); | ||
| 931 | soundbus_dev_put(dev); | ||
| 932 | module_put(THIS_MODULE); | ||
| 933 | return -EINVAL; | ||
| 934 | } | ||
| 935 | if ((err = | ||
| 936 | snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1))) { | ||
| 937 | module_put(ci->owner); | ||
| 938 | kfree(cii); | ||
| 939 | soundbus_dev_put(dev); | ||
| 940 | module_put(THIS_MODULE); | ||
| 941 | return err; | ||
| 942 | } | ||
| 943 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
| 944 | &i2sbus_playback_ops); | ||
| 945 | i2sdev->out.created = 1; | ||
| 946 | } | ||
| 947 | |||
| 948 | if (!i2sdev->in.created && in) { | ||
| 949 | if (dev->pcm->card != card) { | ||
| 950 | printk(KERN_ERR | ||
| 951 | "Can't attach same bus to different cards!\n"); | ||
| 952 | module_put(ci->owner); | ||
| 953 | kfree(cii); | ||
| 954 | soundbus_dev_put(dev); | ||
| 955 | module_put(THIS_MODULE); | ||
| 956 | return -EINVAL; | ||
| 957 | } | ||
| 958 | if ((err = | ||
| 959 | snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1))) { | ||
| 960 | module_put(ci->owner); | ||
| 961 | kfree(cii); | ||
| 962 | soundbus_dev_put(dev); | ||
| 963 | module_put(THIS_MODULE); | ||
| 964 | return err; | ||
| 965 | } | ||
| 966 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
| 967 | &i2sbus_record_ops); | ||
| 968 | i2sdev->in.created = 1; | ||
| 969 | } | ||
| 970 | |||
| 971 | /* so we have to register the pcm after adding any substream | ||
| 972 | * to it because alsa doesn't create the devices for the | ||
| 973 | * substreams when we add them later. | ||
| 974 | * Therefore, force in and out on both busses (above) and | ||
| 975 | * register the pcm now instead of just after creating it. | ||
| 976 | */ | ||
| 977 | err = snd_device_register(card, dev->pcm); | ||
| 978 | if (err) { | ||
| 979 | printk(KERN_ERR "i2sbus: error registering new pcm\n"); | ||
| 980 | module_put(ci->owner); | ||
| 981 | kfree(cii); | ||
| 982 | soundbus_dev_put(dev); | ||
| 983 | module_put(THIS_MODULE); | ||
| 984 | return err; | ||
| 985 | } | ||
| 986 | /* no errors any more, so let's add this to our list */ | ||
| 987 | list_add(&cii->list, &dev->codec_list); | ||
| 988 | |||
| 989 | dev->pcm->private_data = i2sdev; | ||
| 990 | dev->pcm->private_free = i2sbus_private_free; | ||
| 991 | |||
| 992 | /* well, we really should support scatter/gather DMA */ | ||
| 993 | snd_pcm_lib_preallocate_pages_for_all( | ||
| 994 | dev->pcm, SNDRV_DMA_TYPE_DEV, | ||
| 995 | snd_dma_pci_data(macio_get_pci_dev(i2sdev->macio)), | ||
| 996 | 64 * 1024, 64 * 1024); | ||
| 997 | |||
| 998 | return 0; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | void i2sbus_detach_codec(struct soundbus_dev *dev, void *data) | ||
| 1002 | { | ||
| 1003 | struct codec_info_item *cii = NULL, *i; | ||
| 1004 | |||
| 1005 | list_for_each_entry(i, &dev->codec_list, list) { | ||
| 1006 | if (i->codec_data == data) { | ||
| 1007 | cii = i; | ||
| 1008 | break; | ||
| 1009 | } | ||
| 1010 | } | ||
| 1011 | if (cii) { | ||
| 1012 | list_del(&cii->list); | ||
| 1013 | module_put(cii->codec->owner); | ||
| 1014 | kfree(cii); | ||
| 1015 | } | ||
| 1016 | /* no more codecs, but still a pcm? */ | ||
| 1017 | if (list_empty(&dev->codec_list) && dev->pcm) { | ||
| 1018 | /* the actual cleanup is done by the callback above! */ | ||
| 1019 | snd_device_free(dev->pcm->card, dev->pcm); | ||
| 1020 | } | ||
| 1021 | } | ||
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h new file mode 100644 index 000000000000..cfa5162e3b0f --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/i2sbus.h | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | /* | ||
| 2 | * i2sbus driver -- private definitions | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | #ifndef __I2SBUS_H | ||
| 9 | #define __I2SBUS_H | ||
| 10 | #include <asm/dbdma.h> | ||
| 11 | #include <linux/interrupt.h> | ||
| 12 | #include <sound/pcm.h> | ||
| 13 | #include <linux/spinlock.h> | ||
| 14 | #include <linux/mutex.h> | ||
| 15 | #include <asm/prom.h> | ||
| 16 | #include "i2sbus-interface.h" | ||
| 17 | #include "i2sbus-control.h" | ||
| 18 | #include "../soundbus.h" | ||
| 19 | |||
| 20 | struct i2sbus_control { | ||
| 21 | volatile struct i2s_control_regs __iomem *controlregs; | ||
| 22 | struct resource rsrc; | ||
| 23 | struct list_head list; | ||
| 24 | }; | ||
| 25 | |||
| 26 | #define MAX_DBDMA_COMMANDS 32 | ||
| 27 | |||
| 28 | struct dbdma_command_mem { | ||
| 29 | dma_addr_t bus_addr; | ||
| 30 | dma_addr_t bus_cmd_start; | ||
| 31 | struct dbdma_cmd *cmds; | ||
| 32 | void *space; | ||
| 33 | int size; | ||
| 34 | u32 running:1; | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct pcm_info { | ||
| 38 | u32 created:1, /* has this direction been created with alsa? */ | ||
| 39 | active:1; /* is this stream active? */ | ||
| 40 | /* runtime information */ | ||
| 41 | struct snd_pcm_substream *substream; | ||
| 42 | int current_period; | ||
| 43 | u32 frame_count; | ||
| 44 | struct dbdma_command_mem dbdma_ring; | ||
| 45 | volatile struct dbdma_regs __iomem *dbdma; | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct i2sbus_dev { | ||
| 49 | struct soundbus_dev sound; | ||
| 50 | struct macio_dev *macio; | ||
| 51 | struct i2sbus_control *control; | ||
| 52 | volatile struct i2s_interface_regs __iomem *intfregs; | ||
| 53 | |||
| 54 | struct resource resources[3]; | ||
| 55 | struct resource *allocated_resource[3]; | ||
| 56 | int interrupts[3]; | ||
| 57 | char rnames[3][32]; | ||
| 58 | |||
| 59 | /* info about currently active substreams */ | ||
| 60 | struct pcm_info out, in; | ||
| 61 | snd_pcm_format_t format; | ||
| 62 | unsigned int rate; | ||
| 63 | |||
| 64 | /* list for a single controller */ | ||
| 65 | struct list_head item; | ||
| 66 | /* number of bus on controller */ | ||
| 67 | int bus_number; | ||
| 68 | /* for use by control layer */ | ||
| 69 | struct pmf_function *enable, | ||
| 70 | *cell_enable, | ||
| 71 | *cell_disable, | ||
| 72 | *clock_enable, | ||
| 73 | *clock_disable; | ||
| 74 | |||
| 75 | /* locks */ | ||
| 76 | /* spinlock for low-level interrupt locking */ | ||
| 77 | spinlock_t low_lock; | ||
| 78 | /* mutex for high-level consistency */ | ||
| 79 | struct mutex lock; | ||
| 80 | }; | ||
| 81 | |||
| 82 | #define soundbus_dev_to_i2sbus_dev(sdev) \ | ||
| 83 | container_of(sdev, struct i2sbus_dev, sound) | ||
| 84 | |||
| 85 | /* pcm specific functions */ | ||
| 86 | extern int | ||
| 87 | i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | ||
| 88 | struct codec_info *ci, void *data); | ||
| 89 | extern void | ||
| 90 | i2sbus_detach_codec(struct soundbus_dev *dev, void *data); | ||
| 91 | extern irqreturn_t | ||
| 92 | i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs); | ||
| 93 | extern irqreturn_t | ||
| 94 | i2sbus_rx_intr(int irq, void *devid, struct pt_regs *regs); | ||
| 95 | |||
| 96 | /* control specific functions */ | ||
| 97 | extern int i2sbus_control_init(struct macio_dev* dev, | ||
| 98 | struct i2sbus_control **c); | ||
| 99 | extern void i2sbus_control_destroy(struct i2sbus_control *c); | ||
| 100 | extern int i2sbus_control_add_dev(struct i2sbus_control *c, | ||
| 101 | struct i2sbus_dev *i2sdev); | ||
| 102 | extern void i2sbus_control_remove_dev(struct i2sbus_control *c, | ||
| 103 | struct i2sbus_dev *i2sdev); | ||
| 104 | extern int i2sbus_control_enable(struct i2sbus_control *c, | ||
| 105 | struct i2sbus_dev *i2sdev); | ||
| 106 | extern int i2sbus_control_cell(struct i2sbus_control *c, | ||
| 107 | struct i2sbus_dev *i2sdev, | ||
| 108 | int enable); | ||
| 109 | extern int i2sbus_control_clock(struct i2sbus_control *c, | ||
| 110 | struct i2sbus_dev *i2sdev, | ||
| 111 | int enable); | ||
| 112 | #endif /* __I2SBUS_H */ | ||
diff --git a/sound/aoa/soundbus/soundbus.h b/sound/aoa/soundbus/soundbus.h new file mode 100644 index 000000000000..5c27297835d7 --- /dev/null +++ b/sound/aoa/soundbus/soundbus.h | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | /* | ||
| 2 | * soundbus generic definitions | ||
| 3 | * | ||
| 4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
| 5 | * | ||
| 6 | * GPL v2, can be found in COPYING. | ||
| 7 | */ | ||
| 8 | #ifndef __SOUNDBUS_H | ||
| 9 | #define __SOUNDBUS_H | ||
| 10 | |||
| 11 | #include <asm/of_device.h> | ||
| 12 | #include <sound/pcm.h> | ||
| 13 | #include <linux/list.h> | ||
| 14 | |||
| 15 | |||
| 16 | /* When switching from master to slave or the other way around, | ||
| 17 | * you don't want to have the codec chip acting as clock source | ||
| 18 | * while the bus still is. | ||
| 19 | * More importantly, while switch from slave to master, you need | ||
| 20 | * to turn off the chip's master function first, but then there's | ||
| 21 | * no clock for a while and other chips might reset, so we notify | ||
| 22 | * their drivers after having switched. | ||
| 23 | * The constants here are codec-point of view, so when we switch | ||
| 24 | * the soundbus to master we tell the codec we're going to switch | ||
| 25 | * and give it CLOCK_SWITCH_PREPARE_SLAVE! | ||
| 26 | */ | ||
| 27 | enum clock_switch { | ||
| 28 | CLOCK_SWITCH_PREPARE_SLAVE, | ||
| 29 | CLOCK_SWITCH_PREPARE_MASTER, | ||
| 30 | CLOCK_SWITCH_SLAVE, | ||
| 31 | CLOCK_SWITCH_MASTER, | ||
| 32 | CLOCK_SWITCH_NOTIFY, | ||
| 33 | }; | ||
| 34 | |||
| 35 | /* information on a transfer the codec can take */ | ||
| 36 | struct transfer_info { | ||
| 37 | u64 formats; /* SNDRV_PCM_FMTBIT_* */ | ||
| 38 | unsigned int rates; /* SNDRV_PCM_RATE_* */ | ||
| 39 | /* flags */ | ||
| 40 | u32 transfer_in:1, /* input = 1, output = 0 */ | ||
| 41 | must_be_clock_source:1; | ||
| 42 | /* for codecs to distinguish among their TIs */ | ||
| 43 | int tag; | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct codec_info_item { | ||
| 47 | struct codec_info *codec; | ||
| 48 | void *codec_data; | ||
| 49 | struct soundbus_dev *sdev; | ||
| 50 | /* internal, to be used by the soundbus provider */ | ||
| 51 | struct list_head list; | ||
| 52 | }; | ||
| 53 | |||
| 54 | /* for prepare, where the codecs need to know | ||
| 55 | * what we're going to drive the bus with */ | ||
| 56 | struct bus_info { | ||
| 57 | /* see below */ | ||
| 58 | int sysclock_factor; | ||
| 59 | int bus_factor; | ||
| 60 | }; | ||
| 61 | |||
| 62 | /* information on the codec itself, plus function pointers */ | ||
| 63 | struct codec_info { | ||
| 64 | /* the module this lives in */ | ||
| 65 | struct module *owner; | ||
| 66 | |||
| 67 | /* supported transfer possibilities, array terminated by | ||
| 68 | * formats or rates being 0. */ | ||
| 69 | struct transfer_info *transfers; | ||
| 70 | |||
| 71 | /* Master clock speed factor | ||
| 72 | * to be used (master clock speed = sysclock_factor * sampling freq) | ||
| 73 | * Unused if the soundbus provider has no such notion. | ||
| 74 | */ | ||
| 75 | int sysclock_factor; | ||
| 76 | |||
| 77 | /* Bus factor, bus clock speed = bus_factor * sampling freq) | ||
| 78 | * Unused if the soundbus provider has no such notion. | ||
| 79 | */ | ||
| 80 | int bus_factor; | ||
| 81 | |||
| 82 | /* operations */ | ||
| 83 | /* clock switching, see above */ | ||
| 84 | int (*switch_clock)(struct codec_info_item *cii, | ||
| 85 | enum clock_switch clock); | ||
| 86 | |||
| 87 | /* called for each transfer_info when the user | ||
| 88 | * opens the pcm device to determine what the | ||
| 89 | * hardware can support at this point in time. | ||
| 90 | * That can depend on other user-switchable controls. | ||
| 91 | * Return 1 if usable, 0 if not. | ||
| 92 | * out points to another instance of a transfer_info | ||
| 93 | * which is initialised to the values in *ti, and | ||
| 94 | * it's format and rate values can be modified by | ||
| 95 | * the callback if it is necessary to further restrict | ||
| 96 | * the formats that can be used at the moment, for | ||
| 97 | * example when one codec has multiple logical codec | ||
| 98 | * info structs for multiple inputs. | ||
| 99 | */ | ||
| 100 | int (*usable)(struct codec_info_item *cii, | ||
| 101 | struct transfer_info *ti, | ||
| 102 | struct transfer_info *out); | ||
| 103 | |||
| 104 | /* called when pcm stream is opened, probably not implemented | ||
| 105 | * most of the time since it isn't too useful */ | ||
| 106 | int (*open)(struct codec_info_item *cii, | ||
| 107 | struct snd_pcm_substream *substream); | ||
| 108 | |||
| 109 | /* called when the pcm stream is closed, at this point | ||
| 110 | * the user choices can all be unlocked (see below) */ | ||
| 111 | int (*close)(struct codec_info_item *cii, | ||
| 112 | struct snd_pcm_substream *substream); | ||
| 113 | |||
| 114 | /* if the codec must forbid some user choices because | ||
| 115 | * they are not valid with the substream/transfer info, | ||
| 116 | * it must do so here. Example: no digital output for | ||
| 117 | * incompatible framerate, say 8KHz, on Onyx. | ||
| 118 | * If the selected stuff in the substream is NOT | ||
| 119 | * compatible, you have to reject this call! */ | ||
| 120 | int (*prepare)(struct codec_info_item *cii, | ||
| 121 | struct bus_info *bi, | ||
| 122 | struct snd_pcm_substream *substream); | ||
| 123 | |||
| 124 | /* start() is called before data is pushed to the codec. | ||
| 125 | * Note that start() must be atomic! */ | ||
| 126 | int (*start)(struct codec_info_item *cii, | ||
| 127 | struct snd_pcm_substream *substream); | ||
| 128 | |||
| 129 | /* stop() is called after data is no longer pushed to the codec. | ||
| 130 | * Note that stop() must be atomic! */ | ||
| 131 | int (*stop)(struct codec_info_item *cii, | ||
| 132 | struct snd_pcm_substream *substream); | ||
| 133 | |||
| 134 | int (*suspend)(struct codec_info_item *cii, pm_message_t state); | ||
| 135 | int (*resume)(struct codec_info_item *cii); | ||
| 136 | }; | ||
| 137 | |||
| 138 | /* information on a soundbus device */ | ||
| 139 | struct soundbus_dev { | ||
| 140 | /* the bus it belongs to */ | ||
| 141 | struct list_head onbuslist; | ||
| 142 | |||
| 143 | /* the of device it represents */ | ||
| 144 | struct of_device ofdev; | ||
| 145 | |||
| 146 | /* what modules go by */ | ||
| 147 | char modalias[32]; | ||
| 148 | |||
| 149 | /* These fields must be before attach_codec can be called. | ||
| 150 | * They should be set by the owner of the alsa card object | ||
| 151 | * that is needed, and whoever sets them must make sure | ||
| 152 | * that they are unique within that alsa card object. */ | ||
| 153 | char *pcmname; | ||
| 154 | int pcmid; | ||
| 155 | |||
| 156 | /* this is assigned by the soundbus provider in attach_codec */ | ||
| 157 | struct snd_pcm *pcm; | ||
| 158 | |||
| 159 | /* operations */ | ||
| 160 | /* attach a codec to this soundbus, give the alsa | ||
| 161 | * card object the PCMs for this soundbus should be in. | ||
| 162 | * The 'data' pointer must be unique, it is used as the | ||
| 163 | * key for detach_codec(). */ | ||
| 164 | int (*attach_codec)(struct soundbus_dev *dev, struct snd_card *card, | ||
| 165 | struct codec_info *ci, void *data); | ||
| 166 | void (*detach_codec)(struct soundbus_dev *dev, void *data); | ||
| 167 | /* TODO: suspend/resume */ | ||
| 168 | |||
| 169 | /* private for the soundbus provider */ | ||
| 170 | struct list_head codec_list; | ||
| 171 | u32 have_out:1, have_in:1; | ||
| 172 | }; | ||
| 173 | #define to_soundbus_device(d) container_of(d, struct soundbus_dev, ofdev.dev) | ||
| 174 | #define of_to_soundbus_device(d) container_of(d, struct soundbus_dev, ofdev) | ||
| 175 | |||
| 176 | extern int soundbus_add_one(struct soundbus_dev *dev); | ||
| 177 | extern void soundbus_remove_one(struct soundbus_dev *dev); | ||
| 178 | |||
| 179 | extern struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev); | ||
| 180 | extern void soundbus_dev_put(struct soundbus_dev *dev); | ||
| 181 | |||
| 182 | struct soundbus_driver { | ||
| 183 | char *name; | ||
| 184 | struct module *owner; | ||
| 185 | |||
| 186 | /* we don't implement any matching at all */ | ||
| 187 | |||
| 188 | int (*probe)(struct soundbus_dev* dev); | ||
| 189 | int (*remove)(struct soundbus_dev* dev); | ||
| 190 | |||
| 191 | int (*suspend)(struct soundbus_dev* dev, pm_message_t state); | ||
| 192 | int (*resume)(struct soundbus_dev* dev); | ||
| 193 | int (*shutdown)(struct soundbus_dev* dev); | ||
| 194 | |||
| 195 | struct device_driver driver; | ||
| 196 | }; | ||
| 197 | #define to_soundbus_driver(drv) container_of(drv,struct soundbus_driver, driver) | ||
| 198 | |||
| 199 | extern int soundbus_register_driver(struct soundbus_driver *drv); | ||
| 200 | extern void soundbus_unregister_driver(struct soundbus_driver *drv); | ||
| 201 | |||
| 202 | #endif /* __SOUNDBUS_H */ | ||
diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c new file mode 100644 index 000000000000..d31f8146952a --- /dev/null +++ b/sound/aoa/soundbus/sysfs.c | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #include <linux/config.h> | ||
| 2 | #include <linux/kernel.h> | ||
| 3 | #include <linux/stat.h> | ||
| 4 | /* FIX UP */ | ||
| 5 | #include "soundbus.h" | ||
| 6 | |||
| 7 | #define soundbus_config_of_attr(field, format_string) \ | ||
| 8 | static ssize_t \ | ||
| 9 | field##_show (struct device *dev, struct device_attribute *attr, \ | ||
| 10 | char *buf) \ | ||
| 11 | { \ | ||
| 12 | struct soundbus_dev *mdev = to_soundbus_device (dev); \ | ||
| 13 | return sprintf (buf, format_string, mdev->ofdev.node->field); \ | ||
| 14 | } | ||
| 15 | |||
| 16 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | ||
| 17 | char *buf) | ||
| 18 | { | ||
| 19 | struct soundbus_dev *sdev = to_soundbus_device(dev); | ||
| 20 | struct of_device *of = &sdev->ofdev; | ||
| 21 | int length; | ||
| 22 | |||
| 23 | if (*sdev->modalias) { | ||
| 24 | strlcpy(buf, sdev->modalias, sizeof(sdev->modalias) + 1); | ||
| 25 | strcat(buf, "\n"); | ||
| 26 | length = strlen(buf); | ||
| 27 | } else { | ||
| 28 | length = sprintf(buf, "of:N%sT%s\n", | ||
| 29 | of->node->name, of->node->type); | ||
| 30 | } | ||
| 31 | |||
| 32 | return length; | ||
| 33 | } | ||
| 34 | |||
| 35 | soundbus_config_of_attr (name, "%s\n"); | ||
| 36 | soundbus_config_of_attr (type, "%s\n"); | ||
| 37 | |||
| 38 | struct device_attribute soundbus_dev_attrs[] = { | ||
| 39 | __ATTR_RO(name), | ||
| 40 | __ATTR_RO(type), | ||
| 41 | __ATTR_RO(modalias), | ||
| 42 | __ATTR_NULL | ||
| 43 | }; | ||
diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c index 13057d92f08a..b88fb0c5a68a 100644 --- a/sound/arm/sa11xx-uda1341.c +++ b/sound/arm/sa11xx-uda1341.c | |||
| @@ -112,7 +112,7 @@ MODULE_LICENSE("GPL"); | |||
| 112 | MODULE_DESCRIPTION("SA1100/SA1111 + UDA1341TS driver for ALSA"); | 112 | MODULE_DESCRIPTION("SA1100/SA1111 + UDA1341TS driver for ALSA"); |
| 113 | MODULE_SUPPORTED_DEVICE("{{UDA1341,iPAQ H3600 UDA1341TS}}"); | 113 | MODULE_SUPPORTED_DEVICE("{{UDA1341,iPAQ H3600 UDA1341TS}}"); |
| 114 | 114 | ||
| 115 | static char *id = NULL; /* ID for this card */ | 115 | static char *id; /* ID for this card */ |
| 116 | 116 | ||
| 117 | module_param(id, charp, 0444); | 117 | module_param(id, charp, 0444); |
| 118 | MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard."); | 118 | MODULE_PARM_DESC(id, "ID string for SA1100/SA1111 + UDA1341TS soundcard."); |
| @@ -984,11 +984,15 @@ static int __init sa11xx_uda1341_init(void) | |||
| 984 | if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0) | 984 | if ((err = platform_driver_register(&sa11xx_uda1341_driver)) < 0) |
| 985 | return err; | 985 | return err; |
| 986 | device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0); | 986 | device = platform_device_register_simple(SA11XX_UDA1341_DRIVER, -1, NULL, 0); |
| 987 | if (IS_ERR(device)) { | 987 | if (!IS_ERR(device)) { |
| 988 | platform_driver_unregister(&sa11xx_uda1341_driver); | 988 | if (platform_get_drvdata(device)) |
| 989 | return PTR_ERR(device); | 989 | return 0; |
| 990 | } | 990 | platform_device_unregister(device); |
| 991 | return 0; | 991 | err = -ENODEV |
| 992 | } else | ||
| 993 | err = PTR_ERR(device); | ||
| 994 | platform_driver_unregister(&sa11xx_uda1341_driver); | ||
| 995 | return err; | ||
| 992 | } | 996 | } |
| 993 | 997 | ||
| 994 | static void __exit sa11xx_uda1341_exit(void) | 998 | static void __exit sa11xx_uda1341_exit(void) |
diff --git a/sound/core/control.c b/sound/core/control.c index 22565c9b9603..bb397eaa7187 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
| @@ -176,6 +176,8 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, | |||
| 176 | read_unlock(&card->ctl_files_rwlock); | 176 | read_unlock(&card->ctl_files_rwlock); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | EXPORT_SYMBOL(snd_ctl_notify); | ||
| 180 | |||
| 179 | /** | 181 | /** |
| 180 | * snd_ctl_new - create a control instance from the template | 182 | * snd_ctl_new - create a control instance from the template |
| 181 | * @control: the control template | 183 | * @control: the control template |
| @@ -204,6 +206,8 @@ struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, unsigned int acce | |||
| 204 | return kctl; | 206 | return kctl; |
| 205 | } | 207 | } |
| 206 | 208 | ||
| 209 | EXPORT_SYMBOL(snd_ctl_new); | ||
| 210 | |||
| 207 | /** | 211 | /** |
| 208 | * snd_ctl_new1 - create a control instance from the template | 212 | * snd_ctl_new1 - create a control instance from the template |
| 209 | * @ncontrol: the initialization record | 213 | * @ncontrol: the initialization record |
| @@ -242,6 +246,8 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, | |||
| 242 | return snd_ctl_new(&kctl, access); | 246 | return snd_ctl_new(&kctl, access); |
| 243 | } | 247 | } |
| 244 | 248 | ||
| 249 | EXPORT_SYMBOL(snd_ctl_new1); | ||
| 250 | |||
| 245 | /** | 251 | /** |
| 246 | * snd_ctl_free_one - release the control instance | 252 | * snd_ctl_free_one - release the control instance |
| 247 | * @kcontrol: the control instance | 253 | * @kcontrol: the control instance |
| @@ -259,6 +265,8 @@ void snd_ctl_free_one(struct snd_kcontrol *kcontrol) | |||
| 259 | } | 265 | } |
| 260 | } | 266 | } |
| 261 | 267 | ||
| 268 | EXPORT_SYMBOL(snd_ctl_free_one); | ||
| 269 | |||
| 262 | static unsigned int snd_ctl_hole_check(struct snd_card *card, | 270 | static unsigned int snd_ctl_hole_check(struct snd_card *card, |
| 263 | unsigned int count) | 271 | unsigned int count) |
| 264 | { | 272 | { |
| @@ -347,6 +355,8 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
| 347 | return err; | 355 | return err; |
| 348 | } | 356 | } |
| 349 | 357 | ||
| 358 | EXPORT_SYMBOL(snd_ctl_add); | ||
| 359 | |||
| 350 | /** | 360 | /** |
| 351 | * snd_ctl_remove - remove the control from the card and release it | 361 | * snd_ctl_remove - remove the control from the card and release it |
| 352 | * @card: the card instance | 362 | * @card: the card instance |
| @@ -373,6 +383,8 @@ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
| 373 | return 0; | 383 | return 0; |
| 374 | } | 384 | } |
| 375 | 385 | ||
| 386 | EXPORT_SYMBOL(snd_ctl_remove); | ||
| 387 | |||
| 376 | /** | 388 | /** |
| 377 | * snd_ctl_remove_id - remove the control of the given id and release it | 389 | * snd_ctl_remove_id - remove the control of the given id and release it |
| 378 | * @card: the card instance | 390 | * @card: the card instance |
| @@ -399,6 +411,8 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) | |||
| 399 | return ret; | 411 | return ret; |
| 400 | } | 412 | } |
| 401 | 413 | ||
| 414 | EXPORT_SYMBOL(snd_ctl_remove_id); | ||
| 415 | |||
| 402 | /** | 416 | /** |
| 403 | * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it | 417 | * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it |
| 404 | * @file: active control handle | 418 | * @file: active control handle |
| @@ -461,6 +475,8 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, | |||
| 461 | return 0; | 475 | return 0; |
| 462 | } | 476 | } |
| 463 | 477 | ||
| 478 | EXPORT_SYMBOL(snd_ctl_rename_id); | ||
| 479 | |||
| 464 | /** | 480 | /** |
| 465 | * snd_ctl_find_numid - find the control instance with the given number-id | 481 | * snd_ctl_find_numid - find the control instance with the given number-id |
| 466 | * @card: the card instance | 482 | * @card: the card instance |
| @@ -487,6 +503,8 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numi | |||
| 487 | return NULL; | 503 | return NULL; |
| 488 | } | 504 | } |
| 489 | 505 | ||
| 506 | EXPORT_SYMBOL(snd_ctl_find_numid); | ||
| 507 | |||
| 490 | /** | 508 | /** |
| 491 | * snd_ctl_find_id - find the control instance with the given id | 509 | * snd_ctl_find_id - find the control instance with the given id |
| 492 | * @card: the card instance | 510 | * @card: the card instance |
| @@ -527,6 +545,8 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, | |||
| 527 | return NULL; | 545 | return NULL; |
| 528 | } | 546 | } |
| 529 | 547 | ||
| 548 | EXPORT_SYMBOL(snd_ctl_find_id); | ||
| 549 | |||
| 530 | static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, | 550 | static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, |
| 531 | unsigned int cmd, void __user *arg) | 551 | unsigned int cmd, void __user *arg) |
| 532 | { | 552 | { |
| @@ -704,6 +724,8 @@ int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control) | |||
| 704 | return result; | 724 | return result; |
| 705 | } | 725 | } |
| 706 | 726 | ||
| 727 | EXPORT_SYMBOL(snd_ctl_elem_read); | ||
| 728 | |||
| 707 | static int snd_ctl_elem_read_user(struct snd_card *card, | 729 | static int snd_ctl_elem_read_user(struct snd_card *card, |
| 708 | struct snd_ctl_elem_value __user *_control) | 730 | struct snd_ctl_elem_value __user *_control) |
| 709 | { | 731 | { |
| @@ -767,6 +789,8 @@ int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, | |||
| 767 | return result; | 789 | return result; |
| 768 | } | 790 | } |
| 769 | 791 | ||
| 792 | EXPORT_SYMBOL(snd_ctl_elem_write); | ||
| 793 | |||
| 770 | static int snd_ctl_elem_write_user(struct snd_ctl_file *file, | 794 | static int snd_ctl_elem_write_user(struct snd_ctl_file *file, |
| 771 | struct snd_ctl_elem_value __user *_control) | 795 | struct snd_ctl_elem_value __user *_control) |
| 772 | { | 796 | { |
| @@ -1199,11 +1223,15 @@ int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn) | |||
| 1199 | return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls); | 1223 | return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls); |
| 1200 | } | 1224 | } |
| 1201 | 1225 | ||
| 1226 | EXPORT_SYMBOL(snd_ctl_register_ioctl); | ||
| 1227 | |||
| 1202 | #ifdef CONFIG_COMPAT | 1228 | #ifdef CONFIG_COMPAT |
| 1203 | int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn) | 1229 | int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn) |
| 1204 | { | 1230 | { |
| 1205 | return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls); | 1231 | return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls); |
| 1206 | } | 1232 | } |
| 1233 | |||
| 1234 | EXPORT_SYMBOL(snd_ctl_register_ioctl_compat); | ||
| 1207 | #endif | 1235 | #endif |
| 1208 | 1236 | ||
| 1209 | /* | 1237 | /* |
| @@ -1236,12 +1264,15 @@ int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn) | |||
| 1236 | return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls); | 1264 | return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls); |
| 1237 | } | 1265 | } |
| 1238 | 1266 | ||
| 1267 | EXPORT_SYMBOL(snd_ctl_unregister_ioctl); | ||
| 1268 | |||
| 1239 | #ifdef CONFIG_COMPAT | 1269 | #ifdef CONFIG_COMPAT |
| 1240 | int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn) | 1270 | int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn) |
| 1241 | { | 1271 | { |
| 1242 | return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls); | 1272 | return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls); |
| 1243 | } | 1273 | } |
| 1244 | 1274 | ||
| 1275 | EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat); | ||
| 1245 | #endif | 1276 | #endif |
| 1246 | 1277 | ||
| 1247 | static int snd_ctl_fasync(int fd, struct file * file, int on) | 1278 | static int snd_ctl_fasync(int fd, struct file * file, int on) |
diff --git a/sound/core/device.c b/sound/core/device.c index b1cf6ec56784..6ce4da4a1081 100644 --- a/sound/core/device.c +++ b/sound/core/device.c | |||
| @@ -63,6 +63,8 @@ int snd_device_new(struct snd_card *card, snd_device_type_t type, | |||
| 63 | return 0; | 63 | return 0; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | EXPORT_SYMBOL(snd_device_new); | ||
| 67 | |||
| 66 | /** | 68 | /** |
| 67 | * snd_device_free - release the device from the card | 69 | * snd_device_free - release the device from the card |
| 68 | * @card: the card instance | 70 | * @card: the card instance |
| @@ -107,6 +109,8 @@ int snd_device_free(struct snd_card *card, void *device_data) | |||
| 107 | return -ENXIO; | 109 | return -ENXIO; |
| 108 | } | 110 | } |
| 109 | 111 | ||
| 112 | EXPORT_SYMBOL(snd_device_free); | ||
| 113 | |||
| 110 | /** | 114 | /** |
| 111 | * snd_device_disconnect - disconnect the device | 115 | * snd_device_disconnect - disconnect the device |
| 112 | * @card: the card instance | 116 | * @card: the card instance |
| @@ -182,6 +186,8 @@ int snd_device_register(struct snd_card *card, void *device_data) | |||
| 182 | return -ENXIO; | 186 | return -ENXIO; |
| 183 | } | 187 | } |
| 184 | 188 | ||
| 189 | EXPORT_SYMBOL(snd_device_register); | ||
| 190 | |||
| 185 | /* | 191 | /* |
| 186 | * register all the devices on the card. | 192 | * register all the devices on the card. |
| 187 | * called from init.c | 193 | * called from init.c |
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 2524e66eccdd..8bd0dcc93eba 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c | |||
| @@ -486,7 +486,6 @@ static void __init snd_hwdep_proc_init(void) | |||
| 486 | struct snd_info_entry *entry; | 486 | struct snd_info_entry *entry; |
| 487 | 487 | ||
| 488 | if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { | 488 | if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { |
| 489 | entry->c.text.read_size = PAGE_SIZE; | ||
| 490 | entry->c.text.read = snd_hwdep_proc_read; | 489 | entry->c.text.read = snd_hwdep_proc_read; |
| 491 | if (snd_info_register(entry) < 0) { | 490 | if (snd_info_register(entry) < 0) { |
| 492 | snd_info_free_entry(entry); | 491 | snd_info_free_entry(entry); |
diff --git a/sound/core/info.c b/sound/core/info.c index 2582b74d3199..10c1772bf3ea 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | 21 | ||
| 22 | #include <sound/driver.h> | 22 | #include <sound/driver.h> |
| 23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
| 24 | #include <linux/vmalloc.h> | ||
| 25 | #include <linux/time.h> | 24 | #include <linux/time.h> |
| 26 | #include <linux/smp_lock.h> | 25 | #include <linux/smp_lock.h> |
| 27 | #include <linux/string.h> | 26 | #include <linux/string.h> |
| @@ -82,6 +81,24 @@ static int snd_info_version_init(void); | |||
| 82 | static int snd_info_version_done(void); | 81 | static int snd_info_version_done(void); |
| 83 | 82 | ||
| 84 | 83 | ||
| 84 | /* resize the proc r/w buffer */ | ||
| 85 | static int resize_info_buffer(struct snd_info_buffer *buffer, | ||
| 86 | unsigned int nsize) | ||
| 87 | { | ||
| 88 | char *nbuf; | ||
| 89 | |||
| 90 | nsize = PAGE_ALIGN(nsize); | ||
| 91 | nbuf = kmalloc(nsize, GFP_KERNEL); | ||
| 92 | if (! nbuf) | ||
| 93 | return -ENOMEM; | ||
| 94 | |||
| 95 | memcpy(nbuf, buffer->buffer, buffer->len); | ||
| 96 | kfree(buffer->buffer); | ||
| 97 | buffer->buffer = nbuf; | ||
| 98 | buffer->len = nsize; | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 85 | /** | 102 | /** |
| 86 | * snd_iprintf - printf on the procfs buffer | 103 | * snd_iprintf - printf on the procfs buffer |
| 87 | * @buffer: the procfs buffer | 104 | * @buffer: the procfs buffer |
| @@ -95,30 +112,43 @@ int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...) | |||
| 95 | { | 112 | { |
| 96 | va_list args; | 113 | va_list args; |
| 97 | int len, res; | 114 | int len, res; |
| 115 | int err = 0; | ||
| 98 | 116 | ||
| 117 | might_sleep(); | ||
| 99 | if (buffer->stop || buffer->error) | 118 | if (buffer->stop || buffer->error) |
| 100 | return 0; | 119 | return 0; |
| 101 | len = buffer->len - buffer->size; | 120 | len = buffer->len - buffer->size; |
| 102 | va_start(args, fmt); | 121 | va_start(args, fmt); |
| 103 | res = vsnprintf(buffer->curr, len, fmt, args); | 122 | for (;;) { |
| 104 | va_end(args); | 123 | res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, args); |
| 105 | if (res >= len) { | 124 | if (res < len) |
| 106 | buffer->stop = 1; | 125 | break; |
| 107 | return 0; | 126 | err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE); |
| 127 | if (err < 0) | ||
| 128 | break; | ||
| 129 | len = buffer->len - buffer->size; | ||
| 108 | } | 130 | } |
| 131 | va_end(args); | ||
| 132 | |||
| 133 | if (err < 0) | ||
| 134 | return err; | ||
| 109 | buffer->curr += res; | 135 | buffer->curr += res; |
| 110 | buffer->size += res; | 136 | buffer->size += res; |
| 111 | return res; | 137 | return res; |
| 112 | } | 138 | } |
| 113 | 139 | ||
| 140 | EXPORT_SYMBOL(snd_iprintf); | ||
| 141 | |||
| 114 | /* | 142 | /* |
| 115 | 143 | ||
| 116 | */ | 144 | */ |
| 117 | 145 | ||
| 118 | static struct proc_dir_entry *snd_proc_root = NULL; | 146 | static struct proc_dir_entry *snd_proc_root; |
| 119 | struct snd_info_entry *snd_seq_root = NULL; | 147 | struct snd_info_entry *snd_seq_root; |
| 148 | EXPORT_SYMBOL(snd_seq_root); | ||
| 149 | |||
| 120 | #ifdef CONFIG_SND_OSSEMUL | 150 | #ifdef CONFIG_SND_OSSEMUL |
| 121 | struct snd_info_entry *snd_oss_root = NULL; | 151 | struct snd_info_entry *snd_oss_root; |
| 122 | #endif | 152 | #endif |
| 123 | 153 | ||
| 124 | static inline void snd_info_entry_prepare(struct proc_dir_entry *de) | 154 | static inline void snd_info_entry_prepare(struct proc_dir_entry *de) |
| @@ -221,7 +251,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer | |||
| 221 | struct snd_info_private_data *data; | 251 | struct snd_info_private_data *data; |
| 222 | struct snd_info_entry *entry; | 252 | struct snd_info_entry *entry; |
| 223 | struct snd_info_buffer *buf; | 253 | struct snd_info_buffer *buf; |
| 224 | size_t size = 0; | 254 | ssize_t size = 0; |
| 225 | loff_t pos; | 255 | loff_t pos; |
| 226 | 256 | ||
| 227 | data = file->private_data; | 257 | data = file->private_data; |
| @@ -237,14 +267,20 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer | |||
| 237 | buf = data->wbuffer; | 267 | buf = data->wbuffer; |
| 238 | if (buf == NULL) | 268 | if (buf == NULL) |
| 239 | return -EIO; | 269 | return -EIO; |
| 240 | if (pos >= buf->len) | 270 | mutex_lock(&entry->access); |
| 241 | return -ENOMEM; | 271 | if (pos + count >= buf->len) { |
| 242 | size = buf->len - pos; | 272 | if (resize_info_buffer(buf, pos + count)) { |
| 243 | size = min(count, size); | 273 | mutex_unlock(&entry->access); |
| 244 | if (copy_from_user(buf->buffer + pos, buffer, size)) | 274 | return -ENOMEM; |
| 275 | } | ||
| 276 | } | ||
| 277 | if (copy_from_user(buf->buffer + pos, buffer, count)) { | ||
| 278 | mutex_unlock(&entry->access); | ||
| 245 | return -EFAULT; | 279 | return -EFAULT; |
| 246 | if ((long)buf->size < pos + size) | 280 | } |
| 247 | buf->size = pos + size; | 281 | buf->size = pos + count; |
| 282 | mutex_unlock(&entry->access); | ||
| 283 | size = count; | ||
| 248 | break; | 284 | break; |
| 249 | case SNDRV_INFO_CONTENT_DATA: | 285 | case SNDRV_INFO_CONTENT_DATA: |
| 250 | if (entry->c.ops->write) | 286 | if (entry->c.ops->write) |
| @@ -279,18 +315,14 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) | |||
| 279 | } | 315 | } |
| 280 | mode = file->f_flags & O_ACCMODE; | 316 | mode = file->f_flags & O_ACCMODE; |
| 281 | if (mode == O_RDONLY || mode == O_RDWR) { | 317 | if (mode == O_RDONLY || mode == O_RDWR) { |
| 282 | if ((entry->content == SNDRV_INFO_CONTENT_TEXT && | 318 | if ((entry->content == SNDRV_INFO_CONTENT_DATA && |
| 283 | !entry->c.text.read_size) || | ||
| 284 | (entry->content == SNDRV_INFO_CONTENT_DATA && | ||
| 285 | entry->c.ops->read == NULL)) { | 319 | entry->c.ops->read == NULL)) { |
| 286 | err = -ENODEV; | 320 | err = -ENODEV; |
| 287 | goto __error; | 321 | goto __error; |
| 288 | } | 322 | } |
| 289 | } | 323 | } |
| 290 | if (mode == O_WRONLY || mode == O_RDWR) { | 324 | if (mode == O_WRONLY || mode == O_RDWR) { |
| 291 | if ((entry->content == SNDRV_INFO_CONTENT_TEXT && | 325 | if ((entry->content == SNDRV_INFO_CONTENT_DATA && |
| 292 | !entry->c.text.write_size) || | ||
| 293 | (entry->content == SNDRV_INFO_CONTENT_DATA && | ||
| 294 | entry->c.ops->write == NULL)) { | 326 | entry->c.ops->write == NULL)) { |
| 295 | err = -ENODEV; | 327 | err = -ENODEV; |
| 296 | goto __error; | 328 | goto __error; |
| @@ -306,49 +338,23 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) | |||
| 306 | case SNDRV_INFO_CONTENT_TEXT: | 338 | case SNDRV_INFO_CONTENT_TEXT: |
| 307 | if (mode == O_RDONLY || mode == O_RDWR) { | 339 | if (mode == O_RDONLY || mode == O_RDWR) { |
| 308 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | 340 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); |
| 309 | if (buffer == NULL) { | 341 | if (buffer == NULL) |
| 310 | kfree(data); | 342 | goto __nomem; |
| 311 | err = -ENOMEM; | ||
| 312 | goto __error; | ||
| 313 | } | ||
| 314 | buffer->len = (entry->c.text.read_size + | ||
| 315 | (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); | ||
| 316 | buffer->buffer = vmalloc(buffer->len); | ||
| 317 | if (buffer->buffer == NULL) { | ||
| 318 | kfree(buffer); | ||
| 319 | kfree(data); | ||
| 320 | err = -ENOMEM; | ||
| 321 | goto __error; | ||
| 322 | } | ||
| 323 | buffer->curr = buffer->buffer; | ||
| 324 | data->rbuffer = buffer; | 343 | data->rbuffer = buffer; |
| 344 | buffer->len = PAGE_SIZE; | ||
| 345 | buffer->buffer = kmalloc(buffer->len, GFP_KERNEL); | ||
| 346 | if (buffer->buffer == NULL) | ||
| 347 | goto __nomem; | ||
| 325 | } | 348 | } |
| 326 | if (mode == O_WRONLY || mode == O_RDWR) { | 349 | if (mode == O_WRONLY || mode == O_RDWR) { |
| 327 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | 350 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); |
| 328 | if (buffer == NULL) { | 351 | if (buffer == NULL) |
| 329 | if (mode == O_RDWR) { | 352 | goto __nomem; |
| 330 | vfree(data->rbuffer->buffer); | ||
| 331 | kfree(data->rbuffer); | ||
| 332 | } | ||
| 333 | kfree(data); | ||
| 334 | err = -ENOMEM; | ||
| 335 | goto __error; | ||
| 336 | } | ||
| 337 | buffer->len = (entry->c.text.write_size + | ||
| 338 | (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); | ||
| 339 | buffer->buffer = vmalloc(buffer->len); | ||
| 340 | if (buffer->buffer == NULL) { | ||
| 341 | if (mode == O_RDWR) { | ||
| 342 | vfree(data->rbuffer->buffer); | ||
| 343 | kfree(data->rbuffer); | ||
| 344 | } | ||
| 345 | kfree(buffer); | ||
| 346 | kfree(data); | ||
| 347 | err = -ENOMEM; | ||
| 348 | goto __error; | ||
| 349 | } | ||
| 350 | buffer->curr = buffer->buffer; | ||
| 351 | data->wbuffer = buffer; | 353 | data->wbuffer = buffer; |
| 354 | buffer->len = PAGE_SIZE; | ||
| 355 | buffer->buffer = kmalloc(buffer->len, GFP_KERNEL); | ||
| 356 | if (buffer->buffer == NULL) | ||
| 357 | goto __nomem; | ||
| 352 | } | 358 | } |
| 353 | break; | 359 | break; |
| 354 | case SNDRV_INFO_CONTENT_DATA: /* data */ | 360 | case SNDRV_INFO_CONTENT_DATA: /* data */ |
| @@ -373,6 +379,17 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) | |||
| 373 | } | 379 | } |
| 374 | return 0; | 380 | return 0; |
| 375 | 381 | ||
| 382 | __nomem: | ||
| 383 | if (data->rbuffer) { | ||
| 384 | kfree(data->rbuffer->buffer); | ||
| 385 | kfree(data->rbuffer); | ||
| 386 | } | ||
| 387 | if (data->wbuffer) { | ||
| 388 | kfree(data->wbuffer->buffer); | ||
| 389 | kfree(data->wbuffer); | ||
| 390 | } | ||
| 391 | kfree(data); | ||
| 392 | err = -ENOMEM; | ||
| 376 | __error: | 393 | __error: |
| 377 | module_put(entry->module); | 394 | module_put(entry->module); |
| 378 | __error1: | 395 | __error1: |
| @@ -391,11 +408,11 @@ static int snd_info_entry_release(struct inode *inode, struct file *file) | |||
| 391 | entry = data->entry; | 408 | entry = data->entry; |
| 392 | switch (entry->content) { | 409 | switch (entry->content) { |
| 393 | case SNDRV_INFO_CONTENT_TEXT: | 410 | case SNDRV_INFO_CONTENT_TEXT: |
| 394 | if (mode == O_RDONLY || mode == O_RDWR) { | 411 | if (data->rbuffer) { |
| 395 | vfree(data->rbuffer->buffer); | 412 | kfree(data->rbuffer->buffer); |
| 396 | kfree(data->rbuffer); | 413 | kfree(data->rbuffer); |
| 397 | } | 414 | } |
| 398 | if (mode == O_WRONLY || mode == O_RDWR) { | 415 | if (data->wbuffer) { |
| 399 | if (entry->c.text.write) { | 416 | if (entry->c.text.write) { |
| 400 | entry->c.text.write(entry, data->wbuffer); | 417 | entry->c.text.write(entry, data->wbuffer); |
| 401 | if (data->wbuffer->error) { | 418 | if (data->wbuffer->error) { |
| @@ -404,7 +421,7 @@ static int snd_info_entry_release(struct inode *inode, struct file *file) | |||
| 404 | data->wbuffer->error); | 421 | data->wbuffer->error); |
| 405 | } | 422 | } |
| 406 | } | 423 | } |
| 407 | vfree(data->wbuffer->buffer); | 424 | kfree(data->wbuffer->buffer); |
| 408 | kfree(data->wbuffer); | 425 | kfree(data->wbuffer); |
| 409 | } | 426 | } |
| 410 | break; | 427 | break; |
| @@ -664,29 +681,29 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) | |||
| 664 | if (len <= 0 || buffer->stop || buffer->error) | 681 | if (len <= 0 || buffer->stop || buffer->error) |
| 665 | return 1; | 682 | return 1; |
| 666 | while (--len > 0) { | 683 | while (--len > 0) { |
| 667 | c = *buffer->curr++; | 684 | c = buffer->buffer[buffer->curr++]; |
| 668 | if (c == '\n') { | 685 | if (c == '\n') { |
| 669 | if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { | 686 | if (buffer->curr >= buffer->size) |
| 670 | buffer->stop = 1; | 687 | buffer->stop = 1; |
| 671 | } | ||
| 672 | break; | 688 | break; |
| 673 | } | 689 | } |
| 674 | *line++ = c; | 690 | *line++ = c; |
| 675 | if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { | 691 | if (buffer->curr >= buffer->size) { |
| 676 | buffer->stop = 1; | 692 | buffer->stop = 1; |
| 677 | break; | 693 | break; |
| 678 | } | 694 | } |
| 679 | } | 695 | } |
| 680 | while (c != '\n' && !buffer->stop) { | 696 | while (c != '\n' && !buffer->stop) { |
| 681 | c = *buffer->curr++; | 697 | c = buffer->buffer[buffer->curr++]; |
| 682 | if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { | 698 | if (buffer->curr >= buffer->size) |
| 683 | buffer->stop = 1; | 699 | buffer->stop = 1; |
| 684 | } | ||
| 685 | } | 700 | } |
| 686 | *line = '\0'; | 701 | *line = '\0'; |
| 687 | return 0; | 702 | return 0; |
| 688 | } | 703 | } |
| 689 | 704 | ||
| 705 | EXPORT_SYMBOL(snd_info_get_line); | ||
| 706 | |||
| 690 | /** | 707 | /** |
| 691 | * snd_info_get_str - parse a string token | 708 | * snd_info_get_str - parse a string token |
| 692 | * @dest: the buffer to store the string token | 709 | * @dest: the buffer to store the string token |
| @@ -723,6 +740,8 @@ char *snd_info_get_str(char *dest, char *src, int len) | |||
| 723 | return src; | 740 | return src; |
| 724 | } | 741 | } |
| 725 | 742 | ||
| 743 | EXPORT_SYMBOL(snd_info_get_str); | ||
| 744 | |||
| 726 | /** | 745 | /** |
| 727 | * snd_info_create_entry - create an info entry | 746 | * snd_info_create_entry - create an info entry |
| 728 | * @name: the proc file name | 747 | * @name: the proc file name |
| @@ -774,6 +793,8 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module, | |||
| 774 | return entry; | 793 | return entry; |
| 775 | } | 794 | } |
| 776 | 795 | ||
| 796 | EXPORT_SYMBOL(snd_info_create_module_entry); | ||
| 797 | |||
| 777 | /** | 798 | /** |
| 778 | * snd_info_create_card_entry - create an info entry for the given card | 799 | * snd_info_create_card_entry - create an info entry for the given card |
| 779 | * @card: the card instance | 800 | * @card: the card instance |
| @@ -797,6 +818,8 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, | |||
| 797 | return entry; | 818 | return entry; |
| 798 | } | 819 | } |
| 799 | 820 | ||
| 821 | EXPORT_SYMBOL(snd_info_create_card_entry); | ||
| 822 | |||
| 800 | static int snd_info_dev_free_entry(struct snd_device *device) | 823 | static int snd_info_dev_free_entry(struct snd_device *device) |
| 801 | { | 824 | { |
| 802 | struct snd_info_entry *entry = device->device_data; | 825 | struct snd_info_entry *entry = device->device_data; |
| @@ -867,6 +890,8 @@ int snd_card_proc_new(struct snd_card *card, const char *name, | |||
| 867 | return 0; | 890 | return 0; |
| 868 | } | 891 | } |
| 869 | 892 | ||
| 893 | EXPORT_SYMBOL(snd_card_proc_new); | ||
| 894 | |||
| 870 | /** | 895 | /** |
| 871 | * snd_info_free_entry - release the info entry | 896 | * snd_info_free_entry - release the info entry |
| 872 | * @entry: the info entry | 897 | * @entry: the info entry |
| @@ -883,6 +908,8 @@ void snd_info_free_entry(struct snd_info_entry * entry) | |||
| 883 | kfree(entry); | 908 | kfree(entry); |
| 884 | } | 909 | } |
| 885 | 910 | ||
| 911 | EXPORT_SYMBOL(snd_info_free_entry); | ||
| 912 | |||
| 886 | /** | 913 | /** |
| 887 | * snd_info_register - register the info entry | 914 | * snd_info_register - register the info entry |
| 888 | * @entry: the info entry | 915 | * @entry: the info entry |
| @@ -913,6 +940,8 @@ int snd_info_register(struct snd_info_entry * entry) | |||
| 913 | return 0; | 940 | return 0; |
| 914 | } | 941 | } |
| 915 | 942 | ||
| 943 | EXPORT_SYMBOL(snd_info_register); | ||
| 944 | |||
| 916 | /** | 945 | /** |
| 917 | * snd_info_unregister - de-register the info entry | 946 | * snd_info_unregister - de-register the info entry |
| 918 | * @entry: the info entry | 947 | * @entry: the info entry |
| @@ -937,11 +966,13 @@ int snd_info_unregister(struct snd_info_entry * entry) | |||
| 937 | return 0; | 966 | return 0; |
| 938 | } | 967 | } |
| 939 | 968 | ||
| 969 | EXPORT_SYMBOL(snd_info_unregister); | ||
| 970 | |||
| 940 | /* | 971 | /* |
| 941 | 972 | ||
| 942 | */ | 973 | */ |
| 943 | 974 | ||
| 944 | static struct snd_info_entry *snd_info_version_entry = NULL; | 975 | static struct snd_info_entry *snd_info_version_entry; |
| 945 | 976 | ||
| 946 | static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | 977 | static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
| 947 | { | 978 | { |
| @@ -958,7 +989,6 @@ static int __init snd_info_version_init(void) | |||
| 958 | entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL); | 989 | entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL); |
| 959 | if (entry == NULL) | 990 | if (entry == NULL) |
| 960 | return -ENOMEM; | 991 | return -ENOMEM; |
| 961 | entry->c.text.read_size = 256; | ||
| 962 | entry->c.text.read = snd_info_version_read; | 992 | entry->c.text.read = snd_info_version_read; |
| 963 | if (snd_info_register(entry) < 0) { | 993 | if (snd_info_register(entry) < 0) { |
| 964 | snd_info_free_entry(entry); | 994 | snd_info_free_entry(entry); |
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c index f9ce854b3d11..bb2c40d0ab66 100644 --- a/sound/core/info_oss.c +++ b/sound/core/info_oss.c | |||
| @@ -64,6 +64,8 @@ int snd_oss_info_register(int dev, int num, char *string) | |||
| 64 | return 0; | 64 | return 0; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | EXPORT_SYMBOL(snd_oss_info_register); | ||
| 68 | |||
| 67 | extern void snd_card_info_read_oss(struct snd_info_buffer *buffer); | 69 | extern void snd_card_info_read_oss(struct snd_info_buffer *buffer); |
| 68 | 70 | ||
| 69 | static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev) | 71 | static int snd_sndstat_show_strings(struct snd_info_buffer *buf, char *id, int dev) |
| @@ -117,7 +119,6 @@ int snd_info_minor_register(void) | |||
| 117 | 119 | ||
| 118 | memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings)); | 120 | memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings)); |
| 119 | if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) { | 121 | if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) { |
| 120 | entry->c.text.read_size = 2048; | ||
| 121 | entry->c.text.read = snd_sndstat_proc_read; | 122 | entry->c.text.read = snd_sndstat_proc_read; |
| 122 | if (snd_info_register(entry) < 0) { | 123 | if (snd_info_register(entry) < 0) { |
| 123 | snd_info_free_entry(entry); | 124 | snd_info_free_entry(entry); |
diff --git a/sound/core/init.c b/sound/core/init.c index 39ed2e5bb0af..4d9258884e44 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
| @@ -38,12 +38,15 @@ struct snd_shutdown_f_ops { | |||
| 38 | struct snd_shutdown_f_ops *next; | 38 | struct snd_shutdown_f_ops *next; |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | unsigned int snd_cards_lock = 0; /* locked for registering/using */ | 41 | static unsigned int snd_cards_lock; /* locked for registering/using */ |
| 42 | struct snd_card *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL}; | 42 | struct snd_card *snd_cards[SNDRV_CARDS]; |
| 43 | DEFINE_RWLOCK(snd_card_rwlock); | 43 | EXPORT_SYMBOL(snd_cards); |
| 44 | |||
| 45 | static DEFINE_MUTEX(snd_card_mutex); | ||
| 44 | 46 | ||
| 45 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | 47 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) |
| 46 | int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); | 48 | int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); |
| 49 | EXPORT_SYMBOL(snd_mixer_oss_notify_callback); | ||
| 47 | #endif | 50 | #endif |
| 48 | 51 | ||
| 49 | #ifdef CONFIG_PROC_FS | 52 | #ifdef CONFIG_PROC_FS |
| @@ -66,7 +69,6 @@ static inline int init_info_for_card(struct snd_card *card) | |||
| 66 | snd_printd("unable to create card entry\n"); | 69 | snd_printd("unable to create card entry\n"); |
| 67 | return err; | 70 | return err; |
| 68 | } | 71 | } |
| 69 | entry->c.text.read_size = PAGE_SIZE; | ||
| 70 | entry->c.text.read = snd_card_id_read; | 72 | entry->c.text.read = snd_card_id_read; |
| 71 | if (snd_info_register(entry) < 0) { | 73 | if (snd_info_register(entry) < 0) { |
| 72 | snd_info_free_entry(entry); | 74 | snd_info_free_entry(entry); |
| @@ -110,7 +112,7 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
| 110 | strlcpy(card->id, xid, sizeof(card->id)); | 112 | strlcpy(card->id, xid, sizeof(card->id)); |
| 111 | } | 113 | } |
| 112 | err = 0; | 114 | err = 0; |
| 113 | write_lock(&snd_card_rwlock); | 115 | mutex_lock(&snd_card_mutex); |
| 114 | if (idx < 0) { | 116 | if (idx < 0) { |
| 115 | int idx2; | 117 | int idx2; |
| 116 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) | 118 | for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) |
| @@ -128,12 +130,12 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
| 128 | else | 130 | else |
| 129 | err = -ENODEV; | 131 | err = -ENODEV; |
| 130 | if (idx < 0 || err < 0) { | 132 | if (idx < 0 || err < 0) { |
| 131 | write_unlock(&snd_card_rwlock); | 133 | mutex_unlock(&snd_card_mutex); |
| 132 | snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1); | 134 | snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1); |
| 133 | goto __error; | 135 | goto __error; |
| 134 | } | 136 | } |
| 135 | snd_cards_lock |= 1 << idx; /* lock it */ | 137 | snd_cards_lock |= 1 << idx; /* lock it */ |
| 136 | write_unlock(&snd_card_rwlock); | 138 | mutex_unlock(&snd_card_mutex); |
| 137 | card->number = idx; | 139 | card->number = idx; |
| 138 | card->module = module; | 140 | card->module = module; |
| 139 | INIT_LIST_HEAD(&card->devices); | 141 | INIT_LIST_HEAD(&card->devices); |
| @@ -169,6 +171,19 @@ struct snd_card *snd_card_new(int idx, const char *xid, | |||
| 169 | return NULL; | 171 | return NULL; |
| 170 | } | 172 | } |
| 171 | 173 | ||
| 174 | EXPORT_SYMBOL(snd_card_new); | ||
| 175 | |||
| 176 | /* return non-zero if a card is already locked */ | ||
| 177 | int snd_card_locked(int card) | ||
| 178 | { | ||
| 179 | int locked; | ||
| 180 | |||
| 181 | mutex_lock(&snd_card_mutex); | ||
| 182 | locked = snd_cards_lock & (1 << card); | ||
| 183 | mutex_unlock(&snd_card_mutex); | ||
| 184 | return locked; | ||
| 185 | } | ||
| 186 | |||
| 172 | static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig) | 187 | static loff_t snd_disconnect_llseek(struct file *file, loff_t offset, int orig) |
| 173 | { | 188 | { |
| 174 | return -ENODEV; | 189 | return -ENODEV; |
| @@ -236,9 +251,9 @@ int snd_card_disconnect(struct snd_card *card) | |||
| 236 | spin_unlock(&card->files_lock); | 251 | spin_unlock(&card->files_lock); |
| 237 | 252 | ||
| 238 | /* phase 1: disable fops (user space) operations for ALSA API */ | 253 | /* phase 1: disable fops (user space) operations for ALSA API */ |
| 239 | write_lock(&snd_card_rwlock); | 254 | mutex_lock(&snd_card_mutex); |
| 240 | snd_cards[card->number] = NULL; | 255 | snd_cards[card->number] = NULL; |
| 241 | write_unlock(&snd_card_rwlock); | 256 | mutex_unlock(&snd_card_mutex); |
| 242 | 257 | ||
| 243 | /* phase 2: replace file->f_op with special dummy operations */ | 258 | /* phase 2: replace file->f_op with special dummy operations */ |
| 244 | 259 | ||
| @@ -298,6 +313,8 @@ int snd_card_disconnect(struct snd_card *card) | |||
| 298 | return 0; | 313 | return 0; |
| 299 | } | 314 | } |
| 300 | 315 | ||
| 316 | EXPORT_SYMBOL(snd_card_disconnect); | ||
| 317 | |||
| 301 | /** | 318 | /** |
| 302 | * snd_card_free - frees given soundcard structure | 319 | * snd_card_free - frees given soundcard structure |
| 303 | * @card: soundcard structure | 320 | * @card: soundcard structure |
| @@ -315,9 +332,9 @@ int snd_card_free(struct snd_card *card) | |||
| 315 | 332 | ||
| 316 | if (card == NULL) | 333 | if (card == NULL) |
| 317 | return -EINVAL; | 334 | return -EINVAL; |
| 318 | write_lock(&snd_card_rwlock); | 335 | mutex_lock(&snd_card_mutex); |
| 319 | snd_cards[card->number] = NULL; | 336 | snd_cards[card->number] = NULL; |
| 320 | write_unlock(&snd_card_rwlock); | 337 | mutex_unlock(&snd_card_mutex); |
| 321 | 338 | ||
| 322 | #ifdef CONFIG_PM | 339 | #ifdef CONFIG_PM |
| 323 | wake_up(&card->power_sleep); | 340 | wake_up(&card->power_sleep); |
| @@ -353,13 +370,15 @@ int snd_card_free(struct snd_card *card) | |||
| 353 | card->s_f_ops = s_f_ops->next; | 370 | card->s_f_ops = s_f_ops->next; |
| 354 | kfree(s_f_ops); | 371 | kfree(s_f_ops); |
| 355 | } | 372 | } |
| 356 | write_lock(&snd_card_rwlock); | 373 | mutex_lock(&snd_card_mutex); |
| 357 | snd_cards_lock &= ~(1 << card->number); | 374 | snd_cards_lock &= ~(1 << card->number); |
| 358 | write_unlock(&snd_card_rwlock); | 375 | mutex_unlock(&snd_card_mutex); |
| 359 | kfree(card); | 376 | kfree(card); |
| 360 | return 0; | 377 | return 0; |
| 361 | } | 378 | } |
| 362 | 379 | ||
| 380 | EXPORT_SYMBOL(snd_card_free); | ||
| 381 | |||
| 363 | static void snd_card_free_thread(void * __card) | 382 | static void snd_card_free_thread(void * __card) |
| 364 | { | 383 | { |
| 365 | struct snd_card *card = __card; | 384 | struct snd_card *card = __card; |
| @@ -405,6 +424,8 @@ int snd_card_free_in_thread(struct snd_card *card) | |||
| 405 | return -EFAULT; | 424 | return -EFAULT; |
| 406 | } | 425 | } |
| 407 | 426 | ||
| 427 | EXPORT_SYMBOL(snd_card_free_in_thread); | ||
| 428 | |||
| 408 | static void choose_default_id(struct snd_card *card) | 429 | static void choose_default_id(struct snd_card *card) |
| 409 | { | 430 | { |
| 410 | int i, len, idx_flag = 0, loops = SNDRV_CARDS; | 431 | int i, len, idx_flag = 0, loops = SNDRV_CARDS; |
| @@ -487,16 +508,16 @@ int snd_card_register(struct snd_card *card) | |||
| 487 | snd_assert(card != NULL, return -EINVAL); | 508 | snd_assert(card != NULL, return -EINVAL); |
| 488 | if ((err = snd_device_register_all(card)) < 0) | 509 | if ((err = snd_device_register_all(card)) < 0) |
| 489 | return err; | 510 | return err; |
| 490 | write_lock(&snd_card_rwlock); | 511 | mutex_lock(&snd_card_mutex); |
| 491 | if (snd_cards[card->number]) { | 512 | if (snd_cards[card->number]) { |
| 492 | /* already registered */ | 513 | /* already registered */ |
| 493 | write_unlock(&snd_card_rwlock); | 514 | mutex_unlock(&snd_card_mutex); |
| 494 | return 0; | 515 | return 0; |
| 495 | } | 516 | } |
| 496 | if (card->id[0] == '\0') | 517 | if (card->id[0] == '\0') |
| 497 | choose_default_id(card); | 518 | choose_default_id(card); |
| 498 | snd_cards[card->number] = card; | 519 | snd_cards[card->number] = card; |
| 499 | write_unlock(&snd_card_rwlock); | 520 | mutex_unlock(&snd_card_mutex); |
| 500 | init_info_for_card(card); | 521 | init_info_for_card(card); |
| 501 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | 522 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) |
| 502 | if (snd_mixer_oss_notify_callback) | 523 | if (snd_mixer_oss_notify_callback) |
| @@ -505,8 +526,10 @@ int snd_card_register(struct snd_card *card) | |||
| 505 | return 0; | 526 | return 0; |
| 506 | } | 527 | } |
| 507 | 528 | ||
| 529 | EXPORT_SYMBOL(snd_card_register); | ||
| 530 | |||
| 508 | #ifdef CONFIG_PROC_FS | 531 | #ifdef CONFIG_PROC_FS |
| 509 | static struct snd_info_entry *snd_card_info_entry = NULL; | 532 | static struct snd_info_entry *snd_card_info_entry; |
| 510 | 533 | ||
| 511 | static void snd_card_info_read(struct snd_info_entry *entry, | 534 | static void snd_card_info_read(struct snd_info_entry *entry, |
| 512 | struct snd_info_buffer *buffer) | 535 | struct snd_info_buffer *buffer) |
| @@ -515,7 +538,7 @@ static void snd_card_info_read(struct snd_info_entry *entry, | |||
| 515 | struct snd_card *card; | 538 | struct snd_card *card; |
| 516 | 539 | ||
| 517 | for (idx = count = 0; idx < SNDRV_CARDS; idx++) { | 540 | for (idx = count = 0; idx < SNDRV_CARDS; idx++) { |
| 518 | read_lock(&snd_card_rwlock); | 541 | mutex_lock(&snd_card_mutex); |
| 519 | if ((card = snd_cards[idx]) != NULL) { | 542 | if ((card = snd_cards[idx]) != NULL) { |
| 520 | count++; | 543 | count++; |
| 521 | snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n", | 544 | snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n", |
| @@ -526,7 +549,7 @@ static void snd_card_info_read(struct snd_info_entry *entry, | |||
| 526 | snd_iprintf(buffer, " %s\n", | 549 | snd_iprintf(buffer, " %s\n", |
| 527 | card->longname); | 550 | card->longname); |
| 528 | } | 551 | } |
| 529 | read_unlock(&snd_card_rwlock); | 552 | mutex_unlock(&snd_card_mutex); |
| 530 | } | 553 | } |
| 531 | if (!count) | 554 | if (!count) |
| 532 | snd_iprintf(buffer, "--- no soundcards ---\n"); | 555 | snd_iprintf(buffer, "--- no soundcards ---\n"); |
| @@ -540,12 +563,12 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer) | |||
| 540 | struct snd_card *card; | 563 | struct snd_card *card; |
| 541 | 564 | ||
| 542 | for (idx = count = 0; idx < SNDRV_CARDS; idx++) { | 565 | for (idx = count = 0; idx < SNDRV_CARDS; idx++) { |
| 543 | read_lock(&snd_card_rwlock); | 566 | mutex_lock(&snd_card_mutex); |
| 544 | if ((card = snd_cards[idx]) != NULL) { | 567 | if ((card = snd_cards[idx]) != NULL) { |
| 545 | count++; | 568 | count++; |
| 546 | snd_iprintf(buffer, "%s\n", card->longname); | 569 | snd_iprintf(buffer, "%s\n", card->longname); |
| 547 | } | 570 | } |
| 548 | read_unlock(&snd_card_rwlock); | 571 | mutex_unlock(&snd_card_mutex); |
| 549 | } | 572 | } |
| 550 | if (!count) { | 573 | if (!count) { |
| 551 | snd_iprintf(buffer, "--- no soundcards ---\n"); | 574 | snd_iprintf(buffer, "--- no soundcards ---\n"); |
| @@ -563,11 +586,11 @@ static void snd_card_module_info_read(struct snd_info_entry *entry, | |||
| 563 | struct snd_card *card; | 586 | struct snd_card *card; |
| 564 | 587 | ||
| 565 | for (idx = 0; idx < SNDRV_CARDS; idx++) { | 588 | for (idx = 0; idx < SNDRV_CARDS; idx++) { |
| 566 | read_lock(&snd_card_rwlock); | 589 | mutex_lock(&snd_card_mutex); |
| 567 | if ((card = snd_cards[idx]) != NULL) | 590 | if ((card = snd_cards[idx]) != NULL) |
| 568 | snd_iprintf(buffer, "%2i %s\n", | 591 | snd_iprintf(buffer, "%2i %s\n", |
| 569 | idx, card->module->name); | 592 | idx, card->module->name); |
| 570 | read_unlock(&snd_card_rwlock); | 593 | mutex_unlock(&snd_card_mutex); |
| 571 | } | 594 | } |
| 572 | } | 595 | } |
| 573 | #endif | 596 | #endif |
| @@ -579,7 +602,6 @@ int __init snd_card_info_init(void) | |||
| 579 | entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL); | 602 | entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL); |
| 580 | if (! entry) | 603 | if (! entry) |
| 581 | return -ENOMEM; | 604 | return -ENOMEM; |
| 582 | entry->c.text.read_size = PAGE_SIZE; | ||
| 583 | entry->c.text.read = snd_card_info_read; | 605 | entry->c.text.read = snd_card_info_read; |
| 584 | if (snd_info_register(entry) < 0) { | 606 | if (snd_info_register(entry) < 0) { |
| 585 | snd_info_free_entry(entry); | 607 | snd_info_free_entry(entry); |
| @@ -590,7 +612,6 @@ int __init snd_card_info_init(void) | |||
| 590 | #ifdef MODULE | 612 | #ifdef MODULE |
| 591 | entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL); | 613 | entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL); |
| 592 | if (entry) { | 614 | if (entry) { |
| 593 | entry->c.text.read_size = PAGE_SIZE; | ||
| 594 | entry->c.text.read = snd_card_module_info_read; | 615 | entry->c.text.read = snd_card_module_info_read; |
| 595 | if (snd_info_register(entry) < 0) | 616 | if (snd_info_register(entry) < 0) |
| 596 | snd_info_free_entry(entry); | 617 | snd_info_free_entry(entry); |
| @@ -644,6 +665,8 @@ int snd_component_add(struct snd_card *card, const char *component) | |||
| 644 | return 0; | 665 | return 0; |
| 645 | } | 666 | } |
| 646 | 667 | ||
| 668 | EXPORT_SYMBOL(snd_component_add); | ||
| 669 | |||
| 647 | /** | 670 | /** |
| 648 | * snd_card_file_add - add the file to the file list of the card | 671 | * snd_card_file_add - add the file to the file list of the card |
| 649 | * @card: soundcard structure | 672 | * @card: soundcard structure |
| @@ -676,6 +699,8 @@ int snd_card_file_add(struct snd_card *card, struct file *file) | |||
| 676 | return 0; | 699 | return 0; |
| 677 | } | 700 | } |
| 678 | 701 | ||
| 702 | EXPORT_SYMBOL(snd_card_file_add); | ||
| 703 | |||
| 679 | /** | 704 | /** |
| 680 | * snd_card_file_remove - remove the file from the file list | 705 | * snd_card_file_remove - remove the file from the file list |
| 681 | * @card: soundcard structure | 706 | * @card: soundcard structure |
| @@ -717,6 +742,8 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) | |||
| 717 | return 0; | 742 | return 0; |
| 718 | } | 743 | } |
| 719 | 744 | ||
| 745 | EXPORT_SYMBOL(snd_card_file_remove); | ||
| 746 | |||
| 720 | #ifdef CONFIG_PM | 747 | #ifdef CONFIG_PM |
| 721 | /** | 748 | /** |
| 722 | * snd_power_wait - wait until the power-state is changed. | 749 | * snd_power_wait - wait until the power-state is changed. |
| @@ -753,4 +780,5 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state) | |||
| 753 | return result; | 780 | return result; |
| 754 | } | 781 | } |
| 755 | 782 | ||
| 783 | EXPORT_SYMBOL(snd_power_wait); | ||
| 756 | #endif /* CONFIG_PM */ | 784 | #endif /* CONFIG_PM */ |
diff --git a/sound/core/isadma.c b/sound/core/isadma.c index 1a378951da5b..d52398727f0a 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c | |||
| @@ -56,6 +56,8 @@ void snd_dma_program(unsigned long dma, | |||
| 56 | release_dma_lock(flags); | 56 | release_dma_lock(flags); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | EXPORT_SYMBOL(snd_dma_program); | ||
| 60 | |||
| 59 | /** | 61 | /** |
| 60 | * snd_dma_disable - stop the ISA DMA transfer | 62 | * snd_dma_disable - stop the ISA DMA transfer |
| 61 | * @dma: the dma number | 63 | * @dma: the dma number |
| @@ -72,6 +74,8 @@ void snd_dma_disable(unsigned long dma) | |||
| 72 | release_dma_lock(flags); | 74 | release_dma_lock(flags); |
| 73 | } | 75 | } |
| 74 | 76 | ||
| 77 | EXPORT_SYMBOL(snd_dma_disable); | ||
| 78 | |||
| 75 | /** | 79 | /** |
| 76 | * snd_dma_pointer - return the current pointer to DMA transfer buffer in bytes | 80 | * snd_dma_pointer - return the current pointer to DMA transfer buffer in bytes |
| 77 | * @dma: the dma number | 81 | * @dma: the dma number |
| @@ -101,3 +105,5 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size) | |||
| 101 | else | 105 | else |
| 102 | return size - result; | 106 | return size - result; |
| 103 | } | 107 | } |
| 108 | |||
| 109 | EXPORT_SYMBOL(snd_dma_pointer); | ||
diff --git a/sound/core/memory.c b/sound/core/memory.c index 862d62d2e144..fe59850be868 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/config.h> | 23 | #include <linux/config.h> |
| 24 | #include <linux/module.h> | ||
| 24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
| 25 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
| 26 | 27 | ||
| @@ -55,6 +56,8 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size | |||
| 55 | #endif | 56 | #endif |
| 56 | } | 57 | } |
| 57 | 58 | ||
| 59 | EXPORT_SYMBOL(copy_to_user_fromio); | ||
| 60 | |||
| 58 | /** | 61 | /** |
| 59 | * copy_from_user_toio - copy data from user-space to mmio-space | 62 | * copy_from_user_toio - copy data from user-space to mmio-space |
| 60 | * @dst: the destination pointer on mmio-space | 63 | * @dst: the destination pointer on mmio-space |
| @@ -85,3 +88,5 @@ int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size | |||
| 85 | return 0; | 88 | return 0; |
| 86 | #endif | 89 | #endif |
| 87 | } | 90 | } |
| 91 | |||
| 92 | EXPORT_SYMBOL(copy_from_user_toio); | ||
diff --git a/sound/core/misc.c b/sound/core/misc.c index b53e563c09e6..03fc711f4127 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c | |||
| @@ -34,6 +34,8 @@ void release_and_free_resource(struct resource *res) | |||
| 34 | } | 34 | } |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | EXPORT_SYMBOL(release_and_free_resource); | ||
| 38 | |||
| 37 | #ifdef CONFIG_SND_VERBOSE_PRINTK | 39 | #ifdef CONFIG_SND_VERBOSE_PRINTK |
| 38 | void snd_verbose_printk(const char *file, int line, const char *format, ...) | 40 | void snd_verbose_printk(const char *file, int line, const char *format, ...) |
| 39 | { | 41 | { |
| @@ -51,6 +53,8 @@ void snd_verbose_printk(const char *file, int line, const char *format, ...) | |||
| 51 | vprintk(format, args); | 53 | vprintk(format, args); |
| 52 | va_end(args); | 54 | va_end(args); |
| 53 | } | 55 | } |
| 56 | |||
| 57 | EXPORT_SYMBOL(snd_verbose_printk); | ||
| 54 | #endif | 58 | #endif |
| 55 | 59 | ||
| 56 | #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) | 60 | #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) |
| @@ -71,4 +75,6 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) | |||
| 71 | va_end(args); | 75 | va_end(args); |
| 72 | 76 | ||
| 73 | } | 77 | } |
| 78 | |||
| 79 | EXPORT_SYMBOL(snd_verbose_printd); | ||
| 74 | #endif | 80 | #endif |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 9c68bc3f97aa..71b5080fa66d 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
| @@ -1182,9 +1182,7 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer) | |||
| 1182 | return; | 1182 | return; |
| 1183 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 1183 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 1184 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 1184 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; |
| 1185 | entry->c.text.read_size = 8192; | ||
| 1186 | entry->c.text.read = snd_mixer_oss_proc_read; | 1185 | entry->c.text.read = snd_mixer_oss_proc_read; |
| 1187 | entry->c.text.write_size = 8192; | ||
| 1188 | entry->c.text.write = snd_mixer_oss_proc_write; | 1186 | entry->c.text.write = snd_mixer_oss_proc_write; |
| 1189 | entry->private_data = mixer; | 1187 | entry->private_data = mixer; |
| 1190 | if (snd_info_register(entry) < 0) { | 1188 | if (snd_info_register(entry) < 0) { |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index ac990bf0b48f..f5ff4f4a16ee 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
| @@ -45,7 +45,7 @@ | |||
| 45 | 45 | ||
| 46 | #define OSS_ALSAEMULVER _SIOR ('M', 249, int) | 46 | #define OSS_ALSAEMULVER _SIOR ('M', 249, int) |
| 47 | 47 | ||
| 48 | static int dsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0}; | 48 | static int dsp_map[SNDRV_CARDS]; |
| 49 | static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; | 49 | static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; |
| 50 | static int nonblock_open = 1; | 50 | static int nonblock_open = 1; |
| 51 | 51 | ||
| @@ -78,6 +78,487 @@ static inline void snd_leave_user(mm_segment_t fs) | |||
| 78 | set_fs(fs); | 78 | set_fs(fs); |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | /* | ||
| 82 | * helper functions to process hw_params | ||
| 83 | */ | ||
| 84 | static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin) | ||
| 85 | { | ||
| 86 | int changed = 0; | ||
| 87 | if (i->min < min) { | ||
| 88 | i->min = min; | ||
| 89 | i->openmin = openmin; | ||
| 90 | changed = 1; | ||
| 91 | } else if (i->min == min && !i->openmin && openmin) { | ||
| 92 | i->openmin = 1; | ||
| 93 | changed = 1; | ||
| 94 | } | ||
| 95 | if (i->integer) { | ||
| 96 | if (i->openmin) { | ||
| 97 | i->min++; | ||
| 98 | i->openmin = 0; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | if (snd_interval_checkempty(i)) { | ||
| 102 | snd_interval_none(i); | ||
| 103 | return -EINVAL; | ||
| 104 | } | ||
| 105 | return changed; | ||
| 106 | } | ||
| 107 | |||
| 108 | static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax) | ||
| 109 | { | ||
| 110 | int changed = 0; | ||
| 111 | if (i->max > max) { | ||
| 112 | i->max = max; | ||
| 113 | i->openmax = openmax; | ||
| 114 | changed = 1; | ||
| 115 | } else if (i->max == max && !i->openmax && openmax) { | ||
| 116 | i->openmax = 1; | ||
| 117 | changed = 1; | ||
| 118 | } | ||
| 119 | if (i->integer) { | ||
| 120 | if (i->openmax) { | ||
| 121 | i->max--; | ||
| 122 | i->openmax = 0; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | if (snd_interval_checkempty(i)) { | ||
| 126 | snd_interval_none(i); | ||
| 127 | return -EINVAL; | ||
| 128 | } | ||
| 129 | return changed; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int snd_interval_refine_set(struct snd_interval *i, unsigned int val) | ||
| 133 | { | ||
| 134 | struct snd_interval t; | ||
| 135 | t.empty = 0; | ||
| 136 | t.min = t.max = val; | ||
| 137 | t.openmin = t.openmax = 0; | ||
| 138 | t.integer = 1; | ||
| 139 | return snd_interval_refine(i, &t); | ||
| 140 | } | ||
| 141 | |||
| 142 | /** | ||
| 143 | * snd_pcm_hw_param_value_min | ||
| 144 | * @params: the hw_params instance | ||
| 145 | * @var: parameter to retrieve | ||
| 146 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 147 | * | ||
| 148 | * Return the minimum value for field PAR. | ||
| 149 | */ | ||
| 150 | static unsigned int | ||
| 151 | snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params, | ||
| 152 | snd_pcm_hw_param_t var, int *dir) | ||
| 153 | { | ||
| 154 | if (hw_is_mask(var)) { | ||
| 155 | if (dir) | ||
| 156 | *dir = 0; | ||
| 157 | return snd_mask_min(hw_param_mask_c(params, var)); | ||
| 158 | } | ||
| 159 | if (hw_is_interval(var)) { | ||
| 160 | const struct snd_interval *i = hw_param_interval_c(params, var); | ||
| 161 | if (dir) | ||
| 162 | *dir = i->openmin; | ||
| 163 | return snd_interval_min(i); | ||
| 164 | } | ||
| 165 | return -EINVAL; | ||
| 166 | } | ||
| 167 | |||
| 168 | /** | ||
| 169 | * snd_pcm_hw_param_value_max | ||
| 170 | * @params: the hw_params instance | ||
| 171 | * @var: parameter to retrieve | ||
| 172 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 173 | * | ||
| 174 | * Return the maximum value for field PAR. | ||
| 175 | */ | ||
| 176 | static unsigned int | ||
| 177 | snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params, | ||
| 178 | snd_pcm_hw_param_t var, int *dir) | ||
| 179 | { | ||
| 180 | if (hw_is_mask(var)) { | ||
| 181 | if (dir) | ||
| 182 | *dir = 0; | ||
| 183 | return snd_mask_max(hw_param_mask_c(params, var)); | ||
| 184 | } | ||
| 185 | if (hw_is_interval(var)) { | ||
| 186 | const struct snd_interval *i = hw_param_interval_c(params, var); | ||
| 187 | if (dir) | ||
| 188 | *dir = - (int) i->openmax; | ||
| 189 | return snd_interval_max(i); | ||
| 190 | } | ||
| 191 | return -EINVAL; | ||
| 192 | } | ||
| 193 | |||
| 194 | static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params, | ||
| 195 | snd_pcm_hw_param_t var, | ||
| 196 | const struct snd_mask *val) | ||
| 197 | { | ||
| 198 | int changed; | ||
| 199 | changed = snd_mask_refine(hw_param_mask(params, var), val); | ||
| 200 | if (changed) { | ||
| 201 | params->cmask |= 1 << var; | ||
| 202 | params->rmask |= 1 << var; | ||
| 203 | } | ||
| 204 | return changed; | ||
| 205 | } | ||
| 206 | |||
| 207 | static int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, | ||
| 208 | struct snd_pcm_hw_params *params, | ||
| 209 | snd_pcm_hw_param_t var, | ||
| 210 | const struct snd_mask *val) | ||
| 211 | { | ||
| 212 | int changed = _snd_pcm_hw_param_mask(params, var, val); | ||
| 213 | if (changed < 0) | ||
| 214 | return changed; | ||
| 215 | if (params->rmask) { | ||
| 216 | int err = snd_pcm_hw_refine(pcm, params); | ||
| 217 | if (err < 0) | ||
| 218 | return err; | ||
| 219 | } | ||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params, | ||
| 224 | snd_pcm_hw_param_t var, unsigned int val, | ||
| 225 | int dir) | ||
| 226 | { | ||
| 227 | int changed; | ||
| 228 | int open = 0; | ||
| 229 | if (dir) { | ||
| 230 | if (dir > 0) { | ||
| 231 | open = 1; | ||
| 232 | } else if (dir < 0) { | ||
| 233 | if (val > 0) { | ||
| 234 | open = 1; | ||
| 235 | val--; | ||
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
| 239 | if (hw_is_mask(var)) | ||
| 240 | changed = snd_mask_refine_min(hw_param_mask(params, var), | ||
| 241 | val + !!open); | ||
| 242 | else if (hw_is_interval(var)) | ||
| 243 | changed = snd_interval_refine_min(hw_param_interval(params, var), | ||
| 244 | val, open); | ||
| 245 | else | ||
| 246 | return -EINVAL; | ||
| 247 | if (changed) { | ||
| 248 | params->cmask |= 1 << var; | ||
| 249 | params->rmask |= 1 << var; | ||
| 250 | } | ||
| 251 | return changed; | ||
| 252 | } | ||
| 253 | |||
| 254 | /** | ||
| 255 | * snd_pcm_hw_param_min | ||
| 256 | * @pcm: PCM instance | ||
| 257 | * @params: the hw_params instance | ||
| 258 | * @var: parameter to retrieve | ||
| 259 | * @val: minimal value | ||
| 260 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 261 | * | ||
| 262 | * Inside configuration space defined by PARAMS remove from PAR all | ||
| 263 | * values < VAL. Reduce configuration space accordingly. | ||
| 264 | * Return new minimum or -EINVAL if the configuration space is empty | ||
| 265 | */ | ||
| 266 | static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm, | ||
| 267 | struct snd_pcm_hw_params *params, | ||
| 268 | snd_pcm_hw_param_t var, unsigned int val, | ||
| 269 | int *dir) | ||
| 270 | { | ||
| 271 | int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0); | ||
| 272 | if (changed < 0) | ||
| 273 | return changed; | ||
| 274 | if (params->rmask) { | ||
| 275 | int err = snd_pcm_hw_refine(pcm, params); | ||
| 276 | if (err < 0) | ||
| 277 | return err; | ||
| 278 | } | ||
| 279 | return snd_pcm_hw_param_value_min(params, var, dir); | ||
| 280 | } | ||
| 281 | |||
| 282 | static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params, | ||
| 283 | snd_pcm_hw_param_t var, unsigned int val, | ||
| 284 | int dir) | ||
| 285 | { | ||
| 286 | int changed; | ||
| 287 | int open = 0; | ||
| 288 | if (dir) { | ||
| 289 | if (dir < 0) { | ||
| 290 | open = 1; | ||
| 291 | } else if (dir > 0) { | ||
| 292 | open = 1; | ||
| 293 | val++; | ||
| 294 | } | ||
| 295 | } | ||
| 296 | if (hw_is_mask(var)) { | ||
| 297 | if (val == 0 && open) { | ||
| 298 | snd_mask_none(hw_param_mask(params, var)); | ||
| 299 | changed = -EINVAL; | ||
| 300 | } else | ||
| 301 | changed = snd_mask_refine_max(hw_param_mask(params, var), | ||
| 302 | val - !!open); | ||
| 303 | } else if (hw_is_interval(var)) | ||
| 304 | changed = snd_interval_refine_max(hw_param_interval(params, var), | ||
| 305 | val, open); | ||
| 306 | else | ||
| 307 | return -EINVAL; | ||
| 308 | if (changed) { | ||
| 309 | params->cmask |= 1 << var; | ||
| 310 | params->rmask |= 1 << var; | ||
| 311 | } | ||
| 312 | return changed; | ||
| 313 | } | ||
| 314 | |||
| 315 | /** | ||
| 316 | * snd_pcm_hw_param_max | ||
| 317 | * @pcm: PCM instance | ||
| 318 | * @params: the hw_params instance | ||
| 319 | * @var: parameter to retrieve | ||
| 320 | * @val: maximal value | ||
| 321 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 322 | * | ||
| 323 | * Inside configuration space defined by PARAMS remove from PAR all | ||
| 324 | * values >= VAL + 1. Reduce configuration space accordingly. | ||
| 325 | * Return new maximum or -EINVAL if the configuration space is empty | ||
| 326 | */ | ||
| 327 | static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm, | ||
| 328 | struct snd_pcm_hw_params *params, | ||
| 329 | snd_pcm_hw_param_t var, unsigned int val, | ||
| 330 | int *dir) | ||
| 331 | { | ||
| 332 | int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0); | ||
| 333 | if (changed < 0) | ||
| 334 | return changed; | ||
| 335 | if (params->rmask) { | ||
| 336 | int err = snd_pcm_hw_refine(pcm, params); | ||
| 337 | if (err < 0) | ||
| 338 | return err; | ||
| 339 | } | ||
| 340 | return snd_pcm_hw_param_value_max(params, var, dir); | ||
| 341 | } | ||
| 342 | |||
| 343 | static int boundary_sub(int a, int adir, | ||
| 344 | int b, int bdir, | ||
| 345 | int *c, int *cdir) | ||
| 346 | { | ||
| 347 | adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0); | ||
| 348 | bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0); | ||
| 349 | *c = a - b; | ||
| 350 | *cdir = adir - bdir; | ||
| 351 | if (*cdir == -2) { | ||
| 352 | (*c)--; | ||
| 353 | } else if (*cdir == 2) { | ||
| 354 | (*c)++; | ||
| 355 | } | ||
| 356 | return 0; | ||
| 357 | } | ||
| 358 | |||
| 359 | static int boundary_lt(unsigned int a, int adir, | ||
| 360 | unsigned int b, int bdir) | ||
| 361 | { | ||
| 362 | if (adir < 0) { | ||
| 363 | a--; | ||
| 364 | adir = 1; | ||
| 365 | } else if (adir > 0) | ||
| 366 | adir = 1; | ||
| 367 | if (bdir < 0) { | ||
| 368 | b--; | ||
| 369 | bdir = 1; | ||
| 370 | } else if (bdir > 0) | ||
| 371 | bdir = 1; | ||
| 372 | return a < b || (a == b && adir < bdir); | ||
| 373 | } | ||
| 374 | |||
| 375 | /* Return 1 if min is nearer to best than max */ | ||
| 376 | static int boundary_nearer(int min, int mindir, | ||
| 377 | int best, int bestdir, | ||
| 378 | int max, int maxdir) | ||
| 379 | { | ||
| 380 | int dmin, dmindir; | ||
| 381 | int dmax, dmaxdir; | ||
| 382 | boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir); | ||
| 383 | boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir); | ||
| 384 | return boundary_lt(dmin, dmindir, dmax, dmaxdir); | ||
| 385 | } | ||
| 386 | |||
| 387 | /** | ||
| 388 | * snd_pcm_hw_param_near | ||
| 389 | * @pcm: PCM instance | ||
| 390 | * @params: the hw_params instance | ||
| 391 | * @var: parameter to retrieve | ||
| 392 | * @best: value to set | ||
| 393 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 394 | * | ||
| 395 | * Inside configuration space defined by PARAMS set PAR to the available value | ||
| 396 | * nearest to VAL. Reduce configuration space accordingly. | ||
| 397 | * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS, | ||
| 398 | * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT. | ||
| 399 | * Return the value found. | ||
| 400 | */ | ||
| 401 | static int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, | ||
| 402 | struct snd_pcm_hw_params *params, | ||
| 403 | snd_pcm_hw_param_t var, unsigned int best, | ||
| 404 | int *dir) | ||
| 405 | { | ||
| 406 | struct snd_pcm_hw_params *save = NULL; | ||
| 407 | int v; | ||
| 408 | unsigned int saved_min; | ||
| 409 | int last = 0; | ||
| 410 | int min, max; | ||
| 411 | int mindir, maxdir; | ||
| 412 | int valdir = dir ? *dir : 0; | ||
| 413 | /* FIXME */ | ||
| 414 | if (best > INT_MAX) | ||
| 415 | best = INT_MAX; | ||
| 416 | min = max = best; | ||
| 417 | mindir = maxdir = valdir; | ||
| 418 | if (maxdir > 0) | ||
| 419 | maxdir = 0; | ||
| 420 | else if (maxdir == 0) | ||
| 421 | maxdir = -1; | ||
| 422 | else { | ||
| 423 | maxdir = 1; | ||
| 424 | max--; | ||
| 425 | } | ||
| 426 | save = kmalloc(sizeof(*save), GFP_KERNEL); | ||
| 427 | if (save == NULL) | ||
| 428 | return -ENOMEM; | ||
| 429 | *save = *params; | ||
| 430 | saved_min = min; | ||
| 431 | min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir); | ||
| 432 | if (min >= 0) { | ||
| 433 | struct snd_pcm_hw_params *params1; | ||
| 434 | if (max < 0) | ||
| 435 | goto _end; | ||
| 436 | if ((unsigned int)min == saved_min && mindir == valdir) | ||
| 437 | goto _end; | ||
| 438 | params1 = kmalloc(sizeof(*params1), GFP_KERNEL); | ||
| 439 | if (params1 == NULL) { | ||
| 440 | kfree(save); | ||
| 441 | return -ENOMEM; | ||
| 442 | } | ||
| 443 | *params1 = *save; | ||
| 444 | max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir); | ||
| 445 | if (max < 0) { | ||
| 446 | kfree(params1); | ||
| 447 | goto _end; | ||
| 448 | } | ||
| 449 | if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) { | ||
| 450 | *params = *params1; | ||
| 451 | last = 1; | ||
| 452 | } | ||
| 453 | kfree(params1); | ||
| 454 | } else { | ||
| 455 | *params = *save; | ||
| 456 | max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir); | ||
| 457 | snd_assert(max >= 0, return -EINVAL); | ||
| 458 | last = 1; | ||
| 459 | } | ||
| 460 | _end: | ||
| 461 | kfree(save); | ||
| 462 | if (last) | ||
| 463 | v = snd_pcm_hw_param_last(pcm, params, var, dir); | ||
| 464 | else | ||
| 465 | v = snd_pcm_hw_param_first(pcm, params, var, dir); | ||
| 466 | snd_assert(v >= 0, return -EINVAL); | ||
| 467 | return v; | ||
| 468 | } | ||
| 469 | |||
| 470 | static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, | ||
| 471 | snd_pcm_hw_param_t var, unsigned int val, | ||
| 472 | int dir) | ||
| 473 | { | ||
| 474 | int changed; | ||
| 475 | if (hw_is_mask(var)) { | ||
| 476 | struct snd_mask *m = hw_param_mask(params, var); | ||
| 477 | if (val == 0 && dir < 0) { | ||
| 478 | changed = -EINVAL; | ||
| 479 | snd_mask_none(m); | ||
| 480 | } else { | ||
| 481 | if (dir > 0) | ||
| 482 | val++; | ||
| 483 | else if (dir < 0) | ||
| 484 | val--; | ||
| 485 | changed = snd_mask_refine_set(hw_param_mask(params, var), val); | ||
| 486 | } | ||
| 487 | } else if (hw_is_interval(var)) { | ||
| 488 | struct snd_interval *i = hw_param_interval(params, var); | ||
| 489 | if (val == 0 && dir < 0) { | ||
| 490 | changed = -EINVAL; | ||
| 491 | snd_interval_none(i); | ||
| 492 | } else if (dir == 0) | ||
| 493 | changed = snd_interval_refine_set(i, val); | ||
| 494 | else { | ||
| 495 | struct snd_interval t; | ||
| 496 | t.openmin = 1; | ||
| 497 | t.openmax = 1; | ||
| 498 | t.empty = 0; | ||
| 499 | t.integer = 0; | ||
| 500 | if (dir < 0) { | ||
| 501 | t.min = val - 1; | ||
| 502 | t.max = val; | ||
| 503 | } else { | ||
| 504 | t.min = val; | ||
| 505 | t.max = val+1; | ||
| 506 | } | ||
| 507 | changed = snd_interval_refine(i, &t); | ||
| 508 | } | ||
| 509 | } else | ||
| 510 | return -EINVAL; | ||
| 511 | if (changed) { | ||
| 512 | params->cmask |= 1 << var; | ||
| 513 | params->rmask |= 1 << var; | ||
| 514 | } | ||
| 515 | return changed; | ||
| 516 | } | ||
| 517 | |||
| 518 | /** | ||
| 519 | * snd_pcm_hw_param_set | ||
| 520 | * @pcm: PCM instance | ||
| 521 | * @params: the hw_params instance | ||
| 522 | * @var: parameter to retrieve | ||
| 523 | * @val: value to set | ||
| 524 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 525 | * | ||
| 526 | * Inside configuration space defined by PARAMS remove from PAR all | ||
| 527 | * values != VAL. Reduce configuration space accordingly. | ||
| 528 | * Return VAL or -EINVAL if the configuration space is empty | ||
| 529 | */ | ||
| 530 | static int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm, | ||
| 531 | struct snd_pcm_hw_params *params, | ||
| 532 | snd_pcm_hw_param_t var, unsigned int val, | ||
| 533 | int dir) | ||
| 534 | { | ||
| 535 | int changed = _snd_pcm_hw_param_set(params, var, val, dir); | ||
| 536 | if (changed < 0) | ||
| 537 | return changed; | ||
| 538 | if (params->rmask) { | ||
| 539 | int err = snd_pcm_hw_refine(pcm, params); | ||
| 540 | if (err < 0) | ||
| 541 | return err; | ||
| 542 | } | ||
| 543 | return snd_pcm_hw_param_value(params, var, NULL); | ||
| 544 | } | ||
| 545 | |||
| 546 | static int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params, | ||
| 547 | snd_pcm_hw_param_t var) | ||
| 548 | { | ||
| 549 | int changed; | ||
| 550 | changed = snd_interval_setinteger(hw_param_interval(params, var)); | ||
| 551 | if (changed) { | ||
| 552 | params->cmask |= 1 << var; | ||
| 553 | params->rmask |= 1 << var; | ||
| 554 | } | ||
| 555 | return changed; | ||
| 556 | } | ||
| 557 | |||
| 558 | /* | ||
| 559 | * plugin | ||
| 560 | */ | ||
| 561 | |||
| 81 | #ifdef CONFIG_SND_PCM_OSS_PLUGINS | 562 | #ifdef CONFIG_SND_PCM_OSS_PLUGINS |
| 82 | static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream) | 563 | static int snd_pcm_oss_plugin_clear(struct snd_pcm_substream *substream) |
| 83 | { | 564 | { |
| @@ -203,7 +684,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, | |||
| 203 | oss_buffer_size = snd_pcm_plug_client_size(substream, | 684 | oss_buffer_size = snd_pcm_plug_client_size(substream, |
| 204 | snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size; | 685 | snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size; |
| 205 | oss_buffer_size = 1 << ld2(oss_buffer_size); | 686 | oss_buffer_size = 1 << ld2(oss_buffer_size); |
| 206 | if (atomic_read(&runtime->mmap_count)) { | 687 | if (atomic_read(&substream->mmap_count)) { |
| 207 | if (oss_buffer_size > runtime->oss.mmap_bytes) | 688 | if (oss_buffer_size > runtime->oss.mmap_bytes) |
| 208 | oss_buffer_size = runtime->oss.mmap_bytes; | 689 | oss_buffer_size = runtime->oss.mmap_bytes; |
| 209 | } | 690 | } |
| @@ -338,7 +819,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) | |||
| 338 | goto failure; | 819 | goto failure; |
| 339 | } | 820 | } |
| 340 | 821 | ||
| 341 | if (atomic_read(&runtime->mmap_count)) | 822 | if (atomic_read(&substream->mmap_count)) |
| 342 | direct = 1; | 823 | direct = 1; |
| 343 | else | 824 | else |
| 344 | direct = substream->oss.setup.direct; | 825 | direct = substream->oss.setup.direct; |
| @@ -347,7 +828,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) | |||
| 347 | _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS); | 828 | _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS); |
| 348 | _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0); | 829 | _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0); |
| 349 | snd_mask_none(&mask); | 830 | snd_mask_none(&mask); |
| 350 | if (atomic_read(&runtime->mmap_count)) | 831 | if (atomic_read(&substream->mmap_count)) |
| 351 | snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); | 832 | snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); |
| 352 | else { | 833 | else { |
| 353 | snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED); | 834 | snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED); |
| @@ -466,7 +947,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) | |||
| 466 | } else { | 947 | } else { |
| 467 | sw_params->start_threshold = runtime->boundary; | 948 | sw_params->start_threshold = runtime->boundary; |
| 468 | } | 949 | } |
| 469 | if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE) | 950 | if (atomic_read(&substream->mmap_count) || |
| 951 | substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
| 470 | sw_params->stop_threshold = runtime->boundary; | 952 | sw_params->stop_threshold = runtime->boundary; |
| 471 | else | 953 | else |
| 472 | sw_params->stop_threshold = runtime->buffer_size; | 954 | sw_params->stop_threshold = runtime->buffer_size; |
| @@ -476,7 +958,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) | |||
| 476 | sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? | 958 | sw_params->avail_min = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? |
| 477 | 1 : runtime->period_size; | 959 | 1 : runtime->period_size; |
| 478 | sw_params->xfer_align = 1; | 960 | sw_params->xfer_align = 1; |
| 479 | if (atomic_read(&runtime->mmap_count) || | 961 | if (atomic_read(&substream->mmap_count) || |
| 480 | substream->oss.setup.nosilence) { | 962 | substream->oss.setup.nosilence) { |
| 481 | sw_params->silence_threshold = 0; | 963 | sw_params->silence_threshold = 0; |
| 482 | sw_params->silence_size = 0; | 964 | sw_params->silence_size = 0; |
| @@ -820,7 +1302,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha | |||
| 820 | ssize_t tmp; | 1302 | ssize_t tmp; |
| 821 | struct snd_pcm_runtime *runtime = substream->runtime; | 1303 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 822 | 1304 | ||
| 823 | if (atomic_read(&runtime->mmap_count)) | 1305 | if (atomic_read(&substream->mmap_count)) |
| 824 | return -ENXIO; | 1306 | return -ENXIO; |
| 825 | 1307 | ||
| 826 | if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) | 1308 | if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) |
| @@ -850,7 +1332,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha | |||
| 850 | if (runtime->oss.period_ptr == 0 || | 1332 | if (runtime->oss.period_ptr == 0 || |
| 851 | runtime->oss.period_ptr == runtime->oss.buffer_used) | 1333 | runtime->oss.period_ptr == runtime->oss.buffer_used) |
| 852 | runtime->oss.buffer_used = 0; | 1334 | runtime->oss.buffer_used = 0; |
| 853 | else if ((substream->ffile->f_flags & O_NONBLOCK) != 0) | 1335 | else if ((substream->f_flags & O_NONBLOCK) != 0) |
| 854 | return xfer > 0 ? xfer : -EAGAIN; | 1336 | return xfer > 0 ? xfer : -EAGAIN; |
| 855 | } | 1337 | } |
| 856 | } else { | 1338 | } else { |
| @@ -863,7 +1345,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha | |||
| 863 | buf += tmp; | 1345 | buf += tmp; |
| 864 | bytes -= tmp; | 1346 | bytes -= tmp; |
| 865 | xfer += tmp; | 1347 | xfer += tmp; |
| 866 | if ((substream->ffile->f_flags & O_NONBLOCK) != 0 && | 1348 | if ((substream->f_flags & O_NONBLOCK) != 0 && |
| 867 | tmp != runtime->oss.period_bytes) | 1349 | tmp != runtime->oss.period_bytes) |
| 868 | break; | 1350 | break; |
| 869 | } | 1351 | } |
| @@ -910,7 +1392,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use | |||
| 910 | ssize_t tmp; | 1392 | ssize_t tmp; |
| 911 | struct snd_pcm_runtime *runtime = substream->runtime; | 1393 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 912 | 1394 | ||
| 913 | if (atomic_read(&runtime->mmap_count)) | 1395 | if (atomic_read(&substream->mmap_count)) |
| 914 | return -ENXIO; | 1396 | return -ENXIO; |
| 915 | 1397 | ||
| 916 | if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) | 1398 | if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) |
| @@ -1040,7 +1522,7 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) | |||
| 1040 | substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; | 1522 | substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; |
| 1041 | if (substream != NULL) { | 1523 | if (substream != NULL) { |
| 1042 | runtime = substream->runtime; | 1524 | runtime = substream->runtime; |
| 1043 | if (atomic_read(&runtime->mmap_count)) | 1525 | if (atomic_read(&substream->mmap_count)) |
| 1044 | goto __direct; | 1526 | goto __direct; |
| 1045 | if ((err = snd_pcm_oss_make_ready(substream)) < 0) | 1527 | if ((err = snd_pcm_oss_make_ready(substream)) < 0) |
| 1046 | return err; | 1528 | return err; |
| @@ -1101,10 +1583,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) | |||
| 1101 | * finish sync: drain the buffer | 1583 | * finish sync: drain the buffer |
| 1102 | */ | 1584 | */ |
| 1103 | __direct: | 1585 | __direct: |
| 1104 | saved_f_flags = substream->ffile->f_flags; | 1586 | saved_f_flags = substream->f_flags; |
| 1105 | substream->ffile->f_flags &= ~O_NONBLOCK; | 1587 | substream->f_flags &= ~O_NONBLOCK; |
| 1106 | err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); | 1588 | err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL); |
| 1107 | substream->ffile->f_flags = saved_f_flags; | 1589 | substream->f_flags = saved_f_flags; |
| 1108 | if (err < 0) | 1590 | if (err < 0) |
| 1109 | return err; | 1591 | return err; |
| 1110 | runtime->oss.prepare = 1; | 1592 | runtime->oss.prepare = 1; |
| @@ -1209,7 +1691,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) | |||
| 1209 | 1691 | ||
| 1210 | if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) | 1692 | if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0) |
| 1211 | return err; | 1693 | return err; |
| 1212 | if (atomic_read(&substream->runtime->mmap_count)) | 1694 | if (atomic_read(&substream->mmap_count)) |
| 1213 | direct = 1; | 1695 | direct = 1; |
| 1214 | else | 1696 | else |
| 1215 | direct = substream->oss.setup.direct; | 1697 | direct = substream->oss.setup.direct; |
| @@ -1419,7 +1901,7 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr | |||
| 1419 | if (trigger & PCM_ENABLE_OUTPUT) { | 1901 | if (trigger & PCM_ENABLE_OUTPUT) { |
| 1420 | if (runtime->oss.trigger) | 1902 | if (runtime->oss.trigger) |
| 1421 | goto _skip1; | 1903 | goto _skip1; |
| 1422 | if (atomic_read(&psubstream->runtime->mmap_count)) | 1904 | if (atomic_read(&psubstream->mmap_count)) |
| 1423 | snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); | 1905 | snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); |
| 1424 | runtime->oss.trigger = 1; | 1906 | runtime->oss.trigger = 1; |
| 1425 | runtime->start_threshold = 1; | 1907 | runtime->start_threshold = 1; |
| @@ -1537,7 +2019,7 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream | |||
| 1537 | if (err < 0) | 2019 | if (err < 0) |
| 1538 | return err; | 2020 | return err; |
| 1539 | info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); | 2021 | info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); |
| 1540 | if (atomic_read(&runtime->mmap_count)) { | 2022 | if (atomic_read(&substream->mmap_count)) { |
| 1541 | snd_pcm_sframes_t n; | 2023 | snd_pcm_sframes_t n; |
| 1542 | n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; | 2024 | n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; |
| 1543 | if (n < 0) | 2025 | if (n < 0) |
| @@ -1683,9 +2165,9 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream, | |||
| 1683 | substream->oss.oss = 1; | 2165 | substream->oss.oss = 1; |
| 1684 | substream->oss.setup = *setup; | 2166 | substream->oss.setup = *setup; |
| 1685 | if (setup->nonblock) | 2167 | if (setup->nonblock) |
| 1686 | substream->ffile->f_flags |= O_NONBLOCK; | 2168 | substream->f_flags |= O_NONBLOCK; |
| 1687 | else if (setup->block) | 2169 | else if (setup->block) |
| 1688 | substream->ffile->f_flags &= ~O_NONBLOCK; | 2170 | substream->f_flags &= ~O_NONBLOCK; |
| 1689 | runtime = substream->runtime; | 2171 | runtime = substream->runtime; |
| 1690 | runtime->oss.params = 1; | 2172 | runtime->oss.params = 1; |
| 1691 | runtime->oss.trigger = 1; | 2173 | runtime->oss.trigger = 1; |
| @@ -1742,6 +2224,7 @@ static int snd_pcm_oss_open_file(struct file *file, | |||
| 1742 | (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX)) | 2224 | (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX)) |
| 1743 | f_mode = FMODE_WRITE; | 2225 | f_mode = FMODE_WRITE; |
| 1744 | 2226 | ||
| 2227 | file->f_flags &= ~O_APPEND; | ||
| 1745 | for (idx = 0; idx < 2; idx++) { | 2228 | for (idx = 0; idx < 2; idx++) { |
| 1746 | if (setup[idx].disable) | 2229 | if (setup[idx].disable) |
| 1747 | continue; | 2230 | continue; |
| @@ -2059,6 +2542,7 @@ static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t coun | |||
| 2059 | substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; | 2542 | substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; |
| 2060 | if (substream == NULL) | 2543 | if (substream == NULL) |
| 2061 | return -ENXIO; | 2544 | return -ENXIO; |
| 2545 | substream->f_flags = file->f_flags & O_NONBLOCK; | ||
| 2062 | #ifndef OSS_DEBUG | 2546 | #ifndef OSS_DEBUG |
| 2063 | return snd_pcm_oss_read1(substream, buf, count); | 2547 | return snd_pcm_oss_read1(substream, buf, count); |
| 2064 | #else | 2548 | #else |
| @@ -2080,6 +2564,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size | |||
| 2080 | substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; | 2564 | substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; |
| 2081 | if (substream == NULL) | 2565 | if (substream == NULL) |
| 2082 | return -ENXIO; | 2566 | return -ENXIO; |
| 2567 | substream->f_flags = file->f_flags & O_NONBLOCK; | ||
| 2083 | result = snd_pcm_oss_write1(substream, buf, count); | 2568 | result = snd_pcm_oss_write1(substream, buf, count); |
| 2084 | #ifdef OSS_DEBUG | 2569 | #ifdef OSS_DEBUG |
| 2085 | printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result); | 2570 | printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result); |
| @@ -2090,7 +2575,7 @@ static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size | |||
| 2090 | static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) | 2575 | static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) |
| 2091 | { | 2576 | { |
| 2092 | struct snd_pcm_runtime *runtime = substream->runtime; | 2577 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 2093 | if (atomic_read(&runtime->mmap_count)) | 2578 | if (atomic_read(&substream->mmap_count)) |
| 2094 | return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; | 2579 | return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; |
| 2095 | else | 2580 | else |
| 2096 | return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; | 2581 | return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; |
| @@ -2099,7 +2584,7 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) | |||
| 2099 | static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) | 2584 | static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) |
| 2100 | { | 2585 | { |
| 2101 | struct snd_pcm_runtime *runtime = substream->runtime; | 2586 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 2102 | if (atomic_read(&runtime->mmap_count)) | 2587 | if (atomic_read(&substream->mmap_count)) |
| 2103 | return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; | 2588 | return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; |
| 2104 | else | 2589 | else |
| 2105 | return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; | 2590 | return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; |
| @@ -2342,9 +2827,7 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm) | |||
| 2342 | if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) { | 2827 | if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) { |
| 2343 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 2828 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 2344 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 2829 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; |
| 2345 | entry->c.text.read_size = 8192; | ||
| 2346 | entry->c.text.read = snd_pcm_oss_proc_read; | 2830 | entry->c.text.read = snd_pcm_oss_proc_read; |
| 2347 | entry->c.text.write_size = 8192; | ||
| 2348 | entry->c.text.write = snd_pcm_oss_proc_write; | 2831 | entry->c.text.write = snd_pcm_oss_proc_write; |
| 2349 | entry->private_data = pstr; | 2832 | entry->private_data = pstr; |
| 2350 | if (snd_info_register(entry) < 0) { | 2833 | if (snd_info_register(entry) < 0) { |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 84b00038236d..7581edd7b9ff 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
| @@ -351,10 +351,8 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, | |||
| 351 | snd_iprintf(buffer, "closed\n"); | 351 | snd_iprintf(buffer, "closed\n"); |
| 352 | return; | 352 | return; |
| 353 | } | 353 | } |
| 354 | snd_pcm_stream_lock_irq(substream); | ||
| 355 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { | 354 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
| 356 | snd_iprintf(buffer, "no setup\n"); | 355 | snd_iprintf(buffer, "no setup\n"); |
| 357 | snd_pcm_stream_unlock_irq(substream); | ||
| 358 | return; | 356 | return; |
| 359 | } | 357 | } |
| 360 | snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access)); | 358 | snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access)); |
| @@ -375,7 +373,6 @@ static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry, | |||
| 375 | snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames); | 373 | snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames); |
| 376 | } | 374 | } |
| 377 | #endif | 375 | #endif |
| 378 | snd_pcm_stream_unlock_irq(substream); | ||
| 379 | } | 376 | } |
| 380 | 377 | ||
| 381 | static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, | 378 | static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, |
| @@ -387,10 +384,8 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, | |||
| 387 | snd_iprintf(buffer, "closed\n"); | 384 | snd_iprintf(buffer, "closed\n"); |
| 388 | return; | 385 | return; |
| 389 | } | 386 | } |
| 390 | snd_pcm_stream_lock_irq(substream); | ||
| 391 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { | 387 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { |
| 392 | snd_iprintf(buffer, "no setup\n"); | 388 | snd_iprintf(buffer, "no setup\n"); |
| 393 | snd_pcm_stream_unlock_irq(substream); | ||
| 394 | return; | 389 | return; |
| 395 | } | 390 | } |
| 396 | snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode)); | 391 | snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode)); |
| @@ -403,7 +398,6 @@ static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry, | |||
| 403 | snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold); | 398 | snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold); |
| 404 | snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size); | 399 | snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size); |
| 405 | snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary); | 400 | snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary); |
| 406 | snd_pcm_stream_unlock_irq(substream); | ||
| 407 | } | 401 | } |
| 408 | 402 | ||
| 409 | static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, | 403 | static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, |
| @@ -472,7 +466,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) | |||
| 472 | pstr->proc_root = entry; | 466 | pstr->proc_root = entry; |
| 473 | 467 | ||
| 474 | if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) { | 468 | if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) { |
| 475 | snd_info_set_text_ops(entry, pstr, 256, snd_pcm_stream_proc_info_read); | 469 | snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read); |
| 476 | if (snd_info_register(entry) < 0) { | 470 | if (snd_info_register(entry) < 0) { |
| 477 | snd_info_free_entry(entry); | 471 | snd_info_free_entry(entry); |
| 478 | entry = NULL; | 472 | entry = NULL; |
| @@ -483,9 +477,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) | |||
| 483 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 477 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG |
| 484 | if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug", | 478 | if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug", |
| 485 | pstr->proc_root)) != NULL) { | 479 | pstr->proc_root)) != NULL) { |
| 486 | entry->c.text.read_size = 64; | ||
| 487 | entry->c.text.read = snd_pcm_xrun_debug_read; | 480 | entry->c.text.read = snd_pcm_xrun_debug_read; |
| 488 | entry->c.text.write_size = 64; | ||
| 489 | entry->c.text.write = snd_pcm_xrun_debug_write; | 481 | entry->c.text.write = snd_pcm_xrun_debug_write; |
| 490 | entry->mode |= S_IWUSR; | 482 | entry->mode |= S_IWUSR; |
| 491 | entry->private_data = pstr; | 483 | entry->private_data = pstr; |
| @@ -537,7 +529,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) | |||
| 537 | substream->proc_root = entry; | 529 | substream->proc_root = entry; |
| 538 | 530 | ||
| 539 | if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) { | 531 | if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) { |
| 540 | snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_info_read); | 532 | snd_info_set_text_ops(entry, substream, |
| 533 | snd_pcm_substream_proc_info_read); | ||
| 541 | if (snd_info_register(entry) < 0) { | 534 | if (snd_info_register(entry) < 0) { |
| 542 | snd_info_free_entry(entry); | 535 | snd_info_free_entry(entry); |
| 543 | entry = NULL; | 536 | entry = NULL; |
| @@ -546,7 +539,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) | |||
| 546 | substream->proc_info_entry = entry; | 539 | substream->proc_info_entry = entry; |
| 547 | 540 | ||
| 548 | if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) { | 541 | if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) { |
| 549 | snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_hw_params_read); | 542 | snd_info_set_text_ops(entry, substream, |
| 543 | snd_pcm_substream_proc_hw_params_read); | ||
| 550 | if (snd_info_register(entry) < 0) { | 544 | if (snd_info_register(entry) < 0) { |
| 551 | snd_info_free_entry(entry); | 545 | snd_info_free_entry(entry); |
| 552 | entry = NULL; | 546 | entry = NULL; |
| @@ -555,7 +549,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) | |||
| 555 | substream->proc_hw_params_entry = entry; | 549 | substream->proc_hw_params_entry = entry; |
| 556 | 550 | ||
| 557 | if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) { | 551 | if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) { |
| 558 | snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_sw_params_read); | 552 | snd_info_set_text_ops(entry, substream, |
| 553 | snd_pcm_substream_proc_sw_params_read); | ||
| 559 | if (snd_info_register(entry) < 0) { | 554 | if (snd_info_register(entry) < 0) { |
| 560 | snd_info_free_entry(entry); | 555 | snd_info_free_entry(entry); |
| 561 | entry = NULL; | 556 | entry = NULL; |
| @@ -564,7 +559,8 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) | |||
| 564 | substream->proc_sw_params_entry = entry; | 559 | substream->proc_sw_params_entry = entry; |
| 565 | 560 | ||
| 566 | if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) { | 561 | if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) { |
| 567 | snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_status_read); | 562 | snd_info_set_text_ops(entry, substream, |
| 563 | snd_pcm_substream_proc_status_read); | ||
| 568 | if (snd_info_register(entry) < 0) { | 564 | if (snd_info_register(entry) < 0) { |
| 569 | snd_info_free_entry(entry); | 565 | snd_info_free_entry(entry); |
| 570 | entry = NULL; | 566 | entry = NULL; |
| @@ -666,11 +662,14 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count) | |||
| 666 | INIT_LIST_HEAD(&substream->self_group.substreams); | 662 | INIT_LIST_HEAD(&substream->self_group.substreams); |
| 667 | list_add_tail(&substream->link_list, &substream->self_group.substreams); | 663 | list_add_tail(&substream->link_list, &substream->self_group.substreams); |
| 668 | spin_lock_init(&substream->timer_lock); | 664 | spin_lock_init(&substream->timer_lock); |
| 665 | atomic_set(&substream->mmap_count, 0); | ||
| 669 | prev = substream; | 666 | prev = substream; |
| 670 | } | 667 | } |
| 671 | return 0; | 668 | return 0; |
| 672 | } | 669 | } |
| 673 | 670 | ||
| 671 | EXPORT_SYMBOL(snd_pcm_new_stream); | ||
| 672 | |||
| 674 | /** | 673 | /** |
| 675 | * snd_pcm_new - create a new PCM instance | 674 | * snd_pcm_new - create a new PCM instance |
| 676 | * @card: the card instance | 675 | * @card: the card instance |
| @@ -730,6 +729,8 @@ int snd_pcm_new(struct snd_card *card, char *id, int device, | |||
| 730 | return 0; | 729 | return 0; |
| 731 | } | 730 | } |
| 732 | 731 | ||
| 732 | EXPORT_SYMBOL(snd_pcm_new); | ||
| 733 | |||
| 733 | static void snd_pcm_free_stream(struct snd_pcm_str * pstr) | 734 | static void snd_pcm_free_stream(struct snd_pcm_str * pstr) |
| 734 | { | 735 | { |
| 735 | struct snd_pcm_substream *substream, *substream_next; | 736 | struct snd_pcm_substream *substream, *substream_next; |
| @@ -829,6 +830,26 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
| 829 | return -EINVAL; | 830 | return -EINVAL; |
| 830 | } | 831 | } |
| 831 | 832 | ||
| 833 | if (file->f_flags & O_APPEND) { | ||
| 834 | if (prefer_subdevice < 0) { | ||
| 835 | if (pstr->substream_count > 1) | ||
| 836 | return -EINVAL; /* must be unique */ | ||
| 837 | substream = pstr->substream; | ||
| 838 | } else { | ||
| 839 | for (substream = pstr->substream; substream; | ||
| 840 | substream = substream->next) | ||
| 841 | if (substream->number == prefer_subdevice) | ||
| 842 | break; | ||
| 843 | } | ||
| 844 | if (! substream) | ||
| 845 | return -ENODEV; | ||
| 846 | if (! SUBSTREAM_BUSY(substream)) | ||
| 847 | return -EBADFD; | ||
| 848 | substream->ref_count++; | ||
| 849 | *rsubstream = substream; | ||
| 850 | return 0; | ||
| 851 | } | ||
| 852 | |||
| 832 | if (prefer_subdevice >= 0) { | 853 | if (prefer_subdevice >= 0) { |
| 833 | for (substream = pstr->substream; substream; substream = substream->next) | 854 | for (substream = pstr->substream; substream; substream = substream->next) |
| 834 | if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice) | 855 | if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice) |
| @@ -864,7 +885,6 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
| 864 | memset((void*)runtime->control, 0, size); | 885 | memset((void*)runtime->control, 0, size); |
| 865 | 886 | ||
| 866 | init_waitqueue_head(&runtime->sleep); | 887 | init_waitqueue_head(&runtime->sleep); |
| 867 | atomic_set(&runtime->mmap_count, 0); | ||
| 868 | init_timer(&runtime->tick_timer); | 888 | init_timer(&runtime->tick_timer); |
| 869 | runtime->tick_timer.function = snd_pcm_tick_timer_func; | 889 | runtime->tick_timer.function = snd_pcm_tick_timer_func; |
| 870 | runtime->tick_timer.data = (unsigned long) substream; | 890 | runtime->tick_timer.data = (unsigned long) substream; |
| @@ -873,7 +893,8 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
| 873 | 893 | ||
| 874 | substream->runtime = runtime; | 894 | substream->runtime = runtime; |
| 875 | substream->private_data = pcm->private_data; | 895 | substream->private_data = pcm->private_data; |
| 876 | substream->ffile = file; | 896 | substream->ref_count = 1; |
| 897 | substream->f_flags = file->f_flags; | ||
| 877 | pstr->substream_opened++; | 898 | pstr->substream_opened++; |
| 878 | *rsubstream = substream; | 899 | *rsubstream = substream; |
| 879 | return 0; | 900 | return 0; |
| @@ -882,7 +903,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
| 882 | void snd_pcm_detach_substream(struct snd_pcm_substream *substream) | 903 | void snd_pcm_detach_substream(struct snd_pcm_substream *substream) |
| 883 | { | 904 | { |
| 884 | struct snd_pcm_runtime *runtime; | 905 | struct snd_pcm_runtime *runtime; |
| 885 | substream->file = NULL; | 906 | |
| 886 | runtime = substream->runtime; | 907 | runtime = substream->runtime; |
| 887 | snd_assert(runtime != NULL, return); | 908 | snd_assert(runtime != NULL, return); |
| 888 | if (runtime->private_free != NULL) | 909 | if (runtime->private_free != NULL) |
| @@ -1022,6 +1043,8 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree) | |||
| 1022 | return 0; | 1043 | return 0; |
| 1023 | } | 1044 | } |
| 1024 | 1045 | ||
| 1046 | EXPORT_SYMBOL(snd_pcm_notify); | ||
| 1047 | |||
| 1025 | #ifdef CONFIG_PROC_FS | 1048 | #ifdef CONFIG_PROC_FS |
| 1026 | /* | 1049 | /* |
| 1027 | * Info interface | 1050 | * Info interface |
| @@ -1049,15 +1072,14 @@ static void snd_pcm_proc_read(struct snd_info_entry *entry, | |||
| 1049 | mutex_unlock(®ister_mutex); | 1072 | mutex_unlock(®ister_mutex); |
| 1050 | } | 1073 | } |
| 1051 | 1074 | ||
| 1052 | static struct snd_info_entry *snd_pcm_proc_entry = NULL; | 1075 | static struct snd_info_entry *snd_pcm_proc_entry; |
| 1053 | 1076 | ||
| 1054 | static void snd_pcm_proc_init(void) | 1077 | static void snd_pcm_proc_init(void) |
| 1055 | { | 1078 | { |
| 1056 | struct snd_info_entry *entry; | 1079 | struct snd_info_entry *entry; |
| 1057 | 1080 | ||
| 1058 | if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) { | 1081 | if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) { |
| 1059 | snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128, | 1082 | snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read); |
| 1060 | snd_pcm_proc_read); | ||
| 1061 | if (snd_info_register(entry) < 0) { | 1083 | if (snd_info_register(entry) < 0) { |
| 1062 | snd_info_free_entry(entry); | 1084 | snd_info_free_entry(entry); |
| 1063 | entry = NULL; | 1085 | entry = NULL; |
| @@ -1099,33 +1121,3 @@ static void __exit alsa_pcm_exit(void) | |||
| 1099 | 1121 | ||
| 1100 | module_init(alsa_pcm_init) | 1122 | module_init(alsa_pcm_init) |
| 1101 | module_exit(alsa_pcm_exit) | 1123 | module_exit(alsa_pcm_exit) |
| 1102 | |||
| 1103 | EXPORT_SYMBOL(snd_pcm_new); | ||
| 1104 | EXPORT_SYMBOL(snd_pcm_new_stream); | ||
| 1105 | EXPORT_SYMBOL(snd_pcm_notify); | ||
| 1106 | EXPORT_SYMBOL(snd_pcm_open_substream); | ||
| 1107 | EXPORT_SYMBOL(snd_pcm_release_substream); | ||
| 1108 | /* pcm_native.c */ | ||
| 1109 | EXPORT_SYMBOL(snd_pcm_link_rwlock); | ||
| 1110 | #ifdef CONFIG_PM | ||
| 1111 | EXPORT_SYMBOL(snd_pcm_suspend); | ||
| 1112 | EXPORT_SYMBOL(snd_pcm_suspend_all); | ||
| 1113 | #endif | ||
| 1114 | EXPORT_SYMBOL(snd_pcm_kernel_ioctl); | ||
| 1115 | EXPORT_SYMBOL(snd_pcm_mmap_data); | ||
| 1116 | #if SNDRV_PCM_INFO_MMAP_IOMEM | ||
| 1117 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); | ||
| 1118 | #endif | ||
| 1119 | /* pcm_misc.c */ | ||
| 1120 | EXPORT_SYMBOL(snd_pcm_format_signed); | ||
| 1121 | EXPORT_SYMBOL(snd_pcm_format_unsigned); | ||
| 1122 | EXPORT_SYMBOL(snd_pcm_format_linear); | ||
| 1123 | EXPORT_SYMBOL(snd_pcm_format_little_endian); | ||
| 1124 | EXPORT_SYMBOL(snd_pcm_format_big_endian); | ||
| 1125 | EXPORT_SYMBOL(snd_pcm_format_width); | ||
| 1126 | EXPORT_SYMBOL(snd_pcm_format_physical_width); | ||
| 1127 | EXPORT_SYMBOL(snd_pcm_format_size); | ||
| 1128 | EXPORT_SYMBOL(snd_pcm_format_silence_64); | ||
| 1129 | EXPORT_SYMBOL(snd_pcm_format_set_silence); | ||
| 1130 | EXPORT_SYMBOL(snd_pcm_build_linear_format); | ||
| 1131 | EXPORT_SYMBOL(snd_pcm_limit_hw_rates); | ||
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index e5133033de5e..2b8aab6fd6cd 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c | |||
| @@ -497,9 +497,9 @@ static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned l | |||
| 497 | case SNDRV_PCM_IOCTL_LINK: | 497 | case SNDRV_PCM_IOCTL_LINK: |
| 498 | case SNDRV_PCM_IOCTL_UNLINK: | 498 | case SNDRV_PCM_IOCTL_UNLINK: |
| 499 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 499 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 500 | return snd_pcm_playback_ioctl1(substream, cmd, argp); | 500 | return snd_pcm_playback_ioctl1(file, substream, cmd, argp); |
| 501 | else | 501 | else |
| 502 | return snd_pcm_capture_ioctl1(substream, cmd, argp); | 502 | return snd_pcm_capture_ioctl1(file, substream, cmd, argp); |
| 503 | case SNDRV_PCM_IOCTL_HW_REFINE32: | 503 | case SNDRV_PCM_IOCTL_HW_REFINE32: |
| 504 | return snd_pcm_ioctl_hw_params_compat(substream, 1, argp); | 504 | return snd_pcm_ioctl_hw_params_compat(substream, 1, argp); |
| 505 | case SNDRV_PCM_IOCTL_HW_PARAMS32: | 505 | case SNDRV_PCM_IOCTL_HW_PARAMS32: |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index eedc6cb038bb..0bb142a28539 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
| @@ -289,6 +289,7 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops | |||
| 289 | substream->ops = ops; | 289 | substream->ops = ops; |
| 290 | } | 290 | } |
| 291 | 291 | ||
| 292 | EXPORT_SYMBOL(snd_pcm_set_ops); | ||
| 292 | 293 | ||
| 293 | /** | 294 | /** |
| 294 | * snd_pcm_sync - set the PCM sync id | 295 | * snd_pcm_sync - set the PCM sync id |
| @@ -306,13 +307,12 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream) | |||
| 306 | runtime->sync.id32[3] = -1; | 307 | runtime->sync.id32[3] = -1; |
| 307 | } | 308 | } |
| 308 | 309 | ||
| 310 | EXPORT_SYMBOL(snd_pcm_set_sync); | ||
| 311 | |||
| 309 | /* | 312 | /* |
| 310 | * Standard ioctl routine | 313 | * Standard ioctl routine |
| 311 | */ | 314 | */ |
| 312 | 315 | ||
| 313 | /* Code taken from alsa-lib */ | ||
| 314 | #define assert(a) snd_assert((a), return -EINVAL) | ||
| 315 | |||
| 316 | static inline unsigned int div32(unsigned int a, unsigned int b, | 316 | static inline unsigned int div32(unsigned int a, unsigned int b, |
| 317 | unsigned int *r) | 317 | unsigned int *r) |
| 318 | { | 318 | { |
| @@ -369,56 +369,6 @@ static inline unsigned int muldiv32(unsigned int a, unsigned int b, | |||
| 369 | return n; | 369 | return n; |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | static int snd_interval_refine_min(struct snd_interval *i, unsigned int min, int openmin) | ||
| 373 | { | ||
| 374 | int changed = 0; | ||
| 375 | assert(!snd_interval_empty(i)); | ||
| 376 | if (i->min < min) { | ||
| 377 | i->min = min; | ||
| 378 | i->openmin = openmin; | ||
| 379 | changed = 1; | ||
| 380 | } else if (i->min == min && !i->openmin && openmin) { | ||
| 381 | i->openmin = 1; | ||
| 382 | changed = 1; | ||
| 383 | } | ||
| 384 | if (i->integer) { | ||
| 385 | if (i->openmin) { | ||
| 386 | i->min++; | ||
| 387 | i->openmin = 0; | ||
| 388 | } | ||
| 389 | } | ||
| 390 | if (snd_interval_checkempty(i)) { | ||
| 391 | snd_interval_none(i); | ||
| 392 | return -EINVAL; | ||
| 393 | } | ||
| 394 | return changed; | ||
| 395 | } | ||
| 396 | |||
| 397 | static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int openmax) | ||
| 398 | { | ||
| 399 | int changed = 0; | ||
| 400 | assert(!snd_interval_empty(i)); | ||
| 401 | if (i->max > max) { | ||
| 402 | i->max = max; | ||
| 403 | i->openmax = openmax; | ||
| 404 | changed = 1; | ||
| 405 | } else if (i->max == max && !i->openmax && openmax) { | ||
| 406 | i->openmax = 1; | ||
| 407 | changed = 1; | ||
| 408 | } | ||
| 409 | if (i->integer) { | ||
| 410 | if (i->openmax) { | ||
| 411 | i->max--; | ||
| 412 | i->openmax = 0; | ||
| 413 | } | ||
| 414 | } | ||
| 415 | if (snd_interval_checkempty(i)) { | ||
| 416 | snd_interval_none(i); | ||
| 417 | return -EINVAL; | ||
| 418 | } | ||
| 419 | return changed; | ||
| 420 | } | ||
| 421 | |||
| 422 | /** | 372 | /** |
| 423 | * snd_interval_refine - refine the interval value of configurator | 373 | * snd_interval_refine - refine the interval value of configurator |
| 424 | * @i: the interval value to refine | 374 | * @i: the interval value to refine |
| @@ -433,7 +383,7 @@ static int snd_interval_refine_max(struct snd_interval *i, unsigned int max, int | |||
| 433 | int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) | 383 | int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) |
| 434 | { | 384 | { |
| 435 | int changed = 0; | 385 | int changed = 0; |
| 436 | assert(!snd_interval_empty(i)); | 386 | snd_assert(!snd_interval_empty(i), return -EINVAL); |
| 437 | if (i->min < v->min) { | 387 | if (i->min < v->min) { |
| 438 | i->min = v->min; | 388 | i->min = v->min; |
| 439 | i->openmin = v->openmin; | 389 | i->openmin = v->openmin; |
| @@ -472,9 +422,11 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) | |||
| 472 | return changed; | 422 | return changed; |
| 473 | } | 423 | } |
| 474 | 424 | ||
| 425 | EXPORT_SYMBOL(snd_interval_refine); | ||
| 426 | |||
| 475 | static int snd_interval_refine_first(struct snd_interval *i) | 427 | static int snd_interval_refine_first(struct snd_interval *i) |
| 476 | { | 428 | { |
| 477 | assert(!snd_interval_empty(i)); | 429 | snd_assert(!snd_interval_empty(i), return -EINVAL); |
| 478 | if (snd_interval_single(i)) | 430 | if (snd_interval_single(i)) |
| 479 | return 0; | 431 | return 0; |
| 480 | i->max = i->min; | 432 | i->max = i->min; |
| @@ -486,7 +438,7 @@ static int snd_interval_refine_first(struct snd_interval *i) | |||
| 486 | 438 | ||
| 487 | static int snd_interval_refine_last(struct snd_interval *i) | 439 | static int snd_interval_refine_last(struct snd_interval *i) |
| 488 | { | 440 | { |
| 489 | assert(!snd_interval_empty(i)); | 441 | snd_assert(!snd_interval_empty(i), return -EINVAL); |
| 490 | if (snd_interval_single(i)) | 442 | if (snd_interval_single(i)) |
| 491 | return 0; | 443 | return 0; |
| 492 | i->min = i->max; | 444 | i->min = i->max; |
| @@ -496,16 +448,6 @@ static int snd_interval_refine_last(struct snd_interval *i) | |||
| 496 | return 1; | 448 | return 1; |
| 497 | } | 449 | } |
| 498 | 450 | ||
| 499 | static int snd_interval_refine_set(struct snd_interval *i, unsigned int val) | ||
| 500 | { | ||
| 501 | struct snd_interval t; | ||
| 502 | t.empty = 0; | ||
| 503 | t.min = t.max = val; | ||
| 504 | t.openmin = t.openmax = 0; | ||
| 505 | t.integer = 1; | ||
| 506 | return snd_interval_refine(i, &t); | ||
| 507 | } | ||
| 508 | |||
| 509 | void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c) | 451 | void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c) |
| 510 | { | 452 | { |
| 511 | if (a->empty || b->empty) { | 453 | if (a->empty || b->empty) { |
| @@ -621,7 +563,6 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, | |||
| 621 | c->integer = 0; | 563 | c->integer = 0; |
| 622 | } | 564 | } |
| 623 | 565 | ||
| 624 | #undef assert | ||
| 625 | /* ---- */ | 566 | /* ---- */ |
| 626 | 567 | ||
| 627 | 568 | ||
| @@ -727,6 +668,8 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
| 727 | return err; | 668 | return err; |
| 728 | } | 669 | } |
| 729 | 670 | ||
| 671 | EXPORT_SYMBOL(snd_interval_ratnum); | ||
| 672 | |||
| 730 | /** | 673 | /** |
| 731 | * snd_interval_ratden - refine the interval value | 674 | * snd_interval_ratden - refine the interval value |
| 732 | * @i: interval to refine | 675 | * @i: interval to refine |
| @@ -877,6 +820,8 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int * | |||
| 877 | return changed; | 820 | return changed; |
| 878 | } | 821 | } |
| 879 | 822 | ||
| 823 | EXPORT_SYMBOL(snd_interval_list); | ||
| 824 | |||
| 880 | static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step) | 825 | static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step) |
| 881 | { | 826 | { |
| 882 | unsigned int n; | 827 | unsigned int n; |
| @@ -953,6 +898,8 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, | |||
| 953 | return 0; | 898 | return 0; |
| 954 | } | 899 | } |
| 955 | 900 | ||
| 901 | EXPORT_SYMBOL(snd_pcm_hw_rule_add); | ||
| 902 | |||
| 956 | /** | 903 | /** |
| 957 | * snd_pcm_hw_constraint_mask | 904 | * snd_pcm_hw_constraint_mask |
| 958 | * @runtime: PCM runtime instance | 905 | * @runtime: PCM runtime instance |
| @@ -1007,6 +954,8 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa | |||
| 1007 | return snd_interval_setinteger(constrs_interval(constrs, var)); | 954 | return snd_interval_setinteger(constrs_interval(constrs, var)); |
| 1008 | } | 955 | } |
| 1009 | 956 | ||
| 957 | EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); | ||
| 958 | |||
| 1010 | /** | 959 | /** |
| 1011 | * snd_pcm_hw_constraint_minmax | 960 | * snd_pcm_hw_constraint_minmax |
| 1012 | * @runtime: PCM runtime instance | 961 | * @runtime: PCM runtime instance |
| @@ -1028,6 +977,8 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par | |||
| 1028 | return snd_interval_refine(constrs_interval(constrs, var), &t); | 977 | return snd_interval_refine(constrs_interval(constrs, var), &t); |
| 1029 | } | 978 | } |
| 1030 | 979 | ||
| 980 | EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); | ||
| 981 | |||
| 1031 | static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, | 982 | static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, |
| 1032 | struct snd_pcm_hw_rule *rule) | 983 | struct snd_pcm_hw_rule *rule) |
| 1033 | { | 984 | { |
| @@ -1055,6 +1006,8 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime, | |||
| 1055 | var, -1); | 1006 | var, -1); |
| 1056 | } | 1007 | } |
| 1057 | 1008 | ||
| 1009 | EXPORT_SYMBOL(snd_pcm_hw_constraint_list); | ||
| 1010 | |||
| 1058 | static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params, | 1011 | static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params, |
| 1059 | struct snd_pcm_hw_rule *rule) | 1012 | struct snd_pcm_hw_rule *rule) |
| 1060 | { | 1013 | { |
| @@ -1087,6 +1040,8 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, | |||
| 1087 | var, -1); | 1040 | var, -1); |
| 1088 | } | 1041 | } |
| 1089 | 1042 | ||
| 1043 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums); | ||
| 1044 | |||
| 1090 | static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, | 1045 | static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, |
| 1091 | struct snd_pcm_hw_rule *rule) | 1046 | struct snd_pcm_hw_rule *rule) |
| 1092 | { | 1047 | { |
| @@ -1118,6 +1073,8 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, | |||
| 1118 | var, -1); | 1073 | var, -1); |
| 1119 | } | 1074 | } |
| 1120 | 1075 | ||
| 1076 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); | ||
| 1077 | |||
| 1121 | static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, | 1078 | static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, |
| 1122 | struct snd_pcm_hw_rule *rule) | 1079 | struct snd_pcm_hw_rule *rule) |
| 1123 | { | 1080 | { |
| @@ -1149,6 +1106,8 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, | |||
| 1149 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); | 1106 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); |
| 1150 | } | 1107 | } |
| 1151 | 1108 | ||
| 1109 | EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); | ||
| 1110 | |||
| 1152 | static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, | 1111 | static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, |
| 1153 | struct snd_pcm_hw_rule *rule) | 1112 | struct snd_pcm_hw_rule *rule) |
| 1154 | { | 1113 | { |
| @@ -1173,6 +1132,8 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime, | |||
| 1173 | var, -1); | 1132 | var, -1); |
| 1174 | } | 1133 | } |
| 1175 | 1134 | ||
| 1135 | EXPORT_SYMBOL(snd_pcm_hw_constraint_step); | ||
| 1136 | |||
| 1176 | static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) | 1137 | static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) |
| 1177 | { | 1138 | { |
| 1178 | static int pow2_sizes[] = { | 1139 | static int pow2_sizes[] = { |
| @@ -1200,11 +1161,7 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, | |||
| 1200 | var, -1); | 1161 | var, -1); |
| 1201 | } | 1162 | } |
| 1202 | 1163 | ||
| 1203 | /* To use the same code we have in alsa-lib */ | 1164 | EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); |
| 1204 | #define assert(i) snd_assert((i), return -EINVAL) | ||
| 1205 | #ifndef INT_MIN | ||
| 1206 | #define INT_MIN ((int)((unsigned int)INT_MAX+1)) | ||
| 1207 | #endif | ||
| 1208 | 1165 | ||
| 1209 | static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params, | 1166 | static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params, |
| 1210 | snd_pcm_hw_param_t var) | 1167 | snd_pcm_hw_param_t var) |
| @@ -1224,18 +1181,6 @@ static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params, | |||
| 1224 | snd_BUG(); | 1181 | snd_BUG(); |
| 1225 | } | 1182 | } |
| 1226 | 1183 | ||
| 1227 | #if 0 | ||
| 1228 | /* | ||
| 1229 | * snd_pcm_hw_param_any | ||
| 1230 | */ | ||
| 1231 | int snd_pcm_hw_param_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, | ||
| 1232 | snd_pcm_hw_param_t var) | ||
| 1233 | { | ||
| 1234 | _snd_pcm_hw_param_any(params, var); | ||
| 1235 | return snd_pcm_hw_refine(pcm, params); | ||
| 1236 | } | ||
| 1237 | #endif /* 0 */ | ||
| 1238 | |||
| 1239 | void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params) | 1184 | void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params) |
| 1240 | { | 1185 | { |
| 1241 | unsigned int k; | 1186 | unsigned int k; |
| @@ -1247,18 +1192,7 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params) | |||
| 1247 | params->info = ~0U; | 1192 | params->info = ~0U; |
| 1248 | } | 1193 | } |
| 1249 | 1194 | ||
| 1250 | #if 0 | 1195 | EXPORT_SYMBOL(_snd_pcm_hw_params_any); |
| 1251 | /* | ||
| 1252 | * snd_pcm_hw_params_any | ||
| 1253 | * | ||
| 1254 | * Fill PARAMS with full configuration space boundaries | ||
| 1255 | */ | ||
| 1256 | int snd_pcm_hw_params_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params) | ||
| 1257 | { | ||
| 1258 | _snd_pcm_hw_params_any(params); | ||
| 1259 | return snd_pcm_hw_refine(pcm, params); | ||
| 1260 | } | ||
| 1261 | #endif /* 0 */ | ||
| 1262 | 1196 | ||
| 1263 | /** | 1197 | /** |
| 1264 | * snd_pcm_hw_param_value | 1198 | * snd_pcm_hw_param_value |
| @@ -1269,8 +1203,8 @@ int snd_pcm_hw_params_any(struct snd_pcm_substream *pcm, struct snd_pcm_hw_param | |||
| 1269 | * Return the value for field PAR if it's fixed in configuration space | 1203 | * Return the value for field PAR if it's fixed in configuration space |
| 1270 | * defined by PARAMS. Return -EINVAL otherwise | 1204 | * defined by PARAMS. Return -EINVAL otherwise |
| 1271 | */ | 1205 | */ |
| 1272 | static int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, | 1206 | int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, |
| 1273 | snd_pcm_hw_param_t var, int *dir) | 1207 | snd_pcm_hw_param_t var, int *dir) |
| 1274 | { | 1208 | { |
| 1275 | if (hw_is_mask(var)) { | 1209 | if (hw_is_mask(var)) { |
| 1276 | const struct snd_mask *mask = hw_param_mask_c(params, var); | 1210 | const struct snd_mask *mask = hw_param_mask_c(params, var); |
| @@ -1288,61 +1222,10 @@ static int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, | |||
| 1288 | *dir = i->openmin; | 1222 | *dir = i->openmin; |
| 1289 | return snd_interval_value(i); | 1223 | return snd_interval_value(i); |
| 1290 | } | 1224 | } |
| 1291 | assert(0); | ||
| 1292 | return -EINVAL; | ||
| 1293 | } | ||
| 1294 | |||
| 1295 | /** | ||
| 1296 | * snd_pcm_hw_param_value_min | ||
| 1297 | * @params: the hw_params instance | ||
| 1298 | * @var: parameter to retrieve | ||
| 1299 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 1300 | * | ||
| 1301 | * Return the minimum value for field PAR. | ||
| 1302 | */ | ||
| 1303 | unsigned int snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params, | ||
| 1304 | snd_pcm_hw_param_t var, int *dir) | ||
| 1305 | { | ||
| 1306 | if (hw_is_mask(var)) { | ||
| 1307 | if (dir) | ||
| 1308 | *dir = 0; | ||
| 1309 | return snd_mask_min(hw_param_mask_c(params, var)); | ||
| 1310 | } | ||
| 1311 | if (hw_is_interval(var)) { | ||
| 1312 | const struct snd_interval *i = hw_param_interval_c(params, var); | ||
| 1313 | if (dir) | ||
| 1314 | *dir = i->openmin; | ||
| 1315 | return snd_interval_min(i); | ||
| 1316 | } | ||
| 1317 | assert(0); | ||
| 1318 | return -EINVAL; | 1225 | return -EINVAL; |
| 1319 | } | 1226 | } |
| 1320 | 1227 | ||
| 1321 | /** | 1228 | EXPORT_SYMBOL(snd_pcm_hw_param_value); |
| 1322 | * snd_pcm_hw_param_value_max | ||
| 1323 | * @params: the hw_params instance | ||
| 1324 | * @var: parameter to retrieve | ||
| 1325 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 1326 | * | ||
| 1327 | * Return the maximum value for field PAR. | ||
| 1328 | */ | ||
| 1329 | unsigned int snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params, | ||
| 1330 | snd_pcm_hw_param_t var, int *dir) | ||
| 1331 | { | ||
| 1332 | if (hw_is_mask(var)) { | ||
| 1333 | if (dir) | ||
| 1334 | *dir = 0; | ||
| 1335 | return snd_mask_max(hw_param_mask_c(params, var)); | ||
| 1336 | } | ||
| 1337 | if (hw_is_interval(var)) { | ||
| 1338 | const struct snd_interval *i = hw_param_interval_c(params, var); | ||
| 1339 | if (dir) | ||
| 1340 | *dir = - (int) i->openmax; | ||
| 1341 | return snd_interval_max(i); | ||
| 1342 | } | ||
| 1343 | assert(0); | ||
| 1344 | return -EINVAL; | ||
| 1345 | } | ||
| 1346 | 1229 | ||
| 1347 | void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, | 1230 | void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, |
| 1348 | snd_pcm_hw_param_t var) | 1231 | snd_pcm_hw_param_t var) |
| @@ -1360,42 +1243,7 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, | |||
| 1360 | } | 1243 | } |
| 1361 | } | 1244 | } |
| 1362 | 1245 | ||
| 1363 | int _snd_pcm_hw_param_setinteger(struct snd_pcm_hw_params *params, | 1246 | EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); |
| 1364 | snd_pcm_hw_param_t var) | ||
| 1365 | { | ||
| 1366 | int changed; | ||
| 1367 | assert(hw_is_interval(var)); | ||
| 1368 | changed = snd_interval_setinteger(hw_param_interval(params, var)); | ||
| 1369 | if (changed) { | ||
| 1370 | params->cmask |= 1 << var; | ||
| 1371 | params->rmask |= 1 << var; | ||
| 1372 | } | ||
| 1373 | return changed; | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | #if 0 | ||
| 1377 | /* | ||
| 1378 | * snd_pcm_hw_param_setinteger | ||
| 1379 | * | ||
| 1380 | * Inside configuration space defined by PARAMS remove from PAR all | ||
| 1381 | * non integer values. Reduce configuration space accordingly. | ||
| 1382 | * Return -EINVAL if the configuration space is empty | ||
| 1383 | */ | ||
| 1384 | int snd_pcm_hw_param_setinteger(struct snd_pcm_substream *pcm, | ||
| 1385 | struct snd_pcm_hw_params *params, | ||
| 1386 | snd_pcm_hw_param_t var) | ||
| 1387 | { | ||
| 1388 | int changed = _snd_pcm_hw_param_setinteger(params, var); | ||
| 1389 | if (changed < 0) | ||
| 1390 | return changed; | ||
| 1391 | if (params->rmask) { | ||
| 1392 | int err = snd_pcm_hw_refine(pcm, params); | ||
| 1393 | if (err < 0) | ||
| 1394 | return err; | ||
| 1395 | } | ||
| 1396 | return 0; | ||
| 1397 | } | ||
| 1398 | #endif /* 0 */ | ||
| 1399 | 1247 | ||
| 1400 | static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, | 1248 | static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, |
| 1401 | snd_pcm_hw_param_t var) | 1249 | snd_pcm_hw_param_t var) |
| @@ -1405,10 +1253,8 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, | |||
| 1405 | changed = snd_mask_refine_first(hw_param_mask(params, var)); | 1253 | changed = snd_mask_refine_first(hw_param_mask(params, var)); |
| 1406 | else if (hw_is_interval(var)) | 1254 | else if (hw_is_interval(var)) |
| 1407 | changed = snd_interval_refine_first(hw_param_interval(params, var)); | 1255 | changed = snd_interval_refine_first(hw_param_interval(params, var)); |
| 1408 | else { | 1256 | else |
| 1409 | assert(0); | ||
| 1410 | return -EINVAL; | 1257 | return -EINVAL; |
| 1411 | } | ||
| 1412 | if (changed) { | 1258 | if (changed) { |
| 1413 | params->cmask |= 1 << var; | 1259 | params->cmask |= 1 << var; |
| 1414 | params->rmask |= 1 << var; | 1260 | params->rmask |= 1 << var; |
| @@ -1428,20 +1274,22 @@ static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, | |||
| 1428 | * values > minimum. Reduce configuration space accordingly. | 1274 | * values > minimum. Reduce configuration space accordingly. |
| 1429 | * Return the minimum. | 1275 | * Return the minimum. |
| 1430 | */ | 1276 | */ |
| 1431 | static int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, | 1277 | int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, |
| 1432 | struct snd_pcm_hw_params *params, | 1278 | struct snd_pcm_hw_params *params, |
| 1433 | snd_pcm_hw_param_t var, int *dir) | 1279 | snd_pcm_hw_param_t var, int *dir) |
| 1434 | { | 1280 | { |
| 1435 | int changed = _snd_pcm_hw_param_first(params, var); | 1281 | int changed = _snd_pcm_hw_param_first(params, var); |
| 1436 | if (changed < 0) | 1282 | if (changed < 0) |
| 1437 | return changed; | 1283 | return changed; |
| 1438 | if (params->rmask) { | 1284 | if (params->rmask) { |
| 1439 | int err = snd_pcm_hw_refine(pcm, params); | 1285 | int err = snd_pcm_hw_refine(pcm, params); |
| 1440 | assert(err >= 0); | 1286 | snd_assert(err >= 0, return err); |
| 1441 | } | 1287 | } |
| 1442 | return snd_pcm_hw_param_value(params, var, dir); | 1288 | return snd_pcm_hw_param_value(params, var, dir); |
| 1443 | } | 1289 | } |
| 1444 | 1290 | ||
| 1291 | EXPORT_SYMBOL(snd_pcm_hw_param_first); | ||
| 1292 | |||
| 1445 | static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, | 1293 | static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, |
| 1446 | snd_pcm_hw_param_t var) | 1294 | snd_pcm_hw_param_t var) |
| 1447 | { | 1295 | { |
| @@ -1450,10 +1298,8 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, | |||
| 1450 | changed = snd_mask_refine_last(hw_param_mask(params, var)); | 1298 | changed = snd_mask_refine_last(hw_param_mask(params, var)); |
| 1451 | else if (hw_is_interval(var)) | 1299 | else if (hw_is_interval(var)) |
| 1452 | changed = snd_interval_refine_last(hw_param_interval(params, var)); | 1300 | changed = snd_interval_refine_last(hw_param_interval(params, var)); |
| 1453 | else { | 1301 | else |
| 1454 | assert(0); | ||
| 1455 | return -EINVAL; | 1302 | return -EINVAL; |
| 1456 | } | ||
| 1457 | if (changed) { | 1303 | if (changed) { |
| 1458 | params->cmask |= 1 << var; | 1304 | params->cmask |= 1 << var; |
| 1459 | params->rmask |= 1 << var; | 1305 | params->rmask |= 1 << var; |
| @@ -1473,381 +1319,21 @@ static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, | |||
| 1473 | * values < maximum. Reduce configuration space accordingly. | 1319 | * values < maximum. Reduce configuration space accordingly. |
| 1474 | * Return the maximum. | 1320 | * Return the maximum. |
| 1475 | */ | 1321 | */ |
| 1476 | static int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, | 1322 | int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, |
| 1477 | struct snd_pcm_hw_params *params, | 1323 | struct snd_pcm_hw_params *params, |
| 1478 | snd_pcm_hw_param_t var, int *dir) | 1324 | snd_pcm_hw_param_t var, int *dir) |
| 1479 | { | 1325 | { |
| 1480 | int changed = _snd_pcm_hw_param_last(params, var); | 1326 | int changed = _snd_pcm_hw_param_last(params, var); |
| 1481 | if (changed < 0) | 1327 | if (changed < 0) |
| 1482 | return changed; | 1328 | return changed; |
| 1483 | if (params->rmask) { | 1329 | if (params->rmask) { |
| 1484 | int err = snd_pcm_hw_refine(pcm, params); | 1330 | int err = snd_pcm_hw_refine(pcm, params); |
| 1485 | assert(err >= 0); | 1331 | snd_assert(err >= 0, return err); |
| 1486 | } | 1332 | } |
| 1487 | return snd_pcm_hw_param_value(params, var, dir); | 1333 | return snd_pcm_hw_param_value(params, var, dir); |
| 1488 | } | 1334 | } |
| 1489 | 1335 | ||
| 1490 | int _snd_pcm_hw_param_min(struct snd_pcm_hw_params *params, | 1336 | EXPORT_SYMBOL(snd_pcm_hw_param_last); |
| 1491 | snd_pcm_hw_param_t var, unsigned int val, int dir) | ||
| 1492 | { | ||
| 1493 | int changed; | ||
| 1494 | int open = 0; | ||
| 1495 | if (dir) { | ||
| 1496 | if (dir > 0) { | ||
| 1497 | open = 1; | ||
| 1498 | } else if (dir < 0) { | ||
| 1499 | if (val > 0) { | ||
| 1500 | open = 1; | ||
| 1501 | val--; | ||
| 1502 | } | ||
| 1503 | } | ||
| 1504 | } | ||
| 1505 | if (hw_is_mask(var)) | ||
| 1506 | changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!open); | ||
| 1507 | else if (hw_is_interval(var)) | ||
| 1508 | changed = snd_interval_refine_min(hw_param_interval(params, var), val, open); | ||
| 1509 | else { | ||
| 1510 | assert(0); | ||
| 1511 | return -EINVAL; | ||
| 1512 | } | ||
| 1513 | if (changed) { | ||
| 1514 | params->cmask |= 1 << var; | ||
| 1515 | params->rmask |= 1 << var; | ||
| 1516 | } | ||
| 1517 | return changed; | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | /** | ||
| 1521 | * snd_pcm_hw_param_min | ||
| 1522 | * @pcm: PCM instance | ||
| 1523 | * @params: the hw_params instance | ||
| 1524 | * @var: parameter to retrieve | ||
| 1525 | * @val: minimal value | ||
| 1526 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 1527 | * | ||
| 1528 | * Inside configuration space defined by PARAMS remove from PAR all | ||
| 1529 | * values < VAL. Reduce configuration space accordingly. | ||
| 1530 | * Return new minimum or -EINVAL if the configuration space is empty | ||
| 1531 | */ | ||
| 1532 | static int snd_pcm_hw_param_min(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, | ||
| 1533 | snd_pcm_hw_param_t var, unsigned int val, | ||
| 1534 | int *dir) | ||
| 1535 | { | ||
| 1536 | int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0); | ||
| 1537 | if (changed < 0) | ||
| 1538 | return changed; | ||
| 1539 | if (params->rmask) { | ||
| 1540 | int err = snd_pcm_hw_refine(pcm, params); | ||
| 1541 | if (err < 0) | ||
| 1542 | return err; | ||
| 1543 | } | ||
| 1544 | return snd_pcm_hw_param_value_min(params, var, dir); | ||
| 1545 | } | ||
| 1546 | |||
| 1547 | static int _snd_pcm_hw_param_max(struct snd_pcm_hw_params *params, | ||
| 1548 | snd_pcm_hw_param_t var, unsigned int val, | ||
| 1549 | int dir) | ||
| 1550 | { | ||
| 1551 | int changed; | ||
| 1552 | int open = 0; | ||
| 1553 | if (dir) { | ||
| 1554 | if (dir < 0) { | ||
| 1555 | open = 1; | ||
| 1556 | } else if (dir > 0) { | ||
| 1557 | open = 1; | ||
| 1558 | val++; | ||
| 1559 | } | ||
| 1560 | } | ||
| 1561 | if (hw_is_mask(var)) { | ||
| 1562 | if (val == 0 && open) { | ||
| 1563 | snd_mask_none(hw_param_mask(params, var)); | ||
| 1564 | changed = -EINVAL; | ||
| 1565 | } else | ||
| 1566 | changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!open); | ||
| 1567 | } else if (hw_is_interval(var)) | ||
| 1568 | changed = snd_interval_refine_max(hw_param_interval(params, var), val, open); | ||
| 1569 | else { | ||
| 1570 | assert(0); | ||
| 1571 | return -EINVAL; | ||
| 1572 | } | ||
| 1573 | if (changed) { | ||
| 1574 | params->cmask |= 1 << var; | ||
| 1575 | params->rmask |= 1 << var; | ||
| 1576 | } | ||
| 1577 | return changed; | ||
| 1578 | } | ||
| 1579 | |||
| 1580 | /** | ||
| 1581 | * snd_pcm_hw_param_max | ||
| 1582 | * @pcm: PCM instance | ||
| 1583 | * @params: the hw_params instance | ||
| 1584 | * @var: parameter to retrieve | ||
| 1585 | * @val: maximal value | ||
| 1586 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 1587 | * | ||
| 1588 | * Inside configuration space defined by PARAMS remove from PAR all | ||
| 1589 | * values >= VAL + 1. Reduce configuration space accordingly. | ||
| 1590 | * Return new maximum or -EINVAL if the configuration space is empty | ||
| 1591 | */ | ||
| 1592 | static int snd_pcm_hw_param_max(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, | ||
| 1593 | snd_pcm_hw_param_t var, unsigned int val, | ||
| 1594 | int *dir) | ||
| 1595 | { | ||
| 1596 | int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0); | ||
| 1597 | if (changed < 0) | ||
| 1598 | return changed; | ||
| 1599 | if (params->rmask) { | ||
| 1600 | int err = snd_pcm_hw_refine(pcm, params); | ||
| 1601 | if (err < 0) | ||
| 1602 | return err; | ||
| 1603 | } | ||
| 1604 | return snd_pcm_hw_param_value_max(params, var, dir); | ||
| 1605 | } | ||
| 1606 | |||
| 1607 | int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params, | ||
| 1608 | snd_pcm_hw_param_t var, unsigned int val, int dir) | ||
| 1609 | { | ||
| 1610 | int changed; | ||
| 1611 | if (hw_is_mask(var)) { | ||
| 1612 | struct snd_mask *m = hw_param_mask(params, var); | ||
| 1613 | if (val == 0 && dir < 0) { | ||
| 1614 | changed = -EINVAL; | ||
| 1615 | snd_mask_none(m); | ||
| 1616 | } else { | ||
| 1617 | if (dir > 0) | ||
| 1618 | val++; | ||
| 1619 | else if (dir < 0) | ||
| 1620 | val--; | ||
| 1621 | changed = snd_mask_refine_set(hw_param_mask(params, var), val); | ||
| 1622 | } | ||
| 1623 | } else if (hw_is_interval(var)) { | ||
| 1624 | struct snd_interval *i = hw_param_interval(params, var); | ||
| 1625 | if (val == 0 && dir < 0) { | ||
| 1626 | changed = -EINVAL; | ||
| 1627 | snd_interval_none(i); | ||
| 1628 | } else if (dir == 0) | ||
| 1629 | changed = snd_interval_refine_set(i, val); | ||
| 1630 | else { | ||
| 1631 | struct snd_interval t; | ||
| 1632 | t.openmin = 1; | ||
| 1633 | t.openmax = 1; | ||
| 1634 | t.empty = 0; | ||
| 1635 | t.integer = 0; | ||
| 1636 | if (dir < 0) { | ||
| 1637 | t.min = val - 1; | ||
| 1638 | t.max = val; | ||
| 1639 | } else { | ||
| 1640 | t.min = val; | ||
| 1641 | t.max = val+1; | ||
| 1642 | } | ||
| 1643 | changed = snd_interval_refine(i, &t); | ||
| 1644 | } | ||
| 1645 | } else { | ||
| 1646 | assert(0); | ||
| 1647 | return -EINVAL; | ||
| 1648 | } | ||
| 1649 | if (changed) { | ||
| 1650 | params->cmask |= 1 << var; | ||
| 1651 | params->rmask |= 1 << var; | ||
| 1652 | } | ||
| 1653 | return changed; | ||
| 1654 | } | ||
| 1655 | |||
| 1656 | /** | ||
| 1657 | * snd_pcm_hw_param_set | ||
| 1658 | * @pcm: PCM instance | ||
| 1659 | * @params: the hw_params instance | ||
| 1660 | * @var: parameter to retrieve | ||
| 1661 | * @val: value to set | ||
| 1662 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 1663 | * | ||
| 1664 | * Inside configuration space defined by PARAMS remove from PAR all | ||
| 1665 | * values != VAL. Reduce configuration space accordingly. | ||
| 1666 | * Return VAL or -EINVAL if the configuration space is empty | ||
| 1667 | */ | ||
| 1668 | int snd_pcm_hw_param_set(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, | ||
| 1669 | snd_pcm_hw_param_t var, unsigned int val, int dir) | ||
| 1670 | { | ||
| 1671 | int changed = _snd_pcm_hw_param_set(params, var, val, dir); | ||
| 1672 | if (changed < 0) | ||
| 1673 | return changed; | ||
| 1674 | if (params->rmask) { | ||
| 1675 | int err = snd_pcm_hw_refine(pcm, params); | ||
| 1676 | if (err < 0) | ||
| 1677 | return err; | ||
| 1678 | } | ||
| 1679 | return snd_pcm_hw_param_value(params, var, NULL); | ||
| 1680 | } | ||
| 1681 | |||
| 1682 | static int _snd_pcm_hw_param_mask(struct snd_pcm_hw_params *params, | ||
| 1683 | snd_pcm_hw_param_t var, const struct snd_mask *val) | ||
| 1684 | { | ||
| 1685 | int changed; | ||
| 1686 | assert(hw_is_mask(var)); | ||
| 1687 | changed = snd_mask_refine(hw_param_mask(params, var), val); | ||
| 1688 | if (changed) { | ||
| 1689 | params->cmask |= 1 << var; | ||
| 1690 | params->rmask |= 1 << var; | ||
| 1691 | } | ||
| 1692 | return changed; | ||
| 1693 | } | ||
| 1694 | |||
| 1695 | /** | ||
| 1696 | * snd_pcm_hw_param_mask | ||
| 1697 | * @pcm: PCM instance | ||
| 1698 | * @params: the hw_params instance | ||
| 1699 | * @var: parameter to retrieve | ||
| 1700 | * @val: mask to apply | ||
| 1701 | * | ||
| 1702 | * Inside configuration space defined by PARAMS remove from PAR all values | ||
| 1703 | * not contained in MASK. Reduce configuration space accordingly. | ||
| 1704 | * This function can be called only for SNDRV_PCM_HW_PARAM_ACCESS, | ||
| 1705 | * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT. | ||
| 1706 | * Return 0 on success or -EINVAL | ||
| 1707 | * if the configuration space is empty | ||
| 1708 | */ | ||
| 1709 | int snd_pcm_hw_param_mask(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, | ||
| 1710 | snd_pcm_hw_param_t var, const struct snd_mask *val) | ||
| 1711 | { | ||
| 1712 | int changed = _snd_pcm_hw_param_mask(params, var, val); | ||
| 1713 | if (changed < 0) | ||
| 1714 | return changed; | ||
| 1715 | if (params->rmask) { | ||
| 1716 | int err = snd_pcm_hw_refine(pcm, params); | ||
| 1717 | if (err < 0) | ||
| 1718 | return err; | ||
| 1719 | } | ||
| 1720 | return 0; | ||
| 1721 | } | ||
| 1722 | |||
| 1723 | static int boundary_sub(int a, int adir, | ||
| 1724 | int b, int bdir, | ||
| 1725 | int *c, int *cdir) | ||
| 1726 | { | ||
| 1727 | adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0); | ||
| 1728 | bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0); | ||
| 1729 | *c = a - b; | ||
| 1730 | *cdir = adir - bdir; | ||
| 1731 | if (*cdir == -2) { | ||
| 1732 | assert(*c > INT_MIN); | ||
| 1733 | (*c)--; | ||
| 1734 | } else if (*cdir == 2) { | ||
| 1735 | assert(*c < INT_MAX); | ||
| 1736 | (*c)++; | ||
| 1737 | } | ||
| 1738 | return 0; | ||
| 1739 | } | ||
| 1740 | |||
| 1741 | static int boundary_lt(unsigned int a, int adir, | ||
| 1742 | unsigned int b, int bdir) | ||
| 1743 | { | ||
| 1744 | assert(a > 0 || adir >= 0); | ||
| 1745 | assert(b > 0 || bdir >= 0); | ||
| 1746 | if (adir < 0) { | ||
| 1747 | a--; | ||
| 1748 | adir = 1; | ||
| 1749 | } else if (adir > 0) | ||
| 1750 | adir = 1; | ||
| 1751 | if (bdir < 0) { | ||
| 1752 | b--; | ||
| 1753 | bdir = 1; | ||
| 1754 | } else if (bdir > 0) | ||
| 1755 | bdir = 1; | ||
| 1756 | return a < b || (a == b && adir < bdir); | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | /* Return 1 if min is nearer to best than max */ | ||
| 1760 | static int boundary_nearer(int min, int mindir, | ||
| 1761 | int best, int bestdir, | ||
| 1762 | int max, int maxdir) | ||
| 1763 | { | ||
| 1764 | int dmin, dmindir; | ||
| 1765 | int dmax, dmaxdir; | ||
| 1766 | boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir); | ||
| 1767 | boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir); | ||
| 1768 | return boundary_lt(dmin, dmindir, dmax, dmaxdir); | ||
| 1769 | } | ||
| 1770 | |||
| 1771 | /** | ||
| 1772 | * snd_pcm_hw_param_near | ||
| 1773 | * @pcm: PCM instance | ||
| 1774 | * @params: the hw_params instance | ||
| 1775 | * @var: parameter to retrieve | ||
| 1776 | * @best: value to set | ||
| 1777 | * @dir: pointer to the direction (-1,0,1) or NULL | ||
| 1778 | * | ||
| 1779 | * Inside configuration space defined by PARAMS set PAR to the available value | ||
| 1780 | * nearest to VAL. Reduce configuration space accordingly. | ||
| 1781 | * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS, | ||
| 1782 | * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT. | ||
| 1783 | * Return the value found. | ||
| 1784 | */ | ||
| 1785 | int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params, | ||
| 1786 | snd_pcm_hw_param_t var, unsigned int best, int *dir) | ||
| 1787 | { | ||
| 1788 | struct snd_pcm_hw_params *save = NULL; | ||
| 1789 | int v; | ||
| 1790 | unsigned int saved_min; | ||
| 1791 | int last = 0; | ||
| 1792 | int min, max; | ||
| 1793 | int mindir, maxdir; | ||
| 1794 | int valdir = dir ? *dir : 0; | ||
| 1795 | /* FIXME */ | ||
| 1796 | if (best > INT_MAX) | ||
| 1797 | best = INT_MAX; | ||
| 1798 | min = max = best; | ||
| 1799 | mindir = maxdir = valdir; | ||
| 1800 | if (maxdir > 0) | ||
| 1801 | maxdir = 0; | ||
| 1802 | else if (maxdir == 0) | ||
| 1803 | maxdir = -1; | ||
| 1804 | else { | ||
| 1805 | maxdir = 1; | ||
| 1806 | max--; | ||
| 1807 | } | ||
| 1808 | save = kmalloc(sizeof(*save), GFP_KERNEL); | ||
| 1809 | if (save == NULL) | ||
| 1810 | return -ENOMEM; | ||
| 1811 | *save = *params; | ||
| 1812 | saved_min = min; | ||
| 1813 | min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir); | ||
| 1814 | if (min >= 0) { | ||
| 1815 | struct snd_pcm_hw_params *params1; | ||
| 1816 | if (max < 0) | ||
| 1817 | goto _end; | ||
| 1818 | if ((unsigned int)min == saved_min && mindir == valdir) | ||
| 1819 | goto _end; | ||
| 1820 | params1 = kmalloc(sizeof(*params1), GFP_KERNEL); | ||
| 1821 | if (params1 == NULL) { | ||
| 1822 | kfree(save); | ||
| 1823 | return -ENOMEM; | ||
| 1824 | } | ||
| 1825 | *params1 = *save; | ||
| 1826 | max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir); | ||
| 1827 | if (max < 0) { | ||
| 1828 | kfree(params1); | ||
| 1829 | goto _end; | ||
| 1830 | } | ||
| 1831 | if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) { | ||
| 1832 | *params = *params1; | ||
| 1833 | last = 1; | ||
| 1834 | } | ||
| 1835 | kfree(params1); | ||
| 1836 | } else { | ||
| 1837 | *params = *save; | ||
| 1838 | max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir); | ||
| 1839 | assert(max >= 0); | ||
| 1840 | last = 1; | ||
| 1841 | } | ||
| 1842 | _end: | ||
| 1843 | kfree(save); | ||
| 1844 | if (last) | ||
| 1845 | v = snd_pcm_hw_param_last(pcm, params, var, dir); | ||
| 1846 | else | ||
| 1847 | v = snd_pcm_hw_param_first(pcm, params, var, dir); | ||
| 1848 | assert(v >= 0); | ||
| 1849 | return v; | ||
| 1850 | } | ||
| 1851 | 1337 | ||
| 1852 | /** | 1338 | /** |
| 1853 | * snd_pcm_hw_param_choose | 1339 | * snd_pcm_hw_param_choose |
| @@ -1859,39 +1345,32 @@ int snd_pcm_hw_param_near(struct snd_pcm_substream *pcm, struct snd_pcm_hw_param | |||
| 1859 | * first access, first format, first subformat, min channels, | 1345 | * first access, first format, first subformat, min channels, |
| 1860 | * min rate, min period time, max buffer size, min tick time | 1346 | * min rate, min period time, max buffer size, min tick time |
| 1861 | */ | 1347 | */ |
| 1862 | int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, struct snd_pcm_hw_params *params) | 1348 | int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, |
| 1863 | { | 1349 | struct snd_pcm_hw_params *params) |
| 1864 | int err; | 1350 | { |
| 1865 | 1351 | static int vars[] = { | |
| 1866 | err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_ACCESS, NULL); | 1352 | SNDRV_PCM_HW_PARAM_ACCESS, |
| 1867 | assert(err >= 0); | 1353 | SNDRV_PCM_HW_PARAM_FORMAT, |
| 1868 | 1354 | SNDRV_PCM_HW_PARAM_SUBFORMAT, | |
| 1869 | err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_FORMAT, NULL); | 1355 | SNDRV_PCM_HW_PARAM_CHANNELS, |
| 1870 | assert(err >= 0); | 1356 | SNDRV_PCM_HW_PARAM_RATE, |
| 1871 | 1357 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | |
| 1872 | err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_SUBFORMAT, NULL); | 1358 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, |
| 1873 | assert(err >= 0); | 1359 | SNDRV_PCM_HW_PARAM_TICK_TIME, |
| 1874 | 1360 | -1 | |
| 1875 | err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_CHANNELS, NULL); | 1361 | }; |
| 1876 | assert(err >= 0); | 1362 | int err, *v; |
| 1877 | |||
| 1878 | err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_RATE, NULL); | ||
| 1879 | assert(err >= 0); | ||
| 1880 | |||
| 1881 | err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_PERIOD_TIME, NULL); | ||
| 1882 | assert(err >= 0); | ||
| 1883 | |||
| 1884 | err = snd_pcm_hw_param_last(pcm, params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL); | ||
| 1885 | assert(err >= 0); | ||
| 1886 | |||
| 1887 | err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_TICK_TIME, NULL); | ||
| 1888 | assert(err >= 0); | ||
| 1889 | 1363 | ||
| 1364 | for (v = vars; *v != -1; v++) { | ||
| 1365 | if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) | ||
| 1366 | err = snd_pcm_hw_param_first(pcm, params, *v, NULL); | ||
| 1367 | else | ||
| 1368 | err = snd_pcm_hw_param_last(pcm, params, *v, NULL); | ||
| 1369 | snd_assert(err >= 0, return err); | ||
| 1370 | } | ||
| 1890 | return 0; | 1371 | return 0; |
| 1891 | } | 1372 | } |
| 1892 | 1373 | ||
| 1893 | #undef assert | ||
| 1894 | |||
| 1895 | static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, | 1374 | static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, |
| 1896 | void *arg) | 1375 | void *arg) |
| 1897 | { | 1376 | { |
| @@ -1967,6 +1446,8 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, | |||
| 1967 | return -ENXIO; | 1446 | return -ENXIO; |
| 1968 | } | 1447 | } |
| 1969 | 1448 | ||
| 1449 | EXPORT_SYMBOL(snd_pcm_lib_ioctl); | ||
| 1450 | |||
| 1970 | /* | 1451 | /* |
| 1971 | * Conditions | 1452 | * Conditions |
| 1972 | */ | 1453 | */ |
| @@ -2101,6 +1582,8 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) | |||
| 2101 | kill_fasync(&runtime->fasync, SIGIO, POLL_IN); | 1582 | kill_fasync(&runtime->fasync, SIGIO, POLL_IN); |
| 2102 | } | 1583 | } |
| 2103 | 1584 | ||
| 1585 | EXPORT_SYMBOL(snd_pcm_period_elapsed); | ||
| 1586 | |||
| 2104 | static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, | 1587 | static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, |
| 2105 | unsigned int hwoff, | 1588 | unsigned int hwoff, |
| 2106 | unsigned long data, unsigned int off, | 1589 | unsigned long data, unsigned int off, |
| @@ -2299,7 +1782,7 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v | |||
| 2299 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | 1782 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
| 2300 | return -EBADFD; | 1783 | return -EBADFD; |
| 2301 | 1784 | ||
| 2302 | nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); | 1785 | nonblock = !!(substream->f_flags & O_NONBLOCK); |
| 2303 | 1786 | ||
| 2304 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && | 1787 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && |
| 2305 | runtime->channels > 1) | 1788 | runtime->channels > 1) |
| @@ -2308,6 +1791,8 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v | |||
| 2308 | snd_pcm_lib_write_transfer); | 1791 | snd_pcm_lib_write_transfer); |
| 2309 | } | 1792 | } |
| 2310 | 1793 | ||
| 1794 | EXPORT_SYMBOL(snd_pcm_lib_write); | ||
| 1795 | |||
| 2311 | static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, | 1796 | static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, |
| 2312 | unsigned int hwoff, | 1797 | unsigned int hwoff, |
| 2313 | unsigned long data, unsigned int off, | 1798 | unsigned long data, unsigned int off, |
| @@ -2362,7 +1847,7 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, | |||
| 2362 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | 1847 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
| 2363 | return -EBADFD; | 1848 | return -EBADFD; |
| 2364 | 1849 | ||
| 2365 | nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); | 1850 | nonblock = !!(substream->f_flags & O_NONBLOCK); |
| 2366 | 1851 | ||
| 2367 | if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) | 1852 | if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) |
| 2368 | return -EINVAL; | 1853 | return -EINVAL; |
| @@ -2370,6 +1855,8 @@ snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, | |||
| 2370 | nonblock, snd_pcm_lib_writev_transfer); | 1855 | nonblock, snd_pcm_lib_writev_transfer); |
| 2371 | } | 1856 | } |
| 2372 | 1857 | ||
| 1858 | EXPORT_SYMBOL(snd_pcm_lib_writev); | ||
| 1859 | |||
| 2373 | static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, | 1860 | static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, |
| 2374 | unsigned int hwoff, | 1861 | unsigned int hwoff, |
| 2375 | unsigned long data, unsigned int off, | 1862 | unsigned long data, unsigned int off, |
| @@ -2572,12 +2059,14 @@ snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __u | |||
| 2572 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | 2059 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
| 2573 | return -EBADFD; | 2060 | return -EBADFD; |
| 2574 | 2061 | ||
| 2575 | nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); | 2062 | nonblock = !!(substream->f_flags & O_NONBLOCK); |
| 2576 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED) | 2063 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED) |
| 2577 | return -EINVAL; | 2064 | return -EINVAL; |
| 2578 | return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); | 2065 | return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); |
| 2579 | } | 2066 | } |
| 2580 | 2067 | ||
| 2068 | EXPORT_SYMBOL(snd_pcm_lib_read); | ||
| 2069 | |||
| 2581 | static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, | 2070 | static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, |
| 2582 | unsigned int hwoff, | 2071 | unsigned int hwoff, |
| 2583 | unsigned long data, unsigned int off, | 2072 | unsigned long data, unsigned int off, |
| @@ -2629,58 +2118,10 @@ snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, | |||
| 2629 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | 2118 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
| 2630 | return -EBADFD; | 2119 | return -EBADFD; |
| 2631 | 2120 | ||
| 2632 | nonblock = !!(substream->ffile->f_flags & O_NONBLOCK); | 2121 | nonblock = !!(substream->f_flags & O_NONBLOCK); |
| 2633 | if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) | 2122 | if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) |
| 2634 | return -EINVAL; | 2123 | return -EINVAL; |
| 2635 | return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer); | 2124 | return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer); |
| 2636 | } | 2125 | } |
| 2637 | 2126 | ||
| 2638 | /* | ||
| 2639 | * Exported symbols | ||
| 2640 | */ | ||
| 2641 | |||
| 2642 | EXPORT_SYMBOL(snd_interval_refine); | ||
| 2643 | EXPORT_SYMBOL(snd_interval_list); | ||
| 2644 | EXPORT_SYMBOL(snd_interval_ratnum); | ||
| 2645 | EXPORT_SYMBOL(_snd_pcm_hw_params_any); | ||
| 2646 | EXPORT_SYMBOL(_snd_pcm_hw_param_min); | ||
| 2647 | EXPORT_SYMBOL(_snd_pcm_hw_param_set); | ||
| 2648 | EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); | ||
| 2649 | EXPORT_SYMBOL(_snd_pcm_hw_param_setinteger); | ||
| 2650 | EXPORT_SYMBOL(snd_pcm_hw_param_value_min); | ||
| 2651 | EXPORT_SYMBOL(snd_pcm_hw_param_value_max); | ||
| 2652 | EXPORT_SYMBOL(snd_pcm_hw_param_mask); | ||
| 2653 | EXPORT_SYMBOL(snd_pcm_hw_param_first); | ||
| 2654 | EXPORT_SYMBOL(snd_pcm_hw_param_last); | ||
| 2655 | EXPORT_SYMBOL(snd_pcm_hw_param_near); | ||
| 2656 | EXPORT_SYMBOL(snd_pcm_hw_param_set); | ||
| 2657 | EXPORT_SYMBOL(snd_pcm_hw_refine); | ||
| 2658 | EXPORT_SYMBOL(snd_pcm_hw_constraints_init); | ||
| 2659 | EXPORT_SYMBOL(snd_pcm_hw_constraints_complete); | ||
| 2660 | EXPORT_SYMBOL(snd_pcm_hw_constraint_list); | ||
| 2661 | EXPORT_SYMBOL(snd_pcm_hw_constraint_step); | ||
| 2662 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums); | ||
| 2663 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); | ||
| 2664 | EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); | ||
| 2665 | EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); | ||
| 2666 | EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); | ||
| 2667 | EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); | ||
| 2668 | EXPORT_SYMBOL(snd_pcm_hw_rule_add); | ||
| 2669 | EXPORT_SYMBOL(snd_pcm_set_ops); | ||
| 2670 | EXPORT_SYMBOL(snd_pcm_set_sync); | ||
| 2671 | EXPORT_SYMBOL(snd_pcm_lib_ioctl); | ||
| 2672 | EXPORT_SYMBOL(snd_pcm_stop); | ||
| 2673 | EXPORT_SYMBOL(snd_pcm_period_elapsed); | ||
| 2674 | EXPORT_SYMBOL(snd_pcm_lib_write); | ||
| 2675 | EXPORT_SYMBOL(snd_pcm_lib_read); | ||
| 2676 | EXPORT_SYMBOL(snd_pcm_lib_writev); | ||
| 2677 | EXPORT_SYMBOL(snd_pcm_lib_readv); | 2127 | EXPORT_SYMBOL(snd_pcm_lib_readv); |
| 2678 | EXPORT_SYMBOL(snd_pcm_lib_buffer_bytes); | ||
| 2679 | EXPORT_SYMBOL(snd_pcm_lib_period_bytes); | ||
| 2680 | /* pcm_memory.c */ | ||
| 2681 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); | ||
| 2682 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); | ||
| 2683 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); | ||
| 2684 | EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); | ||
| 2685 | EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); | ||
| 2686 | EXPORT_SYMBOL(snd_pcm_lib_free_pages); | ||
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 428f8c169ee1..067d2056db9a 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c | |||
| @@ -126,6 +126,8 @@ int snd_pcm_lib_preallocate_free_for_all(struct snd_pcm *pcm) | |||
| 126 | return 0; | 126 | return 0; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); | ||
| 130 | |||
| 129 | #ifdef CONFIG_SND_VERBOSE_PROCFS | 131 | #ifdef CONFIG_SND_VERBOSE_PROCFS |
| 130 | /* | 132 | /* |
| 131 | * read callback for prealloc proc file | 133 | * read callback for prealloc proc file |
| @@ -191,9 +193,7 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) | |||
| 191 | struct snd_info_entry *entry; | 193 | struct snd_info_entry *entry; |
| 192 | 194 | ||
| 193 | if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) { | 195 | if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) { |
| 194 | entry->c.text.read_size = 64; | ||
| 195 | entry->c.text.read = snd_pcm_lib_preallocate_proc_read; | 196 | entry->c.text.read = snd_pcm_lib_preallocate_proc_read; |
| 196 | entry->c.text.write_size = 64; | ||
| 197 | entry->c.text.write = snd_pcm_lib_preallocate_proc_write; | 197 | entry->c.text.write = snd_pcm_lib_preallocate_proc_write; |
| 198 | entry->mode |= S_IWUSR; | 198 | entry->mode |= S_IWUSR; |
| 199 | entry->private_data = substream; | 199 | entry->private_data = substream; |
| @@ -253,6 +253,8 @@ int snd_pcm_lib_preallocate_pages(struct snd_pcm_substream *substream, | |||
| 253 | return snd_pcm_lib_preallocate_pages1(substream, size, max); | 253 | return snd_pcm_lib_preallocate_pages1(substream, size, max); |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); | ||
| 257 | |||
| 256 | /** | 258 | /** |
| 257 | * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams) | 259 | * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams) |
| 258 | * @pcm: the pcm instance | 260 | * @pcm: the pcm instance |
| @@ -280,6 +282,8 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, | |||
| 280 | return 0; | 282 | return 0; |
| 281 | } | 283 | } |
| 282 | 284 | ||
| 285 | EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); | ||
| 286 | |||
| 283 | /** | 287 | /** |
| 284 | * snd_pcm_sgbuf_ops_page - get the page struct at the given offset | 288 | * snd_pcm_sgbuf_ops_page - get the page struct at the given offset |
| 285 | * @substream: the pcm substream instance | 289 | * @substream: the pcm substream instance |
| @@ -298,6 +302,8 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigne | |||
| 298 | return sgbuf->page_table[idx]; | 302 | return sgbuf->page_table[idx]; |
| 299 | } | 303 | } |
| 300 | 304 | ||
| 305 | EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); | ||
| 306 | |||
| 301 | /** | 307 | /** |
| 302 | * snd_pcm_lib_malloc_pages - allocate the DMA buffer | 308 | * snd_pcm_lib_malloc_pages - allocate the DMA buffer |
| 303 | * @substream: the substream to allocate the DMA buffer to | 309 | * @substream: the substream to allocate the DMA buffer to |
| @@ -349,6 +355,8 @@ int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size) | |||
| 349 | return 1; /* area was changed */ | 355 | return 1; /* area was changed */ |
| 350 | } | 356 | } |
| 351 | 357 | ||
| 358 | EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); | ||
| 359 | |||
| 352 | /** | 360 | /** |
| 353 | * snd_pcm_lib_free_pages - release the allocated DMA buffer. | 361 | * snd_pcm_lib_free_pages - release the allocated DMA buffer. |
| 354 | * @substream: the substream to release the DMA buffer | 362 | * @substream: the substream to release the DMA buffer |
| @@ -374,3 +382,5 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) | |||
| 374 | snd_pcm_set_runtime_buffer(substream, NULL); | 382 | snd_pcm_set_runtime_buffer(substream, NULL); |
| 375 | return 0; | 383 | return 0; |
| 376 | } | 384 | } |
| 385 | |||
| 386 | EXPORT_SYMBOL(snd_pcm_lib_free_pages); | ||
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 593c77f4d181..0019c59a779d 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c | |||
| @@ -207,6 +207,8 @@ int snd_pcm_format_signed(snd_pcm_format_t format) | |||
| 207 | return val; | 207 | return val; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | EXPORT_SYMBOL(snd_pcm_format_signed); | ||
| 211 | |||
| 210 | /** | 212 | /** |
| 211 | * snd_pcm_format_unsigned - Check the PCM format is unsigned linear | 213 | * snd_pcm_format_unsigned - Check the PCM format is unsigned linear |
| 212 | * @format: the format to check | 214 | * @format: the format to check |
| @@ -224,6 +226,8 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format) | |||
| 224 | return !val; | 226 | return !val; |
| 225 | } | 227 | } |
| 226 | 228 | ||
| 229 | EXPORT_SYMBOL(snd_pcm_format_unsigned); | ||
| 230 | |||
| 227 | /** | 231 | /** |
| 228 | * snd_pcm_format_linear - Check the PCM format is linear | 232 | * snd_pcm_format_linear - Check the PCM format is linear |
| 229 | * @format: the format to check | 233 | * @format: the format to check |
| @@ -235,6 +239,8 @@ int snd_pcm_format_linear(snd_pcm_format_t format) | |||
| 235 | return snd_pcm_format_signed(format) >= 0; | 239 | return snd_pcm_format_signed(format) >= 0; |
| 236 | } | 240 | } |
| 237 | 241 | ||
| 242 | EXPORT_SYMBOL(snd_pcm_format_linear); | ||
| 243 | |||
| 238 | /** | 244 | /** |
| 239 | * snd_pcm_format_little_endian - Check the PCM format is little-endian | 245 | * snd_pcm_format_little_endian - Check the PCM format is little-endian |
| 240 | * @format: the format to check | 246 | * @format: the format to check |
| @@ -252,6 +258,8 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format) | |||
| 252 | return val; | 258 | return val; |
| 253 | } | 259 | } |
| 254 | 260 | ||
| 261 | EXPORT_SYMBOL(snd_pcm_format_little_endian); | ||
| 262 | |||
| 255 | /** | 263 | /** |
| 256 | * snd_pcm_format_big_endian - Check the PCM format is big-endian | 264 | * snd_pcm_format_big_endian - Check the PCM format is big-endian |
| 257 | * @format: the format to check | 265 | * @format: the format to check |
| @@ -269,6 +277,8 @@ int snd_pcm_format_big_endian(snd_pcm_format_t format) | |||
| 269 | return !val; | 277 | return !val; |
| 270 | } | 278 | } |
| 271 | 279 | ||
| 280 | EXPORT_SYMBOL(snd_pcm_format_big_endian); | ||
| 281 | |||
| 272 | /** | 282 | /** |
| 273 | * snd_pcm_format_width - return the bit-width of the format | 283 | * snd_pcm_format_width - return the bit-width of the format |
| 274 | * @format: the format to check | 284 | * @format: the format to check |
| @@ -286,6 +296,8 @@ int snd_pcm_format_width(snd_pcm_format_t format) | |||
| 286 | return val; | 296 | return val; |
| 287 | } | 297 | } |
| 288 | 298 | ||
| 299 | EXPORT_SYMBOL(snd_pcm_format_width); | ||
| 300 | |||
| 289 | /** | 301 | /** |
| 290 | * snd_pcm_format_physical_width - return the physical bit-width of the format | 302 | * snd_pcm_format_physical_width - return the physical bit-width of the format |
| 291 | * @format: the format to check | 303 | * @format: the format to check |
| @@ -303,6 +315,8 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format) | |||
| 303 | return val; | 315 | return val; |
| 304 | } | 316 | } |
| 305 | 317 | ||
| 318 | EXPORT_SYMBOL(snd_pcm_format_physical_width); | ||
| 319 | |||
| 306 | /** | 320 | /** |
| 307 | * snd_pcm_format_size - return the byte size of samples on the given format | 321 | * snd_pcm_format_size - return the byte size of samples on the given format |
| 308 | * @format: the format to check | 322 | * @format: the format to check |
| @@ -318,6 +332,8 @@ ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples) | |||
| 318 | return samples * phys_width / 8; | 332 | return samples * phys_width / 8; |
| 319 | } | 333 | } |
| 320 | 334 | ||
| 335 | EXPORT_SYMBOL(snd_pcm_format_size); | ||
| 336 | |||
| 321 | /** | 337 | /** |
| 322 | * snd_pcm_format_silence_64 - return the silent data in 8 bytes array | 338 | * snd_pcm_format_silence_64 - return the silent data in 8 bytes array |
| 323 | * @format: the format to check | 339 | * @format: the format to check |
| @@ -333,6 +349,8 @@ const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format) | |||
| 333 | return pcm_formats[format].silence; | 349 | return pcm_formats[format].silence; |
| 334 | } | 350 | } |
| 335 | 351 | ||
| 352 | EXPORT_SYMBOL(snd_pcm_format_silence_64); | ||
| 353 | |||
| 336 | /** | 354 | /** |
| 337 | * snd_pcm_format_set_silence - set the silence data on the buffer | 355 | * snd_pcm_format_set_silence - set the silence data on the buffer |
| 338 | * @format: the PCM format | 356 | * @format: the PCM format |
| @@ -402,6 +420,8 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int | |||
| 402 | return 0; | 420 | return 0; |
| 403 | } | 421 | } |
| 404 | 422 | ||
| 423 | EXPORT_SYMBOL(snd_pcm_format_set_silence); | ||
| 424 | |||
| 405 | /* [width][unsigned][bigendian] */ | 425 | /* [width][unsigned][bigendian] */ |
| 406 | static int linear_formats[4][2][2] = { | 426 | static int linear_formats[4][2][2] = { |
| 407 | {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8}, | 427 | {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8}, |
| @@ -432,6 +452,8 @@ snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_end | |||
| 432 | return linear_formats[width][!!unsignd][!!big_endian]; | 452 | return linear_formats[width][!!unsignd][!!big_endian]; |
| 433 | } | 453 | } |
| 434 | 454 | ||
| 455 | EXPORT_SYMBOL(snd_pcm_build_linear_format); | ||
| 456 | |||
| 435 | /** | 457 | /** |
| 436 | * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields | 458 | * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields |
| 437 | * @runtime: the runtime instance | 459 | * @runtime: the runtime instance |
| @@ -463,3 +485,5 @@ int snd_pcm_limit_hw_rates(struct snd_pcm_runtime *runtime) | |||
| 463 | } | 485 | } |
| 464 | return 0; | 486 | return 0; |
| 465 | } | 487 | } |
| 488 | |||
| 489 | EXPORT_SYMBOL(snd_pcm_limit_hw_rates); | ||
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 0860c5a84502..439f047929e1 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
| @@ -71,8 +71,9 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream); | |||
| 71 | */ | 71 | */ |
| 72 | 72 | ||
| 73 | DEFINE_RWLOCK(snd_pcm_link_rwlock); | 73 | DEFINE_RWLOCK(snd_pcm_link_rwlock); |
| 74 | static DECLARE_RWSEM(snd_pcm_link_rwsem); | 74 | EXPORT_SYMBOL(snd_pcm_link_rwlock); |
| 75 | 75 | ||
| 76 | static DECLARE_RWSEM(snd_pcm_link_rwsem); | ||
| 76 | 77 | ||
| 77 | static inline mm_segment_t snd_enter_user(void) | 78 | static inline mm_segment_t snd_enter_user(void) |
| 78 | { | 79 | { |
| @@ -319,6 +320,8 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream, | |||
| 319 | return 0; | 320 | return 0; |
| 320 | } | 321 | } |
| 321 | 322 | ||
| 323 | EXPORT_SYMBOL(snd_pcm_hw_refine); | ||
| 324 | |||
| 322 | static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, | 325 | static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, |
| 323 | struct snd_pcm_hw_params __user * _params) | 326 | struct snd_pcm_hw_params __user * _params) |
| 324 | { | 327 | { |
| @@ -369,7 +372,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
| 369 | #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) | 372 | #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) |
| 370 | if (!substream->oss.oss) | 373 | if (!substream->oss.oss) |
| 371 | #endif | 374 | #endif |
| 372 | if (atomic_read(&runtime->mmap_count)) | 375 | if (atomic_read(&substream->mmap_count)) |
| 373 | return -EBADFD; | 376 | return -EBADFD; |
| 374 | 377 | ||
| 375 | params->rmask = ~0U; | 378 | params->rmask = ~0U; |
| @@ -482,7 +485,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream) | |||
| 482 | return -EBADFD; | 485 | return -EBADFD; |
| 483 | } | 486 | } |
| 484 | snd_pcm_stream_unlock_irq(substream); | 487 | snd_pcm_stream_unlock_irq(substream); |
| 485 | if (atomic_read(&runtime->mmap_count)) | 488 | if (atomic_read(&substream->mmap_count)) |
| 486 | return -EBADFD; | 489 | return -EBADFD; |
| 487 | if (substream->ops->hw_free) | 490 | if (substream->ops->hw_free) |
| 488 | result = substream->ops->hw_free(substream); | 491 | result = substream->ops->hw_free(substream); |
| @@ -936,6 +939,8 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, int state) | |||
| 936 | return snd_pcm_action(&snd_pcm_action_stop, substream, state); | 939 | return snd_pcm_action(&snd_pcm_action_stop, substream, state); |
| 937 | } | 940 | } |
| 938 | 941 | ||
| 942 | EXPORT_SYMBOL(snd_pcm_stop); | ||
| 943 | |||
| 939 | /** | 944 | /** |
| 940 | * snd_pcm_drain_done | 945 | * snd_pcm_drain_done |
| 941 | * @substream: the PCM substream | 946 | * @substream: the PCM substream |
| @@ -1085,6 +1090,8 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream) | |||
| 1085 | return err; | 1090 | return err; |
| 1086 | } | 1091 | } |
| 1087 | 1092 | ||
| 1093 | EXPORT_SYMBOL(snd_pcm_suspend); | ||
| 1094 | |||
| 1088 | /** | 1095 | /** |
| 1089 | * snd_pcm_suspend_all | 1096 | * snd_pcm_suspend_all |
| 1090 | * @pcm: the PCM instance | 1097 | * @pcm: the PCM instance |
| @@ -1114,6 +1121,8 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm) | |||
| 1114 | return 0; | 1121 | return 0; |
| 1115 | } | 1122 | } |
| 1116 | 1123 | ||
| 1124 | EXPORT_SYMBOL(snd_pcm_suspend_all); | ||
| 1125 | |||
| 1117 | /* resume */ | 1126 | /* resume */ |
| 1118 | 1127 | ||
| 1119 | static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state) | 1128 | static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state) |
| @@ -1275,13 +1284,16 @@ static int snd_pcm_reset(struct snd_pcm_substream *substream) | |||
| 1275 | /* | 1284 | /* |
| 1276 | * prepare ioctl | 1285 | * prepare ioctl |
| 1277 | */ | 1286 | */ |
| 1278 | static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, int state) | 1287 | /* we use the second argument for updating f_flags */ |
| 1288 | static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, | ||
| 1289 | int f_flags) | ||
| 1279 | { | 1290 | { |
| 1280 | struct snd_pcm_runtime *runtime = substream->runtime; | 1291 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 1281 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | 1292 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
| 1282 | return -EBADFD; | 1293 | return -EBADFD; |
| 1283 | if (snd_pcm_running(substream)) | 1294 | if (snd_pcm_running(substream)) |
| 1284 | return -EBUSY; | 1295 | return -EBUSY; |
| 1296 | substream->f_flags = f_flags; | ||
| 1285 | return 0; | 1297 | return 0; |
| 1286 | } | 1298 | } |
| 1287 | 1299 | ||
| @@ -1310,17 +1322,26 @@ static struct action_ops snd_pcm_action_prepare = { | |||
| 1310 | /** | 1322 | /** |
| 1311 | * snd_pcm_prepare | 1323 | * snd_pcm_prepare |
| 1312 | * @substream: the PCM substream instance | 1324 | * @substream: the PCM substream instance |
| 1325 | * @file: file to refer f_flags | ||
| 1313 | * | 1326 | * |
| 1314 | * Prepare the PCM substream to be triggerable. | 1327 | * Prepare the PCM substream to be triggerable. |
| 1315 | */ | 1328 | */ |
| 1316 | static int snd_pcm_prepare(struct snd_pcm_substream *substream) | 1329 | static int snd_pcm_prepare(struct snd_pcm_substream *substream, |
| 1330 | struct file *file) | ||
| 1317 | { | 1331 | { |
| 1318 | int res; | 1332 | int res; |
| 1319 | struct snd_card *card = substream->pcm->card; | 1333 | struct snd_card *card = substream->pcm->card; |
| 1334 | int f_flags; | ||
| 1335 | |||
| 1336 | if (file) | ||
| 1337 | f_flags = file->f_flags; | ||
| 1338 | else | ||
| 1339 | f_flags = substream->f_flags; | ||
| 1320 | 1340 | ||
| 1321 | snd_power_lock(card); | 1341 | snd_power_lock(card); |
| 1322 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) | 1342 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) |
| 1323 | res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0); | 1343 | res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, |
| 1344 | substream, f_flags); | ||
| 1324 | snd_power_unlock(card); | 1345 | snd_power_unlock(card); |
| 1325 | return res; | 1346 | return res; |
| 1326 | } | 1347 | } |
| @@ -1331,7 +1352,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 1331 | 1352 | ||
| 1332 | static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) | 1353 | static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) |
| 1333 | { | 1354 | { |
| 1334 | if (substream->ffile->f_flags & O_NONBLOCK) | 1355 | if (substream->f_flags & O_NONBLOCK) |
| 1335 | return -EAGAIN; | 1356 | return -EAGAIN; |
| 1336 | substream->runtime->trigger_master = substream; | 1357 | substream->runtime->trigger_master = substream; |
| 1337 | return 0; | 1358 | return 0; |
| @@ -1448,8 +1469,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream) | |||
| 1448 | } | 1469 | } |
| 1449 | } | 1470 | } |
| 1450 | up_read(&snd_pcm_link_rwsem); | 1471 | up_read(&snd_pcm_link_rwsem); |
| 1451 | if (! num_drecs) | ||
| 1452 | goto _error; | ||
| 1453 | 1472 | ||
| 1454 | snd_pcm_stream_lock_irq(substream); | 1473 | snd_pcm_stream_lock_irq(substream); |
| 1455 | /* resume pause */ | 1474 | /* resume pause */ |
| @@ -2006,6 +2025,10 @@ static void pcm_release_private(struct snd_pcm_substream *substream) | |||
| 2006 | 2025 | ||
| 2007 | void snd_pcm_release_substream(struct snd_pcm_substream *substream) | 2026 | void snd_pcm_release_substream(struct snd_pcm_substream *substream) |
| 2008 | { | 2027 | { |
| 2028 | substream->ref_count--; | ||
| 2029 | if (substream->ref_count > 0) | ||
| 2030 | return; | ||
| 2031 | |||
| 2009 | snd_pcm_drop(substream); | 2032 | snd_pcm_drop(substream); |
| 2010 | if (substream->hw_opened) { | 2033 | if (substream->hw_opened) { |
| 2011 | if (substream->ops->hw_free != NULL) | 2034 | if (substream->ops->hw_free != NULL) |
| @@ -2020,6 +2043,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream) | |||
| 2020 | snd_pcm_detach_substream(substream); | 2043 | snd_pcm_detach_substream(substream); |
| 2021 | } | 2044 | } |
| 2022 | 2045 | ||
| 2046 | EXPORT_SYMBOL(snd_pcm_release_substream); | ||
| 2047 | |||
| 2023 | int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, | 2048 | int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, |
| 2024 | struct file *file, | 2049 | struct file *file, |
| 2025 | struct snd_pcm_substream **rsubstream) | 2050 | struct snd_pcm_substream **rsubstream) |
| @@ -2030,6 +2055,11 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, | |||
| 2030 | err = snd_pcm_attach_substream(pcm, stream, file, &substream); | 2055 | err = snd_pcm_attach_substream(pcm, stream, file, &substream); |
| 2031 | if (err < 0) | 2056 | if (err < 0) |
| 2032 | return err; | 2057 | return err; |
| 2058 | if (substream->ref_count > 1) { | ||
| 2059 | *rsubstream = substream; | ||
| 2060 | return 0; | ||
| 2061 | } | ||
| 2062 | |||
| 2033 | substream->no_mmap_ctrl = 0; | 2063 | substream->no_mmap_ctrl = 0; |
| 2034 | err = snd_pcm_hw_constraints_init(substream); | 2064 | err = snd_pcm_hw_constraints_init(substream); |
| 2035 | if (err < 0) { | 2065 | if (err < 0) { |
| @@ -2056,6 +2086,8 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, | |||
| 2056 | return err; | 2086 | return err; |
| 2057 | } | 2087 | } |
| 2058 | 2088 | ||
| 2089 | EXPORT_SYMBOL(snd_pcm_open_substream); | ||
| 2090 | |||
| 2059 | static int snd_pcm_open_file(struct file *file, | 2091 | static int snd_pcm_open_file(struct file *file, |
| 2060 | struct snd_pcm *pcm, | 2092 | struct snd_pcm *pcm, |
| 2061 | int stream, | 2093 | int stream, |
| @@ -2073,17 +2105,20 @@ static int snd_pcm_open_file(struct file *file, | |||
| 2073 | if (err < 0) | 2105 | if (err < 0) |
| 2074 | return err; | 2106 | return err; |
| 2075 | 2107 | ||
| 2076 | pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); | 2108 | if (substream->ref_count > 1) |
| 2077 | if (pcm_file == NULL) { | 2109 | pcm_file = substream->file; |
| 2078 | snd_pcm_release_substream(substream); | 2110 | else { |
| 2079 | return -ENOMEM; | 2111 | pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); |
| 2112 | if (pcm_file == NULL) { | ||
| 2113 | snd_pcm_release_substream(substream); | ||
| 2114 | return -ENOMEM; | ||
| 2115 | } | ||
| 2116 | str = substream->pstr; | ||
| 2117 | substream->file = pcm_file; | ||
| 2118 | substream->pcm_release = pcm_release_private; | ||
| 2119 | pcm_file->substream = substream; | ||
| 2120 | snd_pcm_add_file(str, pcm_file); | ||
| 2080 | } | 2121 | } |
| 2081 | str = substream->pstr; | ||
| 2082 | substream->file = pcm_file; | ||
| 2083 | substream->pcm_release = pcm_release_private; | ||
| 2084 | pcm_file->substream = substream; | ||
| 2085 | snd_pcm_add_file(str, pcm_file); | ||
| 2086 | |||
| 2087 | file->private_data = pcm_file; | 2122 | file->private_data = pcm_file; |
| 2088 | *rpcm_file = pcm_file; | 2123 | *rpcm_file = pcm_file; |
| 2089 | return 0; | 2124 | return 0; |
| @@ -2170,7 +2205,6 @@ static int snd_pcm_release(struct inode *inode, struct file *file) | |||
| 2170 | pcm_file = file->private_data; | 2205 | pcm_file = file->private_data; |
| 2171 | substream = pcm_file->substream; | 2206 | substream = pcm_file->substream; |
| 2172 | snd_assert(substream != NULL, return -ENXIO); | 2207 | snd_assert(substream != NULL, return -ENXIO); |
| 2173 | snd_assert(!atomic_read(&substream->runtime->mmap_count), ); | ||
| 2174 | pcm = substream->pcm; | 2208 | pcm = substream->pcm; |
| 2175 | fasync_helper(-1, file, 0, &substream->runtime->fasync); | 2209 | fasync_helper(-1, file, 0, &substream->runtime->fasync); |
| 2176 | mutex_lock(&pcm->open_mutex); | 2210 | mutex_lock(&pcm->open_mutex); |
| @@ -2493,7 +2527,8 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, | |||
| 2493 | return 0; | 2527 | return 0; |
| 2494 | } | 2528 | } |
| 2495 | 2529 | ||
| 2496 | static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, | 2530 | static int snd_pcm_common_ioctl1(struct file *file, |
| 2531 | struct snd_pcm_substream *substream, | ||
| 2497 | unsigned int cmd, void __user *arg) | 2532 | unsigned int cmd, void __user *arg) |
| 2498 | { | 2533 | { |
| 2499 | snd_assert(substream != NULL, return -ENXIO); | 2534 | snd_assert(substream != NULL, return -ENXIO); |
| @@ -2518,7 +2553,7 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, | |||
| 2518 | case SNDRV_PCM_IOCTL_CHANNEL_INFO: | 2553 | case SNDRV_PCM_IOCTL_CHANNEL_INFO: |
| 2519 | return snd_pcm_channel_info_user(substream, arg); | 2554 | return snd_pcm_channel_info_user(substream, arg); |
| 2520 | case SNDRV_PCM_IOCTL_PREPARE: | 2555 | case SNDRV_PCM_IOCTL_PREPARE: |
| 2521 | return snd_pcm_prepare(substream); | 2556 | return snd_pcm_prepare(substream, file); |
| 2522 | case SNDRV_PCM_IOCTL_RESET: | 2557 | case SNDRV_PCM_IOCTL_RESET: |
| 2523 | return snd_pcm_reset(substream); | 2558 | return snd_pcm_reset(substream); |
| 2524 | case SNDRV_PCM_IOCTL_START: | 2559 | case SNDRV_PCM_IOCTL_START: |
| @@ -2560,7 +2595,8 @@ static int snd_pcm_common_ioctl1(struct snd_pcm_substream *substream, | |||
| 2560 | return -ENOTTY; | 2595 | return -ENOTTY; |
| 2561 | } | 2596 | } |
| 2562 | 2597 | ||
| 2563 | static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream, | 2598 | static int snd_pcm_playback_ioctl1(struct file *file, |
| 2599 | struct snd_pcm_substream *substream, | ||
| 2564 | unsigned int cmd, void __user *arg) | 2600 | unsigned int cmd, void __user *arg) |
| 2565 | { | 2601 | { |
| 2566 | snd_assert(substream != NULL, return -ENXIO); | 2602 | snd_assert(substream != NULL, return -ENXIO); |
| @@ -2636,10 +2672,11 @@ static int snd_pcm_playback_ioctl1(struct snd_pcm_substream *substream, | |||
| 2636 | return result < 0 ? result : 0; | 2672 | return result < 0 ? result : 0; |
| 2637 | } | 2673 | } |
| 2638 | } | 2674 | } |
| 2639 | return snd_pcm_common_ioctl1(substream, cmd, arg); | 2675 | return snd_pcm_common_ioctl1(file, substream, cmd, arg); |
| 2640 | } | 2676 | } |
| 2641 | 2677 | ||
| 2642 | static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream, | 2678 | static int snd_pcm_capture_ioctl1(struct file *file, |
| 2679 | struct snd_pcm_substream *substream, | ||
| 2643 | unsigned int cmd, void __user *arg) | 2680 | unsigned int cmd, void __user *arg) |
| 2644 | { | 2681 | { |
| 2645 | snd_assert(substream != NULL, return -ENXIO); | 2682 | snd_assert(substream != NULL, return -ENXIO); |
| @@ -2715,7 +2752,7 @@ static int snd_pcm_capture_ioctl1(struct snd_pcm_substream *substream, | |||
| 2715 | return result < 0 ? result : 0; | 2752 | return result < 0 ? result : 0; |
| 2716 | } | 2753 | } |
| 2717 | } | 2754 | } |
| 2718 | return snd_pcm_common_ioctl1(substream, cmd, arg); | 2755 | return snd_pcm_common_ioctl1(file, substream, cmd, arg); |
| 2719 | } | 2756 | } |
| 2720 | 2757 | ||
| 2721 | static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, | 2758 | static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, |
| @@ -2728,7 +2765,8 @@ static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, | |||
| 2728 | if (((cmd >> 8) & 0xff) != 'A') | 2765 | if (((cmd >> 8) & 0xff) != 'A') |
| 2729 | return -ENOTTY; | 2766 | return -ENOTTY; |
| 2730 | 2767 | ||
| 2731 | return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg); | 2768 | return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd, |
| 2769 | (void __user *)arg); | ||
| 2732 | } | 2770 | } |
| 2733 | 2771 | ||
| 2734 | static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, | 2772 | static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, |
| @@ -2741,7 +2779,8 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, | |||
| 2741 | if (((cmd >> 8) & 0xff) != 'A') | 2779 | if (((cmd >> 8) & 0xff) != 'A') |
| 2742 | return -ENOTTY; | 2780 | return -ENOTTY; |
| 2743 | 2781 | ||
| 2744 | return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg); | 2782 | return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd, |
| 2783 | (void __user *)arg); | ||
| 2745 | } | 2784 | } |
| 2746 | 2785 | ||
| 2747 | int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, | 2786 | int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, |
| @@ -2753,12 +2792,12 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, | |||
| 2753 | fs = snd_enter_user(); | 2792 | fs = snd_enter_user(); |
| 2754 | switch (substream->stream) { | 2793 | switch (substream->stream) { |
| 2755 | case SNDRV_PCM_STREAM_PLAYBACK: | 2794 | case SNDRV_PCM_STREAM_PLAYBACK: |
| 2756 | result = snd_pcm_playback_ioctl1(substream, | 2795 | result = snd_pcm_playback_ioctl1(NULL, substream, cmd, |
| 2757 | cmd, (void __user *)arg); | 2796 | (void __user *)arg); |
| 2758 | break; | 2797 | break; |
| 2759 | case SNDRV_PCM_STREAM_CAPTURE: | 2798 | case SNDRV_PCM_STREAM_CAPTURE: |
| 2760 | result = snd_pcm_capture_ioctl1(substream, | 2799 | result = snd_pcm_capture_ioctl1(NULL, substream, cmd, |
| 2761 | cmd, (void __user *)arg); | 2800 | (void __user *)arg); |
| 2762 | break; | 2801 | break; |
| 2763 | default: | 2802 | default: |
| 2764 | result = -EINVAL; | 2803 | result = -EINVAL; |
| @@ -2768,6 +2807,8 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, | |||
| 2768 | return result; | 2807 | return result; |
| 2769 | } | 2808 | } |
| 2770 | 2809 | ||
| 2810 | EXPORT_SYMBOL(snd_pcm_kernel_ioctl); | ||
| 2811 | |||
| 2771 | static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, | 2812 | static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, |
| 2772 | loff_t * offset) | 2813 | loff_t * offset) |
| 2773 | { | 2814 | { |
| @@ -3134,7 +3175,7 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, | |||
| 3134 | area->vm_ops = &snd_pcm_vm_ops_data; | 3175 | area->vm_ops = &snd_pcm_vm_ops_data; |
| 3135 | area->vm_private_data = substream; | 3176 | area->vm_private_data = substream; |
| 3136 | area->vm_flags |= VM_RESERVED; | 3177 | area->vm_flags |= VM_RESERVED; |
| 3137 | atomic_inc(&substream->runtime->mmap_count); | 3178 | atomic_inc(&substream->mmap_count); |
| 3138 | return 0; | 3179 | return 0; |
| 3139 | } | 3180 | } |
| 3140 | 3181 | ||
| @@ -3166,9 +3207,11 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, | |||
| 3166 | (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, | 3207 | (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, |
| 3167 | size, area->vm_page_prot)) | 3208 | size, area->vm_page_prot)) |
| 3168 | return -EAGAIN; | 3209 | return -EAGAIN; |
| 3169 | atomic_inc(&substream->runtime->mmap_count); | 3210 | atomic_inc(&substream->mmap_count); |
| 3170 | return 0; | 3211 | return 0; |
| 3171 | } | 3212 | } |
| 3213 | |||
| 3214 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); | ||
| 3172 | #endif /* SNDRV_PCM_INFO_MMAP */ | 3215 | #endif /* SNDRV_PCM_INFO_MMAP */ |
| 3173 | 3216 | ||
| 3174 | /* | 3217 | /* |
| @@ -3212,6 +3255,8 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, | |||
| 3212 | return snd_pcm_default_mmap(substream, area); | 3255 | return snd_pcm_default_mmap(substream, area); |
| 3213 | } | 3256 | } |
| 3214 | 3257 | ||
| 3258 | EXPORT_SYMBOL(snd_pcm_mmap_data); | ||
| 3259 | |||
| 3215 | static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) | 3260 | static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) |
| 3216 | { | 3261 | { |
| 3217 | struct snd_pcm_file * pcm_file; | 3262 | struct snd_pcm_file * pcm_file; |
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 87b47c9564f7..8c15c66eb4aa 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c | |||
| @@ -43,7 +43,7 @@ MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA."); | |||
| 43 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
| 44 | 44 | ||
| 45 | #ifdef CONFIG_SND_OSSEMUL | 45 | #ifdef CONFIG_SND_OSSEMUL |
| 46 | static int midi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0}; | 46 | static int midi_map[SNDRV_CARDS]; |
| 47 | static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; | 47 | static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; |
| 48 | module_param_array(midi_map, int, NULL, 0444); | 48 | module_param_array(midi_map, int, NULL, 0444); |
| 49 | MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device."); | 49 | MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device."); |
| @@ -1561,7 +1561,6 @@ static int snd_rawmidi_dev_register(struct snd_device *device) | |||
| 1561 | entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root); | 1561 | entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root); |
| 1562 | if (entry) { | 1562 | if (entry) { |
| 1563 | entry->private_data = rmidi; | 1563 | entry->private_data = rmidi; |
| 1564 | entry->c.text.read_size = 1024; | ||
| 1565 | entry->c.text.read = snd_rawmidi_proc_info_read; | 1564 | entry->c.text.read = snd_rawmidi_proc_info_read; |
| 1566 | if (snd_info_register(entry) < 0) { | 1565 | if (snd_info_register(entry) < 0) { |
| 1567 | snd_info_free_entry(entry); | 1566 | snd_info_free_entry(entry); |
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index b9919785180b..e7234135641c 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c | |||
| @@ -291,7 +291,6 @@ register_proc(void) | |||
| 291 | 291 | ||
| 292 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 292 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 293 | entry->private_data = NULL; | 293 | entry->private_data = NULL; |
| 294 | entry->c.text.read_size = 1024; | ||
| 295 | entry->c.text.read = info_read; | 294 | entry->c.text.read = info_read; |
| 296 | if (snd_info_register(entry) < 0) { | 295 | if (snd_info_register(entry) < 0) { |
| 297 | snd_info_free_entry(entry); | 296 | snd_info_free_entry(entry); |
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index 20f954bc7aa0..2f0d8773ac6b 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c | |||
| @@ -129,25 +129,3 @@ static void __exit alsa_seq_exit(void) | |||
| 129 | 129 | ||
| 130 | module_init(alsa_seq_init) | 130 | module_init(alsa_seq_init) |
| 131 | module_exit(alsa_seq_exit) | 131 | module_exit(alsa_seq_exit) |
| 132 | |||
| 133 | /* seq_clientmgr.c */ | ||
| 134 | EXPORT_SYMBOL(snd_seq_create_kernel_client); | ||
| 135 | EXPORT_SYMBOL(snd_seq_delete_kernel_client); | ||
| 136 | EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); | ||
| 137 | EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking); | ||
| 138 | EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); | ||
| 139 | EXPORT_SYMBOL(snd_seq_kernel_client_ctl); | ||
| 140 | EXPORT_SYMBOL(snd_seq_kernel_client_write_poll); | ||
| 141 | EXPORT_SYMBOL(snd_seq_set_queue_tempo); | ||
| 142 | /* seq_memory.c */ | ||
| 143 | EXPORT_SYMBOL(snd_seq_expand_var_event); | ||
| 144 | EXPORT_SYMBOL(snd_seq_dump_var_event); | ||
| 145 | /* seq_ports.c */ | ||
| 146 | EXPORT_SYMBOL(snd_seq_event_port_attach); | ||
| 147 | EXPORT_SYMBOL(snd_seq_event_port_detach); | ||
| 148 | /* seq_lock.c */ | ||
| 149 | #if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG) | ||
| 150 | /*EXPORT_SYMBOL(snd_seq_sleep_in_lock);*/ | ||
| 151 | /*EXPORT_SYMBOL(snd_seq_sleep_timeout_in_lock);*/ | ||
| 152 | EXPORT_SYMBOL(snd_use_lock_sync_helper); | ||
| 153 | #endif | ||
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index bb15d9ee8842..532a660df51d 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c | |||
| @@ -1714,6 +1714,8 @@ int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo) | |||
| 1714 | return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo); | 1714 | return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo); |
| 1715 | } | 1715 | } |
| 1716 | 1716 | ||
| 1717 | EXPORT_SYMBOL(snd_seq_set_queue_tempo); | ||
| 1718 | |||
| 1717 | static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client, | 1719 | static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client, |
| 1718 | void __user *arg) | 1720 | void __user *arg) |
| 1719 | { | 1721 | { |
| @@ -2264,6 +2266,8 @@ int snd_seq_create_kernel_client(struct snd_card *card, int client_index, | |||
| 2264 | return client->number; | 2266 | return client->number; |
| 2265 | } | 2267 | } |
| 2266 | 2268 | ||
| 2269 | EXPORT_SYMBOL(snd_seq_create_kernel_client); | ||
| 2270 | |||
| 2267 | /* exported to kernel modules */ | 2271 | /* exported to kernel modules */ |
| 2268 | int snd_seq_delete_kernel_client(int client) | 2272 | int snd_seq_delete_kernel_client(int client) |
| 2269 | { | 2273 | { |
| @@ -2280,6 +2284,7 @@ int snd_seq_delete_kernel_client(int client) | |||
| 2280 | return 0; | 2284 | return 0; |
| 2281 | } | 2285 | } |
| 2282 | 2286 | ||
| 2287 | EXPORT_SYMBOL(snd_seq_delete_kernel_client); | ||
| 2283 | 2288 | ||
| 2284 | /* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue | 2289 | /* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue |
| 2285 | * and snd_seq_kernel_client_enqueue_blocking | 2290 | * and snd_seq_kernel_client_enqueue_blocking |
| @@ -2328,6 +2333,8 @@ int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event * ev, | |||
| 2328 | return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop); | 2333 | return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop); |
| 2329 | } | 2334 | } |
| 2330 | 2335 | ||
| 2336 | EXPORT_SYMBOL(snd_seq_kernel_client_enqueue); | ||
| 2337 | |||
| 2331 | /* | 2338 | /* |
| 2332 | * exported, called by kernel clients to enqueue events (with blocking) | 2339 | * exported, called by kernel clients to enqueue events (with blocking) |
| 2333 | * | 2340 | * |
| @@ -2340,6 +2347,7 @@ int snd_seq_kernel_client_enqueue_blocking(int client, struct snd_seq_event * ev | |||
| 2340 | return kernel_client_enqueue(client, ev, file, 1, atomic, hop); | 2347 | return kernel_client_enqueue(client, ev, file, 1, atomic, hop); |
| 2341 | } | 2348 | } |
| 2342 | 2349 | ||
| 2350 | EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking); | ||
| 2343 | 2351 | ||
| 2344 | /* | 2352 | /* |
| 2345 | * exported, called by kernel clients to dispatch events directly to other | 2353 | * exported, called by kernel clients to dispatch events directly to other |
| @@ -2376,6 +2384,7 @@ int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev, | |||
| 2376 | return result; | 2384 | return result; |
| 2377 | } | 2385 | } |
| 2378 | 2386 | ||
| 2387 | EXPORT_SYMBOL(snd_seq_kernel_client_dispatch); | ||
| 2379 | 2388 | ||
| 2380 | /* | 2389 | /* |
| 2381 | * exported, called by kernel clients to perform same functions as with | 2390 | * exported, called by kernel clients to perform same functions as with |
| @@ -2396,6 +2405,7 @@ int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg) | |||
| 2396 | return result; | 2405 | return result; |
| 2397 | } | 2406 | } |
| 2398 | 2407 | ||
| 2408 | EXPORT_SYMBOL(snd_seq_kernel_client_ctl); | ||
| 2399 | 2409 | ||
| 2400 | /* exported (for OSS emulator) */ | 2410 | /* exported (for OSS emulator) */ |
| 2401 | int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait) | 2411 | int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait) |
| @@ -2413,6 +2423,8 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table | |||
| 2413 | return 0; | 2423 | return 0; |
| 2414 | } | 2424 | } |
| 2415 | 2425 | ||
| 2426 | EXPORT_SYMBOL(snd_seq_kernel_client_write_poll); | ||
| 2427 | |||
| 2416 | /*---------------------------------------------------------------------------*/ | 2428 | /*---------------------------------------------------------------------------*/ |
| 2417 | 2429 | ||
| 2418 | #ifdef CONFIG_PROC_FS | 2430 | #ifdef CONFIG_PROC_FS |
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index d9a3e5a18d6a..d812dc886360 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c | |||
| @@ -80,7 +80,7 @@ static LIST_HEAD(opslist); | |||
| 80 | static int num_ops; | 80 | static int num_ops; |
| 81 | static DEFINE_MUTEX(ops_mutex); | 81 | static DEFINE_MUTEX(ops_mutex); |
| 82 | #ifdef CONFIG_PROC_FS | 82 | #ifdef CONFIG_PROC_FS |
| 83 | static struct snd_info_entry *info_entry = NULL; | 83 | static struct snd_info_entry *info_entry; |
| 84 | #endif | 84 | #endif |
| 85 | 85 | ||
| 86 | /* | 86 | /* |
| @@ -555,7 +555,6 @@ static int __init alsa_seq_device_init(void) | |||
| 555 | if (info_entry == NULL) | 555 | if (info_entry == NULL) |
| 556 | return -ENOMEM; | 556 | return -ENOMEM; |
| 557 | info_entry->content = SNDRV_INFO_CONTENT_TEXT; | 557 | info_entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 558 | info_entry->c.text.read_size = 2048; | ||
| 559 | info_entry->c.text.read = snd_seq_device_info; | 558 | info_entry->c.text.read = snd_seq_device_info; |
| 560 | if (snd_info_register(info_entry) < 0) { | 559 | if (snd_info_register(info_entry) < 0) { |
| 561 | snd_info_free_entry(info_entry); | 560 | snd_info_free_entry(info_entry); |
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index 2a283a59ea4d..e55488d1237c 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c | |||
| @@ -66,7 +66,7 @@ MODULE_LICENSE("GPL"); | |||
| 66 | MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY)); | 66 | MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY)); |
| 67 | 67 | ||
| 68 | static int ports = 1; | 68 | static int ports = 1; |
| 69 | static int duplex = 0; | 69 | static int duplex; |
| 70 | 70 | ||
| 71 | module_param(ports, int, 0444); | 71 | module_param(ports, int, 0444); |
| 72 | MODULE_PARM_DESC(ports, "number of ports to be created"); | 72 | MODULE_PARM_DESC(ports, "number of ports to be created"); |
| @@ -171,7 +171,9 @@ create_port(int idx, int type) | |||
| 171 | pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; | 171 | pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; |
| 172 | if (duplex) | 172 | if (duplex) |
| 173 | pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; | 173 | pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; |
| 174 | pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC; | 174 | pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
| 175 | | SNDRV_SEQ_PORT_TYPE_SOFTWARE | ||
| 176 | | SNDRV_SEQ_PORT_TYPE_PORT; | ||
| 175 | memset(&pcb, 0, sizeof(pcb)); | 177 | memset(&pcb, 0, sizeof(pcb)); |
| 176 | pcb.owner = THIS_MODULE; | 178 | pcb.owner = THIS_MODULE; |
| 177 | pcb.unuse = dummy_unuse; | 179 | pcb.unuse = dummy_unuse; |
diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c index acce21afdaa4..142e9e6882c9 100644 --- a/sound/core/seq/seq_info.c +++ b/sound/core/seq/seq_info.c | |||
| @@ -34,8 +34,8 @@ static struct snd_info_entry *timer_entry; | |||
| 34 | 34 | ||
| 35 | 35 | ||
| 36 | static struct snd_info_entry * __init | 36 | static struct snd_info_entry * __init |
| 37 | create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *, | 37 | create_info_entry(char *name, void (*read)(struct snd_info_entry *, |
| 38 | struct snd_info_buffer *)) | 38 | struct snd_info_buffer *)) |
| 39 | { | 39 | { |
| 40 | struct snd_info_entry *entry; | 40 | struct snd_info_entry *entry; |
| 41 | 41 | ||
| @@ -43,7 +43,6 @@ create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *, | |||
| 43 | if (entry == NULL) | 43 | if (entry == NULL) |
| 44 | return NULL; | 44 | return NULL; |
| 45 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 45 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 46 | entry->c.text.read_size = size; | ||
| 47 | entry->c.text.read = read; | 46 | entry->c.text.read = read; |
| 48 | if (snd_info_register(entry) < 0) { | 47 | if (snd_info_register(entry) < 0) { |
| 49 | snd_info_free_entry(entry); | 48 | snd_info_free_entry(entry); |
| @@ -55,11 +54,11 @@ create_info_entry(char *name, int size, void (*read)(struct snd_info_entry *, | |||
| 55 | /* create all our /proc entries */ | 54 | /* create all our /proc entries */ |
| 56 | int __init snd_seq_info_init(void) | 55 | int __init snd_seq_info_init(void) |
| 57 | { | 56 | { |
| 58 | queues_entry = create_info_entry("queues", 512 + (256 * SNDRV_SEQ_MAX_QUEUES), | 57 | queues_entry = create_info_entry("queues", |
| 59 | snd_seq_info_queues_read); | 58 | snd_seq_info_queues_read); |
| 60 | clients_entry = create_info_entry("clients", 512 + (256 * SNDRV_SEQ_MAX_CLIENTS), | 59 | clients_entry = create_info_entry("clients", |
| 61 | snd_seq_info_clients_read); | 60 | snd_seq_info_clients_read); |
| 62 | timer_entry = create_info_entry("timer", 1024, snd_seq_info_timer_read); | 61 | timer_entry = create_info_entry("timer", snd_seq_info_timer_read); |
| 63 | return 0; | 62 | return 0; |
| 64 | } | 63 | } |
| 65 | 64 | ||
diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c index a837a94b2d2a..1a34941d4217 100644 --- a/sound/core/seq/seq_lock.c +++ b/sound/core/seq/seq_lock.c | |||
| @@ -44,4 +44,6 @@ void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line) | |||
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | EXPORT_SYMBOL(snd_use_lock_sync_helper); | ||
| 48 | |||
| 47 | #endif | 49 | #endif |
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index 40b4f679c80e..4bffe509f719 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c | |||
| @@ -118,6 +118,8 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event, | |||
| 118 | return 0; | 118 | return 0; |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | EXPORT_SYMBOL(snd_seq_dump_var_event); | ||
| 122 | |||
| 121 | 123 | ||
| 122 | /* | 124 | /* |
| 123 | * exported: | 125 | * exported: |
| @@ -167,6 +169,7 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char | |||
| 167 | return err < 0 ? err : newlen; | 169 | return err < 0 ? err : newlen; |
| 168 | } | 170 | } |
| 169 | 171 | ||
| 172 | EXPORT_SYMBOL(snd_seq_expand_var_event); | ||
| 170 | 173 | ||
| 171 | /* | 174 | /* |
| 172 | * release this cell, free extended data if available | 175 | * release this cell, free extended data if available |
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 9caa1372bece..1daa5b069c79 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c | |||
| @@ -278,6 +278,7 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) | |||
| 278 | struct seq_midisynth *msynth, *ms; | 278 | struct seq_midisynth *msynth, *ms; |
| 279 | struct snd_seq_port_info *port; | 279 | struct snd_seq_port_info *port; |
| 280 | struct snd_rawmidi_info *info; | 280 | struct snd_rawmidi_info *info; |
| 281 | struct snd_rawmidi *rmidi = dev->private_data; | ||
| 281 | int newclient = 0; | 282 | int newclient = 0; |
| 282 | unsigned int p, ports; | 283 | unsigned int p, ports; |
| 283 | struct snd_seq_port_callback pcallbacks; | 284 | struct snd_seq_port_callback pcallbacks; |
| @@ -320,8 +321,8 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) | |||
| 320 | } | 321 | } |
| 321 | client->seq_client = | 322 | client->seq_client = |
| 322 | snd_seq_create_kernel_client( | 323 | snd_seq_create_kernel_client( |
| 323 | card, 0, "%s", info->name[0] ? | 324 | card, 0, "%s", card->shortname[0] ? |
| 324 | (const char *)info->name : "External MIDI"); | 325 | (const char *)card->shortname : "External MIDI"); |
| 325 | if (client->seq_client < 0) { | 326 | if (client->seq_client < 0) { |
| 326 | kfree(client); | 327 | kfree(client); |
| 327 | mutex_unlock(®ister_mutex); | 328 | mutex_unlock(®ister_mutex); |
| @@ -376,7 +377,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) | |||
| 376 | if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) && | 377 | if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) && |
| 377 | info->flags & SNDRV_RAWMIDI_INFO_DUPLEX) | 378 | info->flags & SNDRV_RAWMIDI_INFO_DUPLEX) |
| 378 | port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; | 379 | port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; |
| 379 | port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC; | 380 | port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
| 381 | | SNDRV_SEQ_PORT_TYPE_HARDWARE | ||
| 382 | | SNDRV_SEQ_PORT_TYPE_PORT; | ||
| 380 | port->midi_channels = 16; | 383 | port->midi_channels = 16; |
| 381 | memset(&pcallbacks, 0, sizeof(pcallbacks)); | 384 | memset(&pcallbacks, 0, sizeof(pcallbacks)); |
| 382 | pcallbacks.owner = THIS_MODULE; | 385 | pcallbacks.owner = THIS_MODULE; |
| @@ -387,6 +390,8 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) | |||
| 387 | pcallbacks.unuse = midisynth_unuse; | 390 | pcallbacks.unuse = midisynth_unuse; |
| 388 | pcallbacks.event_input = event_process_midi; | 391 | pcallbacks.event_input = event_process_midi; |
| 389 | port->kernel = &pcallbacks; | 392 | port->kernel = &pcallbacks; |
| 393 | if (rmidi->ops && rmidi->ops->get_port_info) | ||
| 394 | rmidi->ops->get_port_info(rmidi, p, port); | ||
| 390 | if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0) | 395 | if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0) |
| 391 | goto __nomem; | 396 | goto __nomem; |
| 392 | ms->seq_client = client->seq_client; | 397 | ms->seq_client = client->seq_client; |
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 41e078c938cd..334579a9f268 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c | |||
| @@ -221,7 +221,6 @@ static void clear_subscriber_list(struct snd_seq_client *client, | |||
| 221 | { | 221 | { |
| 222 | struct list_head *p, *n; | 222 | struct list_head *p, *n; |
| 223 | 223 | ||
| 224 | down_write(&grp->list_mutex); | ||
| 225 | list_for_each_safe(p, n, &grp->list_head) { | 224 | list_for_each_safe(p, n, &grp->list_head) { |
| 226 | struct snd_seq_subscribers *subs; | 225 | struct snd_seq_subscribers *subs; |
| 227 | struct snd_seq_client *c; | 226 | struct snd_seq_client *c; |
| @@ -259,7 +258,6 @@ static void clear_subscriber_list(struct snd_seq_client *client, | |||
| 259 | snd_seq_client_unlock(c); | 258 | snd_seq_client_unlock(c); |
| 260 | } | 259 | } |
| 261 | } | 260 | } |
| 262 | up_write(&grp->list_mutex); | ||
| 263 | } | 261 | } |
| 264 | 262 | ||
| 265 | /* delete port data */ | 263 | /* delete port data */ |
| @@ -677,6 +675,7 @@ int snd_seq_event_port_attach(int client, | |||
| 677 | return ret; | 675 | return ret; |
| 678 | } | 676 | } |
| 679 | 677 | ||
| 678 | EXPORT_SYMBOL(snd_seq_event_port_attach); | ||
| 680 | 679 | ||
| 681 | /* | 680 | /* |
| 682 | * Detach the driver from a port. | 681 | * Detach the driver from a port. |
| @@ -696,3 +695,5 @@ int snd_seq_event_port_detach(int client, int port) | |||
| 696 | 695 | ||
| 697 | return err; | 696 | return err; |
| 698 | } | 697 | } |
| 698 | |||
| 699 | EXPORT_SYMBOL(snd_seq_event_port_detach); | ||
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index f4edec603b8f..0cfa06c6b81f 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c | |||
| @@ -390,7 +390,9 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev) | |||
| 390 | pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; | 390 | pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE; |
| 391 | pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ; | 391 | pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ; |
| 392 | pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; | 392 | pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; |
| 393 | pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC; | 393 | pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
| 394 | | SNDRV_SEQ_PORT_TYPE_SOFTWARE | ||
| 395 | | SNDRV_SEQ_PORT_TYPE_PORT; | ||
| 394 | pinfo->midi_channels = 16; | 396 | pinfo->midi_channels = 16; |
| 395 | memset(&pcallbacks, 0, sizeof(pcallbacks)); | 397 | memset(&pcallbacks, 0, sizeof(pcallbacks)); |
| 396 | pcallbacks.owner = THIS_MODULE; | 398 | pcallbacks.owner = THIS_MODULE; |
diff --git a/sound/core/sound.c b/sound/core/sound.c index 108e430b5036..cd862728346c 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
| @@ -39,6 +39,8 @@ | |||
| 39 | 39 | ||
| 40 | static int major = CONFIG_SND_MAJOR; | 40 | static int major = CONFIG_SND_MAJOR; |
| 41 | int snd_major; | 41 | int snd_major; |
| 42 | EXPORT_SYMBOL(snd_major); | ||
| 43 | |||
| 42 | static int cards_limit = 1; | 44 | static int cards_limit = 1; |
| 43 | static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO; | 45 | static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO; |
| 44 | 46 | ||
| @@ -60,6 +62,7 @@ MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); | |||
| 60 | * modules are loaded manually, this limit number increases, too. | 62 | * modules are loaded manually, this limit number increases, too. |
| 61 | */ | 63 | */ |
| 62 | int snd_ecards_limit; | 64 | int snd_ecards_limit; |
| 65 | EXPORT_SYMBOL(snd_ecards_limit); | ||
| 63 | 66 | ||
| 64 | static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; | 67 | static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; |
| 65 | static DEFINE_MUTEX(sound_mutex); | 68 | static DEFINE_MUTEX(sound_mutex); |
| @@ -78,20 +81,17 @@ extern struct class *sound_class; | |||
| 78 | */ | 81 | */ |
| 79 | void snd_request_card(int card) | 82 | void snd_request_card(int card) |
| 80 | { | 83 | { |
| 81 | int locked; | ||
| 82 | |||
| 83 | if (! current->fs->root) | 84 | if (! current->fs->root) |
| 84 | return; | 85 | return; |
| 85 | read_lock(&snd_card_rwlock); | 86 | if (snd_card_locked(card)) |
| 86 | locked = snd_cards_lock & (1 << card); | ||
| 87 | read_unlock(&snd_card_rwlock); | ||
| 88 | if (locked) | ||
| 89 | return; | 87 | return; |
| 90 | if (card < 0 || card >= cards_limit) | 88 | if (card < 0 || card >= cards_limit) |
| 91 | return; | 89 | return; |
| 92 | request_module("snd-card-%i", card); | 90 | request_module("snd-card-%i", card); |
| 93 | } | 91 | } |
| 94 | 92 | ||
| 93 | EXPORT_SYMBOL(snd_request_card); | ||
| 94 | |||
| 95 | static void snd_request_other(int minor) | 95 | static void snd_request_other(int minor) |
| 96 | { | 96 | { |
| 97 | char *str; | 97 | char *str; |
| @@ -133,6 +133,8 @@ void *snd_lookup_minor_data(unsigned int minor, int type) | |||
| 133 | return private_data; | 133 | return private_data; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | EXPORT_SYMBOL(snd_lookup_minor_data); | ||
| 137 | |||
| 136 | static int snd_open(struct inode *inode, struct file *file) | 138 | static int snd_open(struct inode *inode, struct file *file) |
| 137 | { | 139 | { |
| 138 | unsigned int minor = iminor(inode); | 140 | unsigned int minor = iminor(inode); |
| @@ -281,6 +283,8 @@ int snd_register_device(int type, struct snd_card *card, int dev, | |||
| 281 | return 0; | 283 | return 0; |
| 282 | } | 284 | } |
| 283 | 285 | ||
| 286 | EXPORT_SYMBOL(snd_register_device); | ||
| 287 | |||
| 284 | /** | 288 | /** |
| 285 | * snd_unregister_device - unregister the device on the given card | 289 | * snd_unregister_device - unregister the device on the given card |
| 286 | * @type: the device type, SNDRV_DEVICE_TYPE_XXX | 290 | * @type: the device type, SNDRV_DEVICE_TYPE_XXX |
| @@ -321,12 +325,14 @@ int snd_unregister_device(int type, struct snd_card *card, int dev) | |||
| 321 | return 0; | 325 | return 0; |
| 322 | } | 326 | } |
| 323 | 327 | ||
| 328 | EXPORT_SYMBOL(snd_unregister_device); | ||
| 329 | |||
| 324 | #ifdef CONFIG_PROC_FS | 330 | #ifdef CONFIG_PROC_FS |
| 325 | /* | 331 | /* |
| 326 | * INFO PART | 332 | * INFO PART |
| 327 | */ | 333 | */ |
| 328 | 334 | ||
| 329 | static struct snd_info_entry *snd_minor_info_entry = NULL; | 335 | static struct snd_info_entry *snd_minor_info_entry; |
| 330 | 336 | ||
| 331 | static const char *snd_device_type_name(int type) | 337 | static const char *snd_device_type_name(int type) |
| 332 | { | 338 | { |
| @@ -381,7 +387,6 @@ int __init snd_minor_info_init(void) | |||
| 381 | 387 | ||
| 382 | entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); | 388 | entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); |
| 383 | if (entry) { | 389 | if (entry) { |
| 384 | entry->c.text.read_size = PAGE_SIZE; | ||
| 385 | entry->c.text.read = snd_minor_info_read; | 390 | entry->c.text.read = snd_minor_info_read; |
| 386 | if (snd_info_register(entry) < 0) { | 391 | if (snd_info_register(entry) < 0) { |
| 387 | snd_info_free_entry(entry); | 392 | snd_info_free_entry(entry); |
| @@ -446,91 +451,3 @@ static void __exit alsa_sound_exit(void) | |||
| 446 | 451 | ||
| 447 | module_init(alsa_sound_init) | 452 | module_init(alsa_sound_init) |
| 448 | module_exit(alsa_sound_exit) | 453 | module_exit(alsa_sound_exit) |
| 449 | |||
| 450 | /* sound.c */ | ||
| 451 | EXPORT_SYMBOL(snd_major); | ||
| 452 | EXPORT_SYMBOL(snd_ecards_limit); | ||
| 453 | #if defined(CONFIG_KMOD) | ||
| 454 | EXPORT_SYMBOL(snd_request_card); | ||
| 455 | #endif | ||
| 456 | EXPORT_SYMBOL(snd_register_device); | ||
| 457 | EXPORT_SYMBOL(snd_unregister_device); | ||
| 458 | EXPORT_SYMBOL(snd_lookup_minor_data); | ||
| 459 | #if defined(CONFIG_SND_OSSEMUL) | ||
| 460 | EXPORT_SYMBOL(snd_register_oss_device); | ||
| 461 | EXPORT_SYMBOL(snd_unregister_oss_device); | ||
| 462 | EXPORT_SYMBOL(snd_lookup_oss_minor_data); | ||
| 463 | #endif | ||
| 464 | /* memory.c */ | ||
| 465 | EXPORT_SYMBOL(copy_to_user_fromio); | ||
| 466 | EXPORT_SYMBOL(copy_from_user_toio); | ||
| 467 | /* init.c */ | ||
| 468 | EXPORT_SYMBOL(snd_cards); | ||
| 469 | #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) | ||
| 470 | EXPORT_SYMBOL(snd_mixer_oss_notify_callback); | ||
| 471 | #endif | ||
| 472 | EXPORT_SYMBOL(snd_card_new); | ||
| 473 | EXPORT_SYMBOL(snd_card_disconnect); | ||
| 474 | EXPORT_SYMBOL(snd_card_free); | ||
| 475 | EXPORT_SYMBOL(snd_card_free_in_thread); | ||
| 476 | EXPORT_SYMBOL(snd_card_register); | ||
| 477 | EXPORT_SYMBOL(snd_component_add); | ||
| 478 | EXPORT_SYMBOL(snd_card_file_add); | ||
| 479 | EXPORT_SYMBOL(snd_card_file_remove); | ||
| 480 | #ifdef CONFIG_PM | ||
| 481 | EXPORT_SYMBOL(snd_power_wait); | ||
| 482 | #endif | ||
| 483 | /* device.c */ | ||
| 484 | EXPORT_SYMBOL(snd_device_new); | ||
| 485 | EXPORT_SYMBOL(snd_device_register); | ||
| 486 | EXPORT_SYMBOL(snd_device_free); | ||
| 487 | /* isadma.c */ | ||
| 488 | #ifdef CONFIG_ISA_DMA_API | ||
| 489 | EXPORT_SYMBOL(snd_dma_program); | ||
| 490 | EXPORT_SYMBOL(snd_dma_disable); | ||
| 491 | EXPORT_SYMBOL(snd_dma_pointer); | ||
| 492 | #endif | ||
| 493 | /* info.c */ | ||
| 494 | #ifdef CONFIG_PROC_FS | ||
| 495 | EXPORT_SYMBOL(snd_seq_root); | ||
| 496 | EXPORT_SYMBOL(snd_iprintf); | ||
| 497 | EXPORT_SYMBOL(snd_info_get_line); | ||
| 498 | EXPORT_SYMBOL(snd_info_get_str); | ||
| 499 | EXPORT_SYMBOL(snd_info_create_module_entry); | ||
| 500 | EXPORT_SYMBOL(snd_info_create_card_entry); | ||
| 501 | EXPORT_SYMBOL(snd_info_free_entry); | ||
| 502 | EXPORT_SYMBOL(snd_info_register); | ||
| 503 | EXPORT_SYMBOL(snd_info_unregister); | ||
| 504 | EXPORT_SYMBOL(snd_card_proc_new); | ||
| 505 | #endif | ||
| 506 | /* info_oss.c */ | ||
| 507 | #if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS) | ||
| 508 | EXPORT_SYMBOL(snd_oss_info_register); | ||
| 509 | #endif | ||
| 510 | /* control.c */ | ||
| 511 | EXPORT_SYMBOL(snd_ctl_new); | ||
| 512 | EXPORT_SYMBOL(snd_ctl_new1); | ||
| 513 | EXPORT_SYMBOL(snd_ctl_free_one); | ||
| 514 | EXPORT_SYMBOL(snd_ctl_add); | ||
| 515 | EXPORT_SYMBOL(snd_ctl_remove); | ||
| 516 | EXPORT_SYMBOL(snd_ctl_remove_id); | ||
| 517 | EXPORT_SYMBOL(snd_ctl_rename_id); | ||
| 518 | EXPORT_SYMBOL(snd_ctl_find_numid); | ||
| 519 | EXPORT_SYMBOL(snd_ctl_find_id); | ||
| 520 | EXPORT_SYMBOL(snd_ctl_notify); | ||
| 521 | EXPORT_SYMBOL(snd_ctl_register_ioctl); | ||
| 522 | EXPORT_SYMBOL(snd_ctl_unregister_ioctl); | ||
| 523 | #ifdef CONFIG_COMPAT | ||
| 524 | EXPORT_SYMBOL(snd_ctl_register_ioctl_compat); | ||
| 525 | EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat); | ||
| 526 | #endif | ||
| 527 | EXPORT_SYMBOL(snd_ctl_elem_read); | ||
| 528 | EXPORT_SYMBOL(snd_ctl_elem_write); | ||
| 529 | /* misc.c */ | ||
| 530 | EXPORT_SYMBOL(release_and_free_resource); | ||
| 531 | #ifdef CONFIG_SND_VERBOSE_PRINTK | ||
| 532 | EXPORT_SYMBOL(snd_verbose_printk); | ||
| 533 | #endif | ||
| 534 | #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) | ||
| 535 | EXPORT_SYMBOL(snd_verbose_printd); | ||
| 536 | #endif | ||
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c index 9055c6de9587..74f0fe5a1ba0 100644 --- a/sound/core/sound_oss.c +++ b/sound/core/sound_oss.c | |||
| @@ -58,6 +58,8 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type) | |||
| 58 | return private_data; | 58 | return private_data; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | EXPORT_SYMBOL(snd_lookup_oss_minor_data); | ||
| 62 | |||
| 61 | static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev) | 63 | static int snd_oss_kernel_minor(int type, struct snd_card *card, int dev) |
| 62 | { | 64 | { |
| 63 | int minor; | 65 | int minor; |
| @@ -158,6 +160,8 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, | |||
| 158 | return -EBUSY; | 160 | return -EBUSY; |
| 159 | } | 161 | } |
| 160 | 162 | ||
| 163 | EXPORT_SYMBOL(snd_register_oss_device); | ||
| 164 | |||
| 161 | int snd_unregister_oss_device(int type, struct snd_card *card, int dev) | 165 | int snd_unregister_oss_device(int type, struct snd_card *card, int dev) |
| 162 | { | 166 | { |
| 163 | int minor = snd_oss_kernel_minor(type, card, dev); | 167 | int minor = snd_oss_kernel_minor(type, card, dev); |
| @@ -197,13 +201,15 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev) | |||
| 197 | return 0; | 201 | return 0; |
| 198 | } | 202 | } |
| 199 | 203 | ||
| 204 | EXPORT_SYMBOL(snd_unregister_oss_device); | ||
| 205 | |||
| 200 | /* | 206 | /* |
| 201 | * INFO PART | 207 | * INFO PART |
| 202 | */ | 208 | */ |
| 203 | 209 | ||
| 204 | #ifdef CONFIG_PROC_FS | 210 | #ifdef CONFIG_PROC_FS |
| 205 | 211 | ||
| 206 | static struct snd_info_entry *snd_minor_info_oss_entry = NULL; | 212 | static struct snd_info_entry *snd_minor_info_oss_entry; |
| 207 | 213 | ||
| 208 | static const char *snd_oss_device_type_name(int type) | 214 | static const char *snd_oss_device_type_name(int type) |
| 209 | { | 215 | { |
| @@ -252,7 +258,6 @@ int __init snd_minor_info_oss_init(void) | |||
| 252 | 258 | ||
| 253 | entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root); | 259 | entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root); |
| 254 | if (entry) { | 260 | if (entry) { |
| 255 | entry->c.text.read_size = PAGE_SIZE; | ||
| 256 | entry->c.text.read = snd_minor_info_oss_read; | 261 | entry->c.text.read = snd_minor_info_oss_read; |
| 257 | if (snd_info_register(entry) < 0) { | 262 | if (snd_info_register(entry) < 0) { |
| 258 | snd_info_free_entry(entry); | 263 | snd_info_free_entry(entry); |
diff --git a/sound/core/timer.c b/sound/core/timer.c index cdeeb639b675..78199f58b93a 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
| @@ -1061,7 +1061,6 @@ static int snd_timer_register_system(void) | |||
| 1061 | static void snd_timer_proc_read(struct snd_info_entry *entry, | 1061 | static void snd_timer_proc_read(struct snd_info_entry *entry, |
| 1062 | struct snd_info_buffer *buffer) | 1062 | struct snd_info_buffer *buffer) |
| 1063 | { | 1063 | { |
| 1064 | unsigned long flags; | ||
| 1065 | struct snd_timer *timer; | 1064 | struct snd_timer *timer; |
| 1066 | struct snd_timer_instance *ti; | 1065 | struct snd_timer_instance *ti; |
| 1067 | struct list_head *p, *q; | 1066 | struct list_head *p, *q; |
| @@ -1095,7 +1094,6 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, | |||
| 1095 | if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) | 1094 | if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) |
| 1096 | snd_iprintf(buffer, " SLAVE"); | 1095 | snd_iprintf(buffer, " SLAVE"); |
| 1097 | snd_iprintf(buffer, "\n"); | 1096 | snd_iprintf(buffer, "\n"); |
| 1098 | spin_lock_irqsave(&timer->lock, flags); | ||
| 1099 | list_for_each(q, &timer->open_list_head) { | 1097 | list_for_each(q, &timer->open_list_head) { |
| 1100 | ti = list_entry(q, struct snd_timer_instance, open_list); | 1098 | ti = list_entry(q, struct snd_timer_instance, open_list); |
| 1101 | snd_iprintf(buffer, " Client %s : %s\n", | 1099 | snd_iprintf(buffer, " Client %s : %s\n", |
| @@ -1104,12 +1102,11 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, | |||
| 1104 | SNDRV_TIMER_IFLG_RUNNING) | 1102 | SNDRV_TIMER_IFLG_RUNNING) |
| 1105 | ? "running" : "stopped"); | 1103 | ? "running" : "stopped"); |
| 1106 | } | 1104 | } |
| 1107 | spin_unlock_irqrestore(&timer->lock, flags); | ||
| 1108 | } | 1105 | } |
| 1109 | mutex_unlock(®ister_mutex); | 1106 | mutex_unlock(®ister_mutex); |
| 1110 | } | 1107 | } |
| 1111 | 1108 | ||
| 1112 | static struct snd_info_entry *snd_timer_proc_entry = NULL; | 1109 | static struct snd_info_entry *snd_timer_proc_entry; |
| 1113 | 1110 | ||
| 1114 | static void __init snd_timer_proc_init(void) | 1111 | static void __init snd_timer_proc_init(void) |
| 1115 | { | 1112 | { |
| @@ -1117,7 +1114,6 @@ static void __init snd_timer_proc_init(void) | |||
| 1117 | 1114 | ||
| 1118 | entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL); | 1115 | entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL); |
| 1119 | if (entry != NULL) { | 1116 | if (entry != NULL) { |
| 1120 | entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128; | ||
| 1121 | entry->c.text.read = snd_timer_proc_read; | 1117 | entry->c.text.read = snd_timer_proc_read; |
| 1122 | if (snd_info_register(entry) < 0) { | 1118 | if (snd_info_register(entry) < 0) { |
| 1123 | snd_info_free_entry(entry); | 1119 | snd_info_free_entry(entry); |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index ae0df549fac7..ffeafaf2ecca 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
| @@ -677,6 +677,10 @@ static int __init alsa_card_dummy_init(void) | |||
| 677 | i, NULL, 0); | 677 | i, NULL, 0); |
| 678 | if (IS_ERR(device)) | 678 | if (IS_ERR(device)) |
| 679 | continue; | 679 | continue; |
| 680 | if (!platform_get_drvdata(device)) { | ||
| 681 | platform_device_unregister(device); | ||
| 682 | continue; | ||
| 683 | } | ||
| 680 | devices[i] = device; | 684 | devices[i] = device; |
| 681 | cards++; | 685 | cards++; |
| 682 | } | 686 | } |
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index 77b06009735d..d3cbbb047582 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c | |||
| @@ -253,6 +253,10 @@ static int __init alsa_card_mpu401_init(void) | |||
| 253 | i, NULL, 0); | 253 | i, NULL, 0); |
| 254 | if (IS_ERR(device)) | 254 | if (IS_ERR(device)) |
| 255 | continue; | 255 | continue; |
| 256 | if (!platform_get_drvdata(device)) { | ||
| 257 | platform_device_unregister(device); | ||
| 258 | continue; | ||
| 259 | } | ||
| 256 | platform_devices[i] = device; | 260 | platform_devices[i] = device; |
| 257 | snd_mpu401_devices++; | 261 | snd_mpu401_devices++; |
| 258 | } | 262 | } |
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index b49a45cbf67a..4bf07ca9b17d 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c | |||
| @@ -58,22 +58,26 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu); | |||
| 58 | #define MPU401_ACK 0xfe | 58 | #define MPU401_ACK 0xfe |
| 59 | 59 | ||
| 60 | /* Build in lowlevel io */ | 60 | /* Build in lowlevel io */ |
| 61 | static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data, unsigned long addr) | 61 | static void mpu401_write_port(struct snd_mpu401 *mpu, unsigned char data, |
| 62 | unsigned long addr) | ||
| 62 | { | 63 | { |
| 63 | outb(data, addr); | 64 | outb(data, addr); |
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | static unsigned char mpu401_read_port(struct snd_mpu401 *mpu, unsigned long addr) | 67 | static unsigned char mpu401_read_port(struct snd_mpu401 *mpu, |
| 68 | unsigned long addr) | ||
| 67 | { | 69 | { |
| 68 | return inb(addr); | 70 | return inb(addr); |
| 69 | } | 71 | } |
| 70 | 72 | ||
| 71 | static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data, unsigned long addr) | 73 | static void mpu401_write_mmio(struct snd_mpu401 *mpu, unsigned char data, |
| 74 | unsigned long addr) | ||
| 72 | { | 75 | { |
| 73 | writeb(data, (void __iomem *)addr); | 76 | writeb(data, (void __iomem *)addr); |
| 74 | } | 77 | } |
| 75 | 78 | ||
| 76 | static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu, unsigned long addr) | 79 | static unsigned char mpu401_read_mmio(struct snd_mpu401 *mpu, |
| 80 | unsigned long addr) | ||
| 77 | { | 81 | { |
| 78 | return readb((void __iomem *)addr); | 82 | return readb((void __iomem *)addr); |
| 79 | } | 83 | } |
| @@ -86,20 +90,13 @@ static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu) | |||
| 86 | mpu->read(mpu, MPU401D(mpu)); | 90 | mpu->read(mpu, MPU401D(mpu)); |
| 87 | #ifdef CONFIG_SND_DEBUG | 91 | #ifdef CONFIG_SND_DEBUG |
| 88 | if (timeout <= 0) | 92 | if (timeout <= 0) |
| 89 | snd_printk("cmd: clear rx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu))); | 93 | snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", |
| 94 | mpu->read(mpu, MPU401C(mpu))); | ||
| 90 | #endif | 95 | #endif |
| 91 | } | 96 | } |
| 92 | 97 | ||
| 93 | static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) | 98 | static void uart_interrupt_tx(struct snd_mpu401 *mpu) |
| 94 | { | 99 | { |
| 95 | spin_lock(&mpu->input_lock); | ||
| 96 | if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) { | ||
| 97 | snd_mpu401_uart_input_read(mpu); | ||
| 98 | } else { | ||
| 99 | snd_mpu401_uart_clear_rx(mpu); | ||
| 100 | } | ||
| 101 | spin_unlock(&mpu->input_lock); | ||
| 102 | /* ok. for better Tx performance try do some output when input is done */ | ||
| 103 | if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && | 100 | if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && |
| 104 | test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { | 101 | test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { |
| 105 | spin_lock(&mpu->output_lock); | 102 | spin_lock(&mpu->output_lock); |
| @@ -108,6 +105,22 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) | |||
| 108 | } | 105 | } |
| 109 | } | 106 | } |
| 110 | 107 | ||
| 108 | static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) | ||
| 109 | { | ||
| 110 | if (mpu->info_flags & MPU401_INFO_INPUT) { | ||
| 111 | spin_lock(&mpu->input_lock); | ||
| 112 | if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) | ||
| 113 | snd_mpu401_uart_input_read(mpu); | ||
| 114 | else | ||
| 115 | snd_mpu401_uart_clear_rx(mpu); | ||
| 116 | spin_unlock(&mpu->input_lock); | ||
| 117 | } | ||
| 118 | if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) | ||
| 119 | /* ok. for better Tx performance try do some output | ||
| 120 | when input is done */ | ||
| 121 | uart_interrupt_tx(mpu); | ||
| 122 | } | ||
| 123 | |||
| 111 | /** | 124 | /** |
| 112 | * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler | 125 | * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler |
| 113 | * @irq: the irq number | 126 | * @irq: the irq number |
| @@ -116,7 +129,8 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) | |||
| 116 | * | 129 | * |
| 117 | * Processes the interrupt for MPU401-UART i/o. | 130 | * Processes the interrupt for MPU401-UART i/o. |
| 118 | */ | 131 | */ |
| 119 | irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 132 | irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, |
| 133 | struct pt_regs *regs) | ||
| 120 | { | 134 | { |
| 121 | struct snd_mpu401 *mpu = dev_id; | 135 | struct snd_mpu401 *mpu = dev_id; |
| 122 | 136 | ||
| @@ -126,6 +140,29 @@ irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, struct pt_regs *reg | |||
| 126 | return IRQ_HANDLED; | 140 | return IRQ_HANDLED; |
| 127 | } | 141 | } |
| 128 | 142 | ||
| 143 | EXPORT_SYMBOL(snd_mpu401_uart_interrupt); | ||
| 144 | |||
| 145 | /** | ||
| 146 | * snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler | ||
| 147 | * @irq: the irq number | ||
| 148 | * @dev_id: mpu401 instance | ||
| 149 | * @regs: the reigster | ||
| 150 | * | ||
| 151 | * Processes the interrupt for MPU401-UART output. | ||
| 152 | */ | ||
| 153 | irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id, | ||
| 154 | struct pt_regs *regs) | ||
| 155 | { | ||
| 156 | struct snd_mpu401 *mpu = dev_id; | ||
| 157 | |||
| 158 | if (mpu == NULL) | ||
| 159 | return IRQ_NONE; | ||
| 160 | uart_interrupt_tx(mpu); | ||
| 161 | return IRQ_HANDLED; | ||
| 162 | } | ||
| 163 | |||
| 164 | EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx); | ||
| 165 | |||
| 129 | /* | 166 | /* |
| 130 | * timer callback | 167 | * timer callback |
| 131 | * reprogram the timer and call the interrupt job | 168 | * reprogram the timer and call the interrupt job |
| @@ -159,7 +196,8 @@ static void snd_mpu401_uart_add_timer (struct snd_mpu401 *mpu, int input) | |||
| 159 | mpu->timer.expires = 1 + jiffies; | 196 | mpu->timer.expires = 1 + jiffies; |
| 160 | add_timer(&mpu->timer); | 197 | add_timer(&mpu->timer); |
| 161 | } | 198 | } |
| 162 | mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : MPU401_MODE_OUTPUT_TIMER; | 199 | mpu->timer_invoked |= input ? MPU401_MODE_INPUT_TIMER : |
| 200 | MPU401_MODE_OUTPUT_TIMER; | ||
| 163 | spin_unlock_irqrestore (&mpu->timer_lock, flags); | 201 | spin_unlock_irqrestore (&mpu->timer_lock, flags); |
| 164 | } | 202 | } |
| 165 | 203 | ||
| @@ -172,7 +210,8 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input) | |||
| 172 | 210 | ||
| 173 | spin_lock_irqsave (&mpu->timer_lock, flags); | 211 | spin_lock_irqsave (&mpu->timer_lock, flags); |
| 174 | if (mpu->timer_invoked) { | 212 | if (mpu->timer_invoked) { |
| 175 | mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER : ~MPU401_MODE_OUTPUT_TIMER; | 213 | mpu->timer_invoked &= input ? ~MPU401_MODE_INPUT_TIMER : |
| 214 | ~MPU401_MODE_OUTPUT_TIMER; | ||
| 176 | if (! mpu->timer_invoked) | 215 | if (! mpu->timer_invoked) |
| 177 | del_timer(&mpu->timer); | 216 | del_timer(&mpu->timer); |
| 178 | } | 217 | } |
| @@ -180,11 +219,12 @@ static void snd_mpu401_uart_remove_timer (struct snd_mpu401 *mpu, int input) | |||
| 180 | } | 219 | } |
| 181 | 220 | ||
| 182 | /* | 221 | /* |
| 183 | 222 | * send a UART command | |
| 223 | * return zero if successful, non-zero for some errors | ||
| 184 | */ | 224 | */ |
| 185 | 225 | ||
| 186 | static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, | 226 | static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, |
| 187 | int ack) | 227 | int ack) |
| 188 | { | 228 | { |
| 189 | unsigned long flags; | 229 | unsigned long flags; |
| 190 | int timeout, ok; | 230 | int timeout, ok; |
| @@ -196,11 +236,13 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, | |||
| 196 | } | 236 | } |
| 197 | /* ok. standard MPU-401 initialization */ | 237 | /* ok. standard MPU-401 initialization */ |
| 198 | if (mpu->hardware != MPU401_HW_SB) { | 238 | if (mpu->hardware != MPU401_HW_SB) { |
| 199 | for (timeout = 1000; timeout > 0 && !snd_mpu401_output_ready(mpu); timeout--) | 239 | for (timeout = 1000; timeout > 0 && |
| 240 | !snd_mpu401_output_ready(mpu); timeout--) | ||
| 200 | udelay(10); | 241 | udelay(10); |
| 201 | #ifdef CONFIG_SND_DEBUG | 242 | #ifdef CONFIG_SND_DEBUG |
| 202 | if (!timeout) | 243 | if (!timeout) |
| 203 | snd_printk("cmd: tx timeout (status = 0x%x)\n", mpu->read(mpu, MPU401C(mpu))); | 244 | snd_printk(KERN_ERR "cmd: tx timeout (status = 0x%x)\n", |
| 245 | mpu->read(mpu, MPU401C(mpu))); | ||
| 204 | #endif | 246 | #endif |
| 205 | } | 247 | } |
| 206 | mpu->write(mpu, cmd, MPU401C(mpu)); | 248 | mpu->write(mpu, cmd, MPU401C(mpu)); |
| @@ -215,12 +257,14 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd, | |||
| 215 | } | 257 | } |
| 216 | if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK) | 258 | if (!ok && mpu->read(mpu, MPU401D(mpu)) == MPU401_ACK) |
| 217 | ok = 1; | 259 | ok = 1; |
| 218 | } else { | 260 | } else |
| 219 | ok = 1; | 261 | ok = 1; |
| 220 | } | ||
| 221 | spin_unlock_irqrestore(&mpu->input_lock, flags); | 262 | spin_unlock_irqrestore(&mpu->input_lock, flags); |
| 222 | if (!ok) { | 263 | if (!ok) { |
| 223 | snd_printk("cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n", cmd, mpu->port, mpu->read(mpu, MPU401C(mpu)), mpu->read(mpu, MPU401D(mpu))); | 264 | snd_printk(KERN_ERR "cmd: 0x%x failed at 0x%lx " |
| 265 | "(status = 0x%x, data = 0x%x)\n", cmd, mpu->port, | ||
| 266 | mpu->read(mpu, MPU401C(mpu)), | ||
| 267 | mpu->read(mpu, MPU401D(mpu))); | ||
| 224 | return 1; | 268 | return 1; |
| 225 | } | 269 | } |
| 226 | return 0; | 270 | return 0; |
| @@ -314,7 +358,8 @@ static int snd_mpu401_uart_output_close(struct snd_rawmidi_substream *substream) | |||
| 314 | /* | 358 | /* |
| 315 | * trigger input callback | 359 | * trigger input callback |
| 316 | */ | 360 | */ |
| 317 | static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) | 361 | static void |
| 362 | snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substream, int up) | ||
| 318 | { | 363 | { |
| 319 | unsigned long flags; | 364 | unsigned long flags; |
| 320 | struct snd_mpu401 *mpu; | 365 | struct snd_mpu401 *mpu; |
| @@ -322,7 +367,8 @@ static void snd_mpu401_uart_input_trigger(struct snd_rawmidi_substream *substrea | |||
| 322 | 367 | ||
| 323 | mpu = substream->rmidi->private_data; | 368 | mpu = substream->rmidi->private_data; |
| 324 | if (up) { | 369 | if (up) { |
| 325 | if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) { | 370 | if (! test_and_set_bit(MPU401_MODE_BIT_INPUT_TRIGGER, |
| 371 | &mpu->mode)) { | ||
| 326 | /* first time - flush FIFO */ | 372 | /* first time - flush FIFO */ |
| 327 | while (max-- > 0) | 373 | while (max-- > 0) |
| 328 | mpu->read(mpu, MPU401D(mpu)); | 374 | mpu->read(mpu, MPU401D(mpu)); |
| @@ -352,13 +398,11 @@ static void snd_mpu401_uart_input_read(struct snd_mpu401 * mpu) | |||
| 352 | unsigned char byte; | 398 | unsigned char byte; |
| 353 | 399 | ||
| 354 | while (max-- > 0) { | 400 | while (max-- > 0) { |
| 355 | if (snd_mpu401_input_avail(mpu)) { | 401 | if (! snd_mpu401_input_avail(mpu)) |
| 356 | byte = mpu->read(mpu, MPU401D(mpu)); | ||
| 357 | if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) | ||
| 358 | snd_rawmidi_receive(mpu->substream_input, &byte, 1); | ||
| 359 | } else { | ||
| 360 | break; /* input not available */ | 402 | break; /* input not available */ |
| 361 | } | 403 | byte = mpu->read(mpu, MPU401D(mpu)); |
| 404 | if (test_bit(MPU401_MODE_BIT_INPUT_TRIGGER, &mpu->mode)) | ||
| 405 | snd_rawmidi_receive(mpu->substream_input, &byte, 1); | ||
| 362 | } | 406 | } |
| 363 | } | 407 | } |
| 364 | 408 | ||
| @@ -380,16 +424,16 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu) | |||
| 380 | int max = 256, timeout; | 424 | int max = 256, timeout; |
| 381 | 425 | ||
| 382 | do { | 426 | do { |
| 383 | if (snd_rawmidi_transmit_peek(mpu->substream_output, &byte, 1) == 1) { | 427 | if (snd_rawmidi_transmit_peek(mpu->substream_output, |
| 428 | &byte, 1) == 1) { | ||
| 384 | for (timeout = 100; timeout > 0; timeout--) { | 429 | for (timeout = 100; timeout > 0; timeout--) { |
| 385 | if (snd_mpu401_output_ready(mpu)) { | 430 | if (snd_mpu401_output_ready(mpu)) |
| 386 | mpu->write(mpu, byte, MPU401D(mpu)); | ||
| 387 | snd_rawmidi_transmit_ack(mpu->substream_output, 1); | ||
| 388 | break; | 431 | break; |
| 389 | } | ||
| 390 | } | 432 | } |
| 391 | if (timeout == 0) | 433 | if (timeout == 0) |
| 392 | break; /* Tx FIFO full - try again later */ | 434 | break; /* Tx FIFO full - try again later */ |
| 435 | mpu->write(mpu, byte, MPU401D(mpu)); | ||
| 436 | snd_rawmidi_transmit_ack(mpu->substream_output, 1); | ||
| 393 | } else { | 437 | } else { |
| 394 | snd_mpu401_uart_remove_timer (mpu, 0); | 438 | snd_mpu401_uart_remove_timer (mpu, 0); |
| 395 | break; /* no other data - leave the tx loop */ | 439 | break; /* no other data - leave the tx loop */ |
| @@ -400,7 +444,8 @@ static void snd_mpu401_uart_output_write(struct snd_mpu401 * mpu) | |||
| 400 | /* | 444 | /* |
| 401 | * output trigger callback | 445 | * output trigger callback |
| 402 | */ | 446 | */ |
| 403 | static void snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) | 447 | static void |
| 448 | snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) | ||
| 404 | { | 449 | { |
| 405 | unsigned long flags; | 450 | unsigned long flags; |
| 406 | struct snd_mpu401 *mpu; | 451 | struct snd_mpu401 *mpu; |
| @@ -413,14 +458,16 @@ static void snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substre | |||
| 413 | * since the output timer might have been removed in | 458 | * since the output timer might have been removed in |
| 414 | * snd_mpu401_uart_output_write(). | 459 | * snd_mpu401_uart_output_write(). |
| 415 | */ | 460 | */ |
| 416 | snd_mpu401_uart_add_timer(mpu, 0); | 461 | if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) |
| 462 | snd_mpu401_uart_add_timer(mpu, 0); | ||
| 417 | 463 | ||
| 418 | /* output pending data */ | 464 | /* output pending data */ |
| 419 | spin_lock_irqsave(&mpu->output_lock, flags); | 465 | spin_lock_irqsave(&mpu->output_lock, flags); |
| 420 | snd_mpu401_uart_output_write(mpu); | 466 | snd_mpu401_uart_output_write(mpu); |
| 421 | spin_unlock_irqrestore(&mpu->output_lock, flags); | 467 | spin_unlock_irqrestore(&mpu->output_lock, flags); |
| 422 | } else { | 468 | } else { |
| 423 | snd_mpu401_uart_remove_timer(mpu, 0); | 469 | if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) |
| 470 | snd_mpu401_uart_remove_timer(mpu, 0); | ||
| 424 | clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); | 471 | clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); |
| 425 | } | 472 | } |
| 426 | } | 473 | } |
| @@ -458,7 +505,7 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) | |||
| 458 | * @device: the device index, zero-based | 505 | * @device: the device index, zero-based |
| 459 | * @hardware: the hardware type, MPU401_HW_XXXX | 506 | * @hardware: the hardware type, MPU401_HW_XXXX |
| 460 | * @port: the base address of MPU401 port | 507 | * @port: the base address of MPU401 port |
| 461 | * @integrated: non-zero if the port was already reserved by the chip | 508 | * @info_flags: bitflags MPU401_INFO_XXX |
| 462 | * @irq: the irq number, -1 if no interrupt for mpu | 509 | * @irq: the irq number, -1 if no interrupt for mpu |
| 463 | * @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved. | 510 | * @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved. |
| 464 | * @rrawmidi: the pointer to store the new rawmidi instance | 511 | * @rrawmidi: the pointer to store the new rawmidi instance |
| @@ -473,17 +520,24 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) | |||
| 473 | */ | 520 | */ |
| 474 | int snd_mpu401_uart_new(struct snd_card *card, int device, | 521 | int snd_mpu401_uart_new(struct snd_card *card, int device, |
| 475 | unsigned short hardware, | 522 | unsigned short hardware, |
| 476 | unsigned long port, int integrated, | 523 | unsigned long port, |
| 524 | unsigned int info_flags, | ||
| 477 | int irq, int irq_flags, | 525 | int irq, int irq_flags, |
| 478 | struct snd_rawmidi ** rrawmidi) | 526 | struct snd_rawmidi ** rrawmidi) |
| 479 | { | 527 | { |
| 480 | struct snd_mpu401 *mpu; | 528 | struct snd_mpu401 *mpu; |
| 481 | struct snd_rawmidi *rmidi; | 529 | struct snd_rawmidi *rmidi; |
| 530 | int in_enable, out_enable; | ||
| 482 | int err; | 531 | int err; |
| 483 | 532 | ||
| 484 | if (rrawmidi) | 533 | if (rrawmidi) |
| 485 | *rrawmidi = NULL; | 534 | *rrawmidi = NULL; |
| 486 | if ((err = snd_rawmidi_new(card, "MPU-401U", device, 1, 1, &rmidi)) < 0) | 535 | if (! (info_flags & (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT))) |
| 536 | info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT; | ||
| 537 | in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0; | ||
| 538 | out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0; | ||
| 539 | if ((err = snd_rawmidi_new(card, "MPU-401U", device, | ||
| 540 | out_enable, in_enable, &rmidi)) < 0) | ||
| 487 | return err; | 541 | return err; |
| 488 | mpu = kzalloc(sizeof(*mpu), GFP_KERNEL); | 542 | mpu = kzalloc(sizeof(*mpu), GFP_KERNEL); |
| 489 | if (mpu == NULL) { | 543 | if (mpu == NULL) { |
| @@ -497,23 +551,23 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, | |||
| 497 | spin_lock_init(&mpu->output_lock); | 551 | spin_lock_init(&mpu->output_lock); |
| 498 | spin_lock_init(&mpu->timer_lock); | 552 | spin_lock_init(&mpu->timer_lock); |
| 499 | mpu->hardware = hardware; | 553 | mpu->hardware = hardware; |
| 500 | if (!integrated) { | 554 | if (! (info_flags & MPU401_INFO_INTEGRATED)) { |
| 501 | int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; | 555 | int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; |
| 502 | if ((mpu->res = request_region(port, res_size, "MPU401 UART")) == NULL) { | 556 | mpu->res = request_region(port, res_size, "MPU401 UART"); |
| 503 | snd_printk(KERN_ERR "mpu401_uart: unable to grab port 0x%lx size %d\n", port, res_size); | 557 | if (mpu->res == NULL) { |
| 558 | snd_printk(KERN_ERR "mpu401_uart: " | ||
| 559 | "unable to grab port 0x%lx size %d\n", | ||
| 560 | port, res_size); | ||
| 504 | snd_device_free(card, rmidi); | 561 | snd_device_free(card, rmidi); |
| 505 | return -EBUSY; | 562 | return -EBUSY; |
| 506 | } | 563 | } |
| 507 | } | 564 | } |
| 508 | switch (hardware) { | 565 | if (info_flags & MPU401_INFO_MMIO) { |
| 509 | case MPU401_HW_AUREAL: | ||
| 510 | mpu->write = mpu401_write_mmio; | 566 | mpu->write = mpu401_write_mmio; |
| 511 | mpu->read = mpu401_read_mmio; | 567 | mpu->read = mpu401_read_mmio; |
| 512 | break; | 568 | } else { |
| 513 | default: | ||
| 514 | mpu->write = mpu401_write_port; | 569 | mpu->write = mpu401_write_port; |
| 515 | mpu->read = mpu401_read_port; | 570 | mpu->read = mpu401_read_port; |
| 516 | break; | ||
| 517 | } | 571 | } |
| 518 | mpu->port = port; | 572 | mpu->port = port; |
| 519 | if (hardware == MPU401_HW_PC98II) | 573 | if (hardware == MPU401_HW_PC98II) |
| @@ -521,30 +575,40 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, | |||
| 521 | else | 575 | else |
| 522 | mpu->cport = port + 1; | 576 | mpu->cport = port + 1; |
| 523 | if (irq >= 0 && irq_flags) { | 577 | if (irq >= 0 && irq_flags) { |
| 524 | if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags, "MPU401 UART", (void *) mpu)) { | 578 | if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags, |
| 525 | snd_printk(KERN_ERR "mpu401_uart: unable to grab IRQ %d\n", irq); | 579 | "MPU401 UART", (void *) mpu)) { |
| 580 | snd_printk(KERN_ERR "mpu401_uart: " | ||
| 581 | "unable to grab IRQ %d\n", irq); | ||
| 526 | snd_device_free(card, rmidi); | 582 | snd_device_free(card, rmidi); |
| 527 | return -EBUSY; | 583 | return -EBUSY; |
| 528 | } | 584 | } |
| 529 | } | 585 | } |
| 586 | mpu->info_flags = info_flags; | ||
| 530 | mpu->irq = irq; | 587 | mpu->irq = irq; |
| 531 | mpu->irq_flags = irq_flags; | 588 | mpu->irq_flags = irq_flags; |
| 532 | if (card->shortname[0]) | 589 | if (card->shortname[0]) |
| 533 | snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", card->shortname); | 590 | snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", |
| 591 | card->shortname); | ||
| 534 | else | 592 | else |
| 535 | sprintf(rmidi->name, "MPU-401 MIDI %d-%d", card->number, device); | 593 | sprintf(rmidi->name, "MPU-401 MIDI %d-%d",card->number, device); |
| 536 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mpu401_uart_output); | 594 | if (out_enable) { |
| 537 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mpu401_uart_input); | 595 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, |
| 538 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | | 596 | &snd_mpu401_uart_output); |
| 539 | SNDRV_RAWMIDI_INFO_INPUT | | 597 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; |
| 540 | SNDRV_RAWMIDI_INFO_DUPLEX; | 598 | } |
| 599 | if (in_enable) { | ||
| 600 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
| 601 | &snd_mpu401_uart_input); | ||
| 602 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; | ||
| 603 | if (out_enable) | ||
| 604 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; | ||
| 605 | } | ||
| 541 | mpu->rmidi = rmidi; | 606 | mpu->rmidi = rmidi; |
| 542 | if (rrawmidi) | 607 | if (rrawmidi) |
| 543 | *rrawmidi = rmidi; | 608 | *rrawmidi = rmidi; |
| 544 | return 0; | 609 | return 0; |
| 545 | } | 610 | } |
| 546 | 611 | ||
| 547 | EXPORT_SYMBOL(snd_mpu401_uart_interrupt); | ||
| 548 | EXPORT_SYMBOL(snd_mpu401_uart_new); | 612 | EXPORT_SYMBOL(snd_mpu401_uart_new); |
| 549 | 613 | ||
| 550 | /* | 614 | /* |
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index b7a0b42813e1..474eed06e70f 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c | |||
| @@ -770,11 +770,15 @@ static int __init alsa_card_mtpav_init(void) | |||
| 770 | return err; | 770 | return err; |
| 771 | 771 | ||
| 772 | device = platform_device_register_simple(SND_MTPAV_DRIVER, -1, NULL, 0); | 772 | device = platform_device_register_simple(SND_MTPAV_DRIVER, -1, NULL, 0); |
| 773 | if (IS_ERR(device)) { | 773 | if (!IS_ERR(device)) { |
| 774 | platform_driver_unregister(&snd_mtpav_driver); | 774 | if (platform_get_drvdata(device)) |
| 775 | return PTR_ERR(device); | 775 | return 0; |
| 776 | } | 776 | platform_device_unregister(device); |
| 777 | return 0; | 777 | err = -ENODEV; |
| 778 | } else | ||
| 779 | err = PTR_ERR(device); | ||
| 780 | platform_driver_unregister(&snd_mtpav_driver); | ||
| 781 | return err; | ||
| 778 | } | 782 | } |
| 779 | 783 | ||
| 780 | static void __exit alsa_card_mtpav_exit(void) | 784 | static void __exit alsa_card_mtpav_exit(void) |
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index 4f8556976774..87fe376f38f0 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c | |||
| @@ -316,6 +316,8 @@ void snd_opl3_interrupt(struct snd_hwdep * hw) | |||
| 316 | } | 316 | } |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | EXPORT_SYMBOL(snd_opl3_interrupt); | ||
| 320 | |||
| 319 | /* | 321 | /* |
| 320 | 322 | ||
| 321 | */ | 323 | */ |
| @@ -369,6 +371,8 @@ int snd_opl3_new(struct snd_card *card, | |||
| 369 | return 0; | 371 | return 0; |
| 370 | } | 372 | } |
| 371 | 373 | ||
| 374 | EXPORT_SYMBOL(snd_opl3_new); | ||
| 375 | |||
| 372 | int snd_opl3_init(struct snd_opl3 *opl3) | 376 | int snd_opl3_init(struct snd_opl3 *opl3) |
| 373 | { | 377 | { |
| 374 | if (! opl3->command) { | 378 | if (! opl3->command) { |
| @@ -393,6 +397,8 @@ int snd_opl3_init(struct snd_opl3 *opl3) | |||
| 393 | return 0; | 397 | return 0; |
| 394 | } | 398 | } |
| 395 | 399 | ||
| 400 | EXPORT_SYMBOL(snd_opl3_init); | ||
| 401 | |||
| 396 | int snd_opl3_create(struct snd_card *card, | 402 | int snd_opl3_create(struct snd_card *card, |
| 397 | unsigned long l_port, | 403 | unsigned long l_port, |
| 398 | unsigned long r_port, | 404 | unsigned long r_port, |
| @@ -451,6 +457,8 @@ int snd_opl3_create(struct snd_card *card, | |||
| 451 | return 0; | 457 | return 0; |
| 452 | } | 458 | } |
| 453 | 459 | ||
| 460 | EXPORT_SYMBOL(snd_opl3_create); | ||
| 461 | |||
| 454 | int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev) | 462 | int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev) |
| 455 | { | 463 | { |
| 456 | int err; | 464 | int err; |
| @@ -468,6 +476,8 @@ int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev) | |||
| 468 | return 0; | 476 | return 0; |
| 469 | } | 477 | } |
| 470 | 478 | ||
| 479 | EXPORT_SYMBOL(snd_opl3_timer_new); | ||
| 480 | |||
| 471 | int snd_opl3_hwdep_new(struct snd_opl3 * opl3, | 481 | int snd_opl3_hwdep_new(struct snd_opl3 * opl3, |
| 472 | int device, int seq_device, | 482 | int device, int seq_device, |
| 473 | struct snd_hwdep ** rhwdep) | 483 | struct snd_hwdep ** rhwdep) |
| @@ -526,17 +536,8 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, | |||
| 526 | return 0; | 536 | return 0; |
| 527 | } | 537 | } |
| 528 | 538 | ||
| 529 | EXPORT_SYMBOL(snd_opl3_interrupt); | ||
| 530 | EXPORT_SYMBOL(snd_opl3_new); | ||
| 531 | EXPORT_SYMBOL(snd_opl3_init); | ||
| 532 | EXPORT_SYMBOL(snd_opl3_create); | ||
| 533 | EXPORT_SYMBOL(snd_opl3_timer_new); | ||
| 534 | EXPORT_SYMBOL(snd_opl3_hwdep_new); | 539 | EXPORT_SYMBOL(snd_opl3_hwdep_new); |
| 535 | 540 | ||
| 536 | /* opl3_synth.c */ | ||
| 537 | EXPORT_SYMBOL(snd_opl3_regmap); | ||
| 538 | EXPORT_SYMBOL(snd_opl3_reset); | ||
| 539 | |||
| 540 | /* | 541 | /* |
| 541 | * INIT part | 542 | * INIT part |
| 542 | */ | 543 | */ |
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c index fccf019a6d85..5fd3a4c95626 100644 --- a/sound/drivers/opl3/opl3_oss.c +++ b/sound/drivers/opl3/opl3_oss.c | |||
| @@ -100,7 +100,8 @@ static int snd_opl3_oss_create_port(struct snd_opl3 * opl3) | |||
| 100 | SNDRV_SEQ_PORT_CAP_WRITE, | 100 | SNDRV_SEQ_PORT_CAP_WRITE, |
| 101 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | | 101 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | |
| 102 | SNDRV_SEQ_PORT_TYPE_MIDI_GM | | 102 | SNDRV_SEQ_PORT_TYPE_MIDI_GM | |
| 103 | SNDRV_SEQ_PORT_TYPE_SYNTH, | 103 | SNDRV_SEQ_PORT_TYPE_HARDWARE | |
| 104 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, | ||
| 104 | voices, voices, | 105 | voices, voices, |
| 105 | name); | 106 | name); |
| 106 | if (opl3->oss_chset->port < 0) { | 107 | if (opl3->oss_chset->port < 0) { |
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c index 57becf34f43e..96762c9d4855 100644 --- a/sound/drivers/opl3/opl3_seq.c +++ b/sound/drivers/opl3/opl3_seq.c | |||
| @@ -203,7 +203,9 @@ static int snd_opl3_synth_create_port(struct snd_opl3 * opl3) | |||
| 203 | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, | 203 | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, |
| 204 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | | 204 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | |
| 205 | SNDRV_SEQ_PORT_TYPE_MIDI_GM | | 205 | SNDRV_SEQ_PORT_TYPE_MIDI_GM | |
| 206 | SNDRV_SEQ_PORT_TYPE_SYNTH, | 206 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | |
| 207 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
| 208 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, | ||
| 207 | 16, voices, | 209 | 16, voices, |
| 208 | name); | 210 | name); |
| 209 | if (opl3->chset->port < 0) { | 211 | if (opl3->chset->port < 0) { |
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c index 6db503f025b3..a4b3543a7118 100644 --- a/sound/drivers/opl3/opl3_synth.c +++ b/sound/drivers/opl3/opl3_synth.c | |||
| @@ -58,6 +58,8 @@ char snd_opl3_regmap[MAX_OPL2_VOICES][4] = | |||
| 58 | { 0x12, 0x15, 0x00, 0x00 } /* is selected (only left reg block) */ | 58 | { 0x12, 0x15, 0x00, 0x00 } /* is selected (only left reg block) */ |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | EXPORT_SYMBOL(snd_opl3_regmap); | ||
| 62 | |||
| 61 | /* | 63 | /* |
| 62 | * prototypes | 64 | * prototypes |
| 63 | */ | 65 | */ |
| @@ -228,6 +230,7 @@ void snd_opl3_reset(struct snd_opl3 * opl3) | |||
| 228 | opl3->rhythm = 0; | 230 | opl3->rhythm = 0; |
| 229 | } | 231 | } |
| 230 | 232 | ||
| 233 | EXPORT_SYMBOL(snd_opl3_reset); | ||
| 231 | 234 | ||
| 232 | static int snd_opl3_play_note(struct snd_opl3 * opl3, struct snd_dm_fm_note * note) | 235 | static int snd_opl3_play_note(struct snd_opl3 * opl3, struct snd_dm_fm_note * note) |
| 233 | { | 236 | { |
| @@ -445,3 +448,4 @@ static int snd_opl3_set_connection(struct snd_opl3 * opl3, int connection) | |||
| 445 | 448 | ||
| 446 | return 0; | 449 | return 0; |
| 447 | } | 450 | } |
| 451 | |||
diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c index 4bc860ae02de..01997f24c895 100644 --- a/sound/drivers/opl4/opl4_lib.c +++ b/sound/drivers/opl4/opl4_lib.c | |||
| @@ -43,6 +43,8 @@ void snd_opl4_write(struct snd_opl4 *opl4, u8 reg, u8 value) | |||
| 43 | outb(value, opl4->pcm_port + 1); | 43 | outb(value, opl4->pcm_port + 1); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | EXPORT_SYMBOL(snd_opl4_write); | ||
| 47 | |||
| 46 | u8 snd_opl4_read(struct snd_opl4 *opl4, u8 reg) | 48 | u8 snd_opl4_read(struct snd_opl4 *opl4, u8 reg) |
| 47 | { | 49 | { |
| 48 | snd_opl4_wait(opl4); | 50 | snd_opl4_wait(opl4); |
| @@ -52,6 +54,8 @@ u8 snd_opl4_read(struct snd_opl4 *opl4, u8 reg) | |||
| 52 | return inb(opl4->pcm_port + 1); | 54 | return inb(opl4->pcm_port + 1); |
| 53 | } | 55 | } |
| 54 | 56 | ||
| 57 | EXPORT_SYMBOL(snd_opl4_read); | ||
| 58 | |||
| 55 | void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size) | 59 | void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size) |
| 56 | { | 60 | { |
| 57 | unsigned long flags; | 61 | unsigned long flags; |
| @@ -76,6 +80,8 @@ void snd_opl4_read_memory(struct snd_opl4 *opl4, char *buf, int offset, int size | |||
| 76 | spin_unlock_irqrestore(&opl4->reg_lock, flags); | 80 | spin_unlock_irqrestore(&opl4->reg_lock, flags); |
| 77 | } | 81 | } |
| 78 | 82 | ||
| 83 | EXPORT_SYMBOL(snd_opl4_read_memory); | ||
| 84 | |||
| 79 | void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, int size) | 85 | void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, int size) |
| 80 | { | 86 | { |
| 81 | unsigned long flags; | 87 | unsigned long flags; |
| @@ -100,6 +106,8 @@ void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, i | |||
| 100 | spin_unlock_irqrestore(&opl4->reg_lock, flags); | 106 | spin_unlock_irqrestore(&opl4->reg_lock, flags); |
| 101 | } | 107 | } |
| 102 | 108 | ||
| 109 | EXPORT_SYMBOL(snd_opl4_write_memory); | ||
| 110 | |||
| 103 | static void snd_opl4_enable_opl4(struct snd_opl4 *opl4) | 111 | static void snd_opl4_enable_opl4(struct snd_opl4 *opl4) |
| 104 | { | 112 | { |
| 105 | outb(OPL3_REG_MODE, opl4->fm_port + 2); | 113 | outb(OPL3_REG_MODE, opl4->fm_port + 2); |
| @@ -256,10 +264,6 @@ int snd_opl4_create(struct snd_card *card, | |||
| 256 | return 0; | 264 | return 0; |
| 257 | } | 265 | } |
| 258 | 266 | ||
| 259 | EXPORT_SYMBOL(snd_opl4_write); | ||
| 260 | EXPORT_SYMBOL(snd_opl4_read); | ||
| 261 | EXPORT_SYMBOL(snd_opl4_write_memory); | ||
| 262 | EXPORT_SYMBOL(snd_opl4_read_memory); | ||
| 263 | EXPORT_SYMBOL(snd_opl4_create); | 267 | EXPORT_SYMBOL(snd_opl4_create); |
| 264 | 268 | ||
| 265 | static int __init alsa_opl4_init(void) | 269 | static int __init alsa_opl4_init(void) |
diff --git a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c index dc0dcdc6c313..43d8a2bdd280 100644 --- a/sound/drivers/opl4/opl4_seq.c +++ b/sound/drivers/opl4/opl4_seq.c | |||
| @@ -164,7 +164,9 @@ static int snd_opl4_seq_new_device(struct snd_seq_device *dev) | |||
| 164 | SNDRV_SEQ_PORT_CAP_WRITE | | 164 | SNDRV_SEQ_PORT_CAP_WRITE | |
| 165 | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, | 165 | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, |
| 166 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | | 166 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | |
| 167 | SNDRV_SEQ_PORT_TYPE_MIDI_GM, | 167 | SNDRV_SEQ_PORT_TYPE_MIDI_GM | |
| 168 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
| 169 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, | ||
| 168 | 16, 24, | 170 | 16, 24, |
| 169 | "OPL4 Wavetable Port"); | 171 | "OPL4 Wavetable Port"); |
| 170 | if (opl4->chset->port < 0) { | 172 | if (opl4->chset->port < 0) { |
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index c01b4c5118b9..2330fec505da 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c | |||
| @@ -998,6 +998,10 @@ static int __init alsa_card_serial_init(void) | |||
| 998 | i, NULL, 0); | 998 | i, NULL, 0); |
| 999 | if (IS_ERR(device)) | 999 | if (IS_ERR(device)) |
| 1000 | continue; | 1000 | continue; |
| 1001 | if (!platform_get_drvdata(device)) { | ||
| 1002 | platform_device_unregister(device); | ||
| 1003 | continue; | ||
| 1004 | } | ||
| 1001 | devices[i] = device; | 1005 | devices[i] = device; |
| 1002 | cards++; | 1006 | cards++; |
| 1003 | } | 1007 | } |
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 26eb2499d442..59171f8200df 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c | |||
| @@ -171,6 +171,10 @@ static int __init alsa_card_virmidi_init(void) | |||
| 171 | i, NULL, 0); | 171 | i, NULL, 0); |
| 172 | if (IS_ERR(device)) | 172 | if (IS_ERR(device)) |
| 173 | continue; | 173 | continue; |
| 174 | if (!platform_get_drvdata(device)) { | ||
| 175 | platform_device_unregister(device); | ||
| 176 | continue; | ||
| 177 | } | ||
| 174 | devices[i] = device; | 178 | devices[i] = device; |
| 175 | cards++; | 179 | cards++; |
| 176 | } | 180 | } |
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index fa4a2b5c2d8d..a60168268ddd 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c | |||
| @@ -70,6 +70,8 @@ int snd_vx_check_reg_bit(struct vx_core *chip, int reg, int mask, int bit, int t | |||
| 70 | return -EIO; | 70 | return -EIO; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | EXPORT_SYMBOL(snd_vx_check_reg_bit); | ||
| 74 | |||
| 73 | /* | 75 | /* |
| 74 | * vx_send_irq_dsp - set command irq bit | 76 | * vx_send_irq_dsp - set command irq bit |
| 75 | * @num: the requested IRQ type, IRQ_XXX | 77 | * @num: the requested IRQ type, IRQ_XXX |
| @@ -465,6 +467,8 @@ int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot) | |||
| 465 | return 0; | 467 | return 0; |
| 466 | } | 468 | } |
| 467 | 469 | ||
| 470 | EXPORT_SYMBOL(snd_vx_load_boot_image); | ||
| 471 | |||
| 468 | /* | 472 | /* |
| 469 | * vx_test_irq_src - query the source of interrupts | 473 | * vx_test_irq_src - query the source of interrupts |
| 470 | * | 474 | * |
| @@ -545,6 +549,7 @@ irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs) | |||
| 545 | return IRQ_HANDLED; | 549 | return IRQ_HANDLED; |
| 546 | } | 550 | } |
| 547 | 551 | ||
| 552 | EXPORT_SYMBOL(snd_vx_irq_handler); | ||
| 548 | 553 | ||
| 549 | /* | 554 | /* |
| 550 | */ | 555 | */ |
| @@ -635,7 +640,7 @@ static void vx_proc_init(struct vx_core *chip) | |||
| 635 | struct snd_info_entry *entry; | 640 | struct snd_info_entry *entry; |
| 636 | 641 | ||
| 637 | if (! snd_card_proc_new(chip->card, "vx-status", &entry)) | 642 | if (! snd_card_proc_new(chip->card, "vx-status", &entry)) |
| 638 | snd_info_set_text_ops(entry, chip, 1024, vx_proc_read); | 643 | snd_info_set_text_ops(entry, chip, vx_proc_read); |
| 639 | } | 644 | } |
| 640 | 645 | ||
| 641 | 646 | ||
| @@ -657,6 +662,8 @@ int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *boot) | |||
| 657 | return 0; | 662 | return 0; |
| 658 | } | 663 | } |
| 659 | 664 | ||
| 665 | EXPORT_SYMBOL(snd_vx_dsp_boot); | ||
| 666 | |||
| 660 | /** | 667 | /** |
| 661 | * snd_vx_dsp_load - load the DSP image | 668 | * snd_vx_dsp_load - load the DSP image |
| 662 | */ | 669 | */ |
| @@ -705,6 +712,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp) | |||
| 705 | return 0; | 712 | return 0; |
| 706 | } | 713 | } |
| 707 | 714 | ||
| 715 | EXPORT_SYMBOL(snd_vx_dsp_load); | ||
| 716 | |||
| 708 | #ifdef CONFIG_PM | 717 | #ifdef CONFIG_PM |
| 709 | /* | 718 | /* |
| 710 | * suspend | 719 | * suspend |
| @@ -721,6 +730,8 @@ int snd_vx_suspend(struct vx_core *chip, pm_message_t state) | |||
| 721 | return 0; | 730 | return 0; |
| 722 | } | 731 | } |
| 723 | 732 | ||
| 733 | EXPORT_SYMBOL(snd_vx_suspend); | ||
| 734 | |||
| 724 | /* | 735 | /* |
| 725 | * resume | 736 | * resume |
| 726 | */ | 737 | */ |
| @@ -747,6 +758,7 @@ int snd_vx_resume(struct vx_core *chip) | |||
| 747 | return 0; | 758 | return 0; |
| 748 | } | 759 | } |
| 749 | 760 | ||
| 761 | EXPORT_SYMBOL(snd_vx_resume); | ||
| 750 | #endif | 762 | #endif |
| 751 | 763 | ||
| 752 | /** | 764 | /** |
| @@ -790,6 +802,8 @@ struct vx_core *snd_vx_create(struct snd_card *card, struct snd_vx_hardware *hw, | |||
| 790 | return chip; | 802 | return chip; |
| 791 | } | 803 | } |
| 792 | 804 | ||
| 805 | EXPORT_SYMBOL(snd_vx_create); | ||
| 806 | |||
| 793 | /* | 807 | /* |
| 794 | * module entries | 808 | * module entries |
| 795 | */ | 809 | */ |
| @@ -804,19 +818,3 @@ static void __exit alsa_vx_core_exit(void) | |||
| 804 | 818 | ||
| 805 | module_init(alsa_vx_core_init) | 819 | module_init(alsa_vx_core_init) |
| 806 | module_exit(alsa_vx_core_exit) | 820 | module_exit(alsa_vx_core_exit) |
| 807 | |||
| 808 | /* | ||
| 809 | * exports | ||
| 810 | */ | ||
| 811 | EXPORT_SYMBOL(snd_vx_check_reg_bit); | ||
| 812 | EXPORT_SYMBOL(snd_vx_create); | ||
| 813 | EXPORT_SYMBOL(snd_vx_setup_firmware); | ||
| 814 | EXPORT_SYMBOL(snd_vx_free_firmware); | ||
| 815 | EXPORT_SYMBOL(snd_vx_irq_handler); | ||
| 816 | EXPORT_SYMBOL(snd_vx_dsp_boot); | ||
| 817 | EXPORT_SYMBOL(snd_vx_dsp_load); | ||
| 818 | EXPORT_SYMBOL(snd_vx_load_boot_image); | ||
| 819 | #ifdef CONFIG_PM | ||
| 820 | EXPORT_SYMBOL(snd_vx_suspend); | ||
| 821 | EXPORT_SYMBOL(snd_vx_resume); | ||
| 822 | #endif | ||
diff --git a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c index d837783fb538..e1920af4501d 100644 --- a/sound/drivers/vx/vx_hwdep.c +++ b/sound/drivers/vx/vx_hwdep.c | |||
| @@ -250,3 +250,6 @@ void snd_vx_free_firmware(struct vx_core *chip) | |||
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | #endif /* SND_VX_FW_LOADER */ | 252 | #endif /* SND_VX_FW_LOADER */ |
| 253 | |||
| 254 | EXPORT_SYMBOL(snd_vx_setup_firmware); | ||
| 255 | EXPORT_SYMBOL(snd_vx_free_firmware); | ||
diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c index edfe76fb0074..b60fb1892828 100644 --- a/sound/i2c/i2c.c +++ b/sound/i2c/i2c.c | |||
| @@ -106,6 +106,8 @@ int snd_i2c_bus_create(struct snd_card *card, const char *name, | |||
| 106 | return 0; | 106 | return 0; |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | EXPORT_SYMBOL(snd_i2c_bus_create); | ||
| 110 | |||
| 109 | int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name, | 111 | int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name, |
| 110 | unsigned char addr, struct snd_i2c_device **rdevice) | 112 | unsigned char addr, struct snd_i2c_device **rdevice) |
| 111 | { | 113 | { |
| @@ -124,6 +126,8 @@ int snd_i2c_device_create(struct snd_i2c_bus *bus, const char *name, | |||
| 124 | return 0; | 126 | return 0; |
| 125 | } | 127 | } |
| 126 | 128 | ||
| 129 | EXPORT_SYMBOL(snd_i2c_device_create); | ||
| 130 | |||
| 127 | int snd_i2c_device_free(struct snd_i2c_device *device) | 131 | int snd_i2c_device_free(struct snd_i2c_device *device) |
| 128 | { | 132 | { |
| 129 | if (device->bus) | 133 | if (device->bus) |
| @@ -134,22 +138,29 @@ int snd_i2c_device_free(struct snd_i2c_device *device) | |||
| 134 | return 0; | 138 | return 0; |
| 135 | } | 139 | } |
| 136 | 140 | ||
| 141 | EXPORT_SYMBOL(snd_i2c_device_free); | ||
| 142 | |||
| 137 | int snd_i2c_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) | 143 | int snd_i2c_sendbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) |
| 138 | { | 144 | { |
| 139 | return device->bus->ops->sendbytes(device, bytes, count); | 145 | return device->bus->ops->sendbytes(device, bytes, count); |
| 140 | } | 146 | } |
| 141 | 147 | ||
| 148 | EXPORT_SYMBOL(snd_i2c_sendbytes); | ||
| 142 | 149 | ||
| 143 | int snd_i2c_readbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) | 150 | int snd_i2c_readbytes(struct snd_i2c_device *device, unsigned char *bytes, int count) |
| 144 | { | 151 | { |
| 145 | return device->bus->ops->readbytes(device, bytes, count); | 152 | return device->bus->ops->readbytes(device, bytes, count); |
| 146 | } | 153 | } |
| 147 | 154 | ||
| 155 | EXPORT_SYMBOL(snd_i2c_readbytes); | ||
| 156 | |||
| 148 | int snd_i2c_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) | 157 | int snd_i2c_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) |
| 149 | { | 158 | { |
| 150 | return bus->ops->probeaddr(bus, addr); | 159 | return bus->ops->probeaddr(bus, addr); |
| 151 | } | 160 | } |
| 152 | 161 | ||
| 162 | EXPORT_SYMBOL(snd_i2c_probeaddr); | ||
| 163 | |||
| 153 | /* | 164 | /* |
| 154 | * bit-operations | 165 | * bit-operations |
| 155 | */ | 166 | */ |
| @@ -320,12 +331,6 @@ static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) | |||
| 320 | return err; | 331 | return err; |
| 321 | } | 332 | } |
| 322 | 333 | ||
| 323 | EXPORT_SYMBOL(snd_i2c_bus_create); | ||
| 324 | EXPORT_SYMBOL(snd_i2c_device_create); | ||
| 325 | EXPORT_SYMBOL(snd_i2c_device_free); | ||
| 326 | EXPORT_SYMBOL(snd_i2c_sendbytes); | ||
| 327 | EXPORT_SYMBOL(snd_i2c_readbytes); | ||
| 328 | EXPORT_SYMBOL(snd_i2c_probeaddr); | ||
| 329 | 334 | ||
| 330 | static int __init alsa_i2c_init(void) | 335 | static int __init alsa_i2c_init(void) |
| 331 | { | 336 | { |
diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c index 746500e06950..b074fdddea55 100644 --- a/sound/i2c/l3/uda1341.c +++ b/sound/i2c/l3/uda1341.c | |||
| @@ -517,9 +517,9 @@ static void __devinit snd_uda1341_proc_init(struct snd_card *card, struct l3_cli | |||
| 517 | struct snd_info_entry *entry; | 517 | struct snd_info_entry *entry; |
| 518 | 518 | ||
| 519 | if (! snd_card_proc_new(card, "uda1341", &entry)) | 519 | if (! snd_card_proc_new(card, "uda1341", &entry)) |
| 520 | snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_read); | 520 | snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_read); |
| 521 | if (! snd_card_proc_new(card, "uda1341-regs", &entry)) | 521 | if (! snd_card_proc_new(card, "uda1341-regs", &entry)) |
| 522 | snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_regs_read); | 522 | snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_regs_read); |
| 523 | } | 523 | } |
| 524 | 524 | ||
| 525 | /* }}} */ | 525 | /* }}} */ |
diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c index c19ba2910b72..42db37552efb 100644 --- a/sound/isa/gus/gus_irq.c +++ b/sound/isa/gus/gus_irq.c | |||
| @@ -136,7 +136,7 @@ void snd_gus_irq_profile_init(struct snd_gus_card *gus) | |||
| 136 | struct snd_info_entry *entry; | 136 | struct snd_info_entry *entry; |
| 137 | 137 | ||
| 138 | if (! snd_card_proc_new(gus->card, "gusirq", &entry)) | 138 | if (! snd_card_proc_new(gus->card, "gusirq", &entry)) |
| 139 | snd_info_set_text_ops(entry, gus, 1024, snd_gus_irq_info_read); | 139 | snd_info_set_text_ops(entry, gus, snd_gus_irq_info_read); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | #endif | 142 | #endif |
diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index 3c0d27aa08b3..f50c276caee8 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c | |||
| @@ -264,10 +264,8 @@ int snd_gf1_mem_init(struct snd_gus_card * gus) | |||
| 264 | if (snd_gf1_mem_xalloc(alloc, &block) == NULL) | 264 | if (snd_gf1_mem_xalloc(alloc, &block) == NULL) |
| 265 | return -ENOMEM; | 265 | return -ENOMEM; |
| 266 | #ifdef CONFIG_SND_DEBUG | 266 | #ifdef CONFIG_SND_DEBUG |
| 267 | if (! snd_card_proc_new(gus->card, "gusmem", &entry)) { | 267 | if (! snd_card_proc_new(gus->card, "gusmem", &entry)) |
| 268 | snd_info_set_text_ops(entry, gus, 1024, snd_gf1_mem_info_read); | 268 | snd_info_set_text_ops(entry, gus, snd_gf1_mem_info_read); |
| 269 | entry->c.text.read_size = 256 * 1024; | ||
| 270 | } | ||
| 271 | #endif | 269 | #endif |
| 272 | return 0; | 270 | return 0; |
| 273 | } | 271 | } |
diff --git a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c index 2767cc187ae3..3e4d4d6edd8b 100644 --- a/sound/isa/gus/gus_synth.c +++ b/sound/isa/gus/gus_synth.c | |||
| @@ -194,7 +194,9 @@ static int snd_gus_synth_create_port(struct snd_gus_card * gus, int idx) | |||
| 194 | &callbacks, | 194 | &callbacks, |
| 195 | SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, | 195 | SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, |
| 196 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | | 196 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | |
| 197 | SNDRV_SEQ_PORT_TYPE_SYNTH, | 197 | SNDRV_SEQ_PORT_TYPE_SYNTH | |
| 198 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
| 199 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, | ||
| 198 | 16, 0, | 200 | 16, 0, |
| 199 | name); | 201 | name); |
| 200 | if (p->chset->port < 0) { | 202 | if (p->chset->port < 0) { |
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 4298d339e786..866300f2acbb 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c | |||
| @@ -70,9 +70,9 @@ static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ | |||
| 70 | static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ | 70 | static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ |
| 71 | static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29}; | 71 | static int joystick_dac[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 29}; |
| 72 | /* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */ | 72 | /* 0 to 31, (0.59V-4.52V or 0.389V-2.98V) */ |
| 73 | static int midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 73 | static int midi[SNDRV_CARDS]; |
| 74 | static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; | 74 | static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; |
| 75 | static int effect[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 75 | static int effect[SNDRV_CARDS]; |
| 76 | 76 | ||
| 77 | #ifdef SNDRV_STB | 77 | #ifdef SNDRV_STB |
| 78 | #define PFX "interwave-stb: " | 78 | #define PFX "interwave-stb: " |
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 6d889052c32c..647a996791e9 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c | |||
| @@ -59,7 +59,7 @@ static long midi_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;/* 0x330,0x300 */ | |||
| 59 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 0,1,3,5,9,11,12,15 */ | 59 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 0,1,3,5,9,11,12,15 */ |
| 60 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */ | 60 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */ |
| 61 | static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */ | 61 | static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3,5,6,7 */ |
| 62 | static int opl3sa3_ymode[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* 0,1,2,3 */ /*SL Added*/ | 62 | static int opl3sa3_ymode[SNDRV_CARDS]; /* 0,1,2,3 */ /*SL Added*/ |
| 63 | 63 | ||
| 64 | module_param_array(index, int, NULL, 0444); | 64 | module_param_array(index, int, NULL, 0444); |
| 65 | MODULE_PARM_DESC(index, "Index value for OPL3-SA soundcard."); | 65 | MODULE_PARM_DESC(index, "Index value for OPL3-SA soundcard."); |
| @@ -221,7 +221,7 @@ static void snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsig | |||
| 221 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 221 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | static int __init snd_opl3sa2_detect(struct snd_opl3sa2 *chip) | 224 | static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip) |
| 225 | { | 225 | { |
| 226 | struct snd_card *card; | 226 | struct snd_card *card; |
| 227 | unsigned long port; | 227 | unsigned long port; |
| @@ -489,7 +489,7 @@ static void snd_opl3sa2_master_free(struct snd_kcontrol *kcontrol) | |||
| 489 | chip->master_volume = NULL; | 489 | chip->master_volume = NULL; |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | static int __init snd_opl3sa2_mixer(struct snd_opl3sa2 *chip) | 492 | static int __devinit snd_opl3sa2_mixer(struct snd_opl3sa2 *chip) |
| 493 | { | 493 | { |
| 494 | struct snd_card *card = chip->card; | 494 | struct snd_card *card = chip->card; |
| 495 | struct snd_ctl_elem_id id1, id2; | 495 | struct snd_ctl_elem_id id1, id2; |
| @@ -583,8 +583,8 @@ static int snd_opl3sa2_resume(struct snd_card *card) | |||
| 583 | #endif /* CONFIG_PM */ | 583 | #endif /* CONFIG_PM */ |
| 584 | 584 | ||
| 585 | #ifdef CONFIG_PNP | 585 | #ifdef CONFIG_PNP |
| 586 | static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, | 586 | static int __devinit snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, |
| 587 | struct pnp_dev *pdev) | 587 | struct pnp_dev *pdev) |
| 588 | { | 588 | { |
| 589 | struct pnp_resource_table * cfg; | 589 | struct pnp_resource_table * cfg; |
| 590 | int err; | 590 | int err; |
| @@ -862,7 +862,7 @@ static struct pnp_card_driver opl3sa2_pnpc_driver = { | |||
| 862 | }; | 862 | }; |
| 863 | #endif /* CONFIG_PNP */ | 863 | #endif /* CONFIG_PNP */ |
| 864 | 864 | ||
| 865 | static int __init snd_opl3sa2_nonpnp_probe(struct platform_device *pdev) | 865 | static int __devinit snd_opl3sa2_nonpnp_probe(struct platform_device *pdev) |
| 866 | { | 866 | { |
| 867 | struct snd_card *card; | 867 | struct snd_card *card; |
| 868 | int err; | 868 | int err; |
diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index e6bfcf74c1c1..283817f2de75 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c | |||
| @@ -967,7 +967,7 @@ static void __init snd_miro_proc_init(struct snd_miro * miro) | |||
| 967 | struct snd_info_entry *entry; | 967 | struct snd_info_entry *entry; |
| 968 | 968 | ||
| 969 | if (! snd_card_proc_new(miro->card, "miro", &entry)) | 969 | if (! snd_card_proc_new(miro->card, "miro", &entry)) |
| 970 | snd_info_set_text_ops(entry, miro, 1024, snd_miro_proc_read); | 970 | snd_info_set_text_ops(entry, miro, snd_miro_proc_read); |
| 971 | } | 971 | } |
| 972 | 972 | ||
| 973 | /* | 973 | /* |
diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index c0b8d61b75e7..658179e86142 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c | |||
| @@ -131,7 +131,7 @@ snd_emu8000_dma_chan(struct snd_emu8000 *emu, int ch, int mode) | |||
| 131 | 131 | ||
| 132 | /* | 132 | /* |
| 133 | */ | 133 | */ |
| 134 | static void __init | 134 | static void __devinit |
| 135 | snd_emu8000_read_wait(struct snd_emu8000 *emu) | 135 | snd_emu8000_read_wait(struct snd_emu8000 *emu) |
| 136 | { | 136 | { |
| 137 | while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) { | 137 | while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) { |
| @@ -143,7 +143,7 @@ snd_emu8000_read_wait(struct snd_emu8000 *emu) | |||
| 143 | 143 | ||
| 144 | /* | 144 | /* |
| 145 | */ | 145 | */ |
| 146 | static void __init | 146 | static void __devinit |
| 147 | snd_emu8000_write_wait(struct snd_emu8000 *emu) | 147 | snd_emu8000_write_wait(struct snd_emu8000 *emu) |
| 148 | { | 148 | { |
| 149 | while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) { | 149 | while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) { |
| @@ -156,7 +156,7 @@ snd_emu8000_write_wait(struct snd_emu8000 *emu) | |||
| 156 | /* | 156 | /* |
| 157 | * detect a card at the given port | 157 | * detect a card at the given port |
| 158 | */ | 158 | */ |
| 159 | static int __init | 159 | static int __devinit |
| 160 | snd_emu8000_detect(struct snd_emu8000 *emu) | 160 | snd_emu8000_detect(struct snd_emu8000 *emu) |
| 161 | { | 161 | { |
| 162 | /* Initialise */ | 162 | /* Initialise */ |
| @@ -182,7 +182,7 @@ snd_emu8000_detect(struct snd_emu8000 *emu) | |||
| 182 | /* | 182 | /* |
| 183 | * intiailize audio channels | 183 | * intiailize audio channels |
| 184 | */ | 184 | */ |
| 185 | static void __init | 185 | static void __devinit |
| 186 | init_audio(struct snd_emu8000 *emu) | 186 | init_audio(struct snd_emu8000 *emu) |
| 187 | { | 187 | { |
| 188 | int ch; | 188 | int ch; |
| @@ -223,7 +223,7 @@ init_audio(struct snd_emu8000 *emu) | |||
| 223 | /* | 223 | /* |
| 224 | * initialize DMA address | 224 | * initialize DMA address |
| 225 | */ | 225 | */ |
| 226 | static void __init | 226 | static void __devinit |
| 227 | init_dma(struct snd_emu8000 *emu) | 227 | init_dma(struct snd_emu8000 *emu) |
| 228 | { | 228 | { |
| 229 | EMU8000_SMALR_WRITE(emu, 0); | 229 | EMU8000_SMALR_WRITE(emu, 0); |
| @@ -327,7 +327,7 @@ static unsigned short init4[128] /*__devinitdata*/ = { | |||
| 327 | * Taken from the oss driver, not obvious from the doc how this | 327 | * Taken from the oss driver, not obvious from the doc how this |
| 328 | * is meant to work | 328 | * is meant to work |
| 329 | */ | 329 | */ |
| 330 | static void __init | 330 | static void __devinit |
| 331 | send_array(struct snd_emu8000 *emu, unsigned short *data, int size) | 331 | send_array(struct snd_emu8000 *emu, unsigned short *data, int size) |
| 332 | { | 332 | { |
| 333 | int i; | 333 | int i; |
| @@ -349,7 +349,7 @@ send_array(struct snd_emu8000 *emu, unsigned short *data, int size) | |||
| 349 | * Send initialization arrays to start up, this just follows the | 349 | * Send initialization arrays to start up, this just follows the |
| 350 | * initialisation sequence in the adip. | 350 | * initialisation sequence in the adip. |
| 351 | */ | 351 | */ |
| 352 | static void __init | 352 | static void __devinit |
| 353 | init_arrays(struct snd_emu8000 *emu) | 353 | init_arrays(struct snd_emu8000 *emu) |
| 354 | { | 354 | { |
| 355 | send_array(emu, init1, ARRAY_SIZE(init1)/4); | 355 | send_array(emu, init1, ARRAY_SIZE(init1)/4); |
| @@ -375,7 +375,7 @@ init_arrays(struct snd_emu8000 *emu) | |||
| 375 | * seems that the only way to do this is to use the one channel and keep | 375 | * seems that the only way to do this is to use the one channel and keep |
| 376 | * reallocating between read and write. | 376 | * reallocating between read and write. |
| 377 | */ | 377 | */ |
| 378 | static void __init | 378 | static void __devinit |
| 379 | size_dram(struct snd_emu8000 *emu) | 379 | size_dram(struct snd_emu8000 *emu) |
| 380 | { | 380 | { |
| 381 | int i, size; | 381 | int i, size; |
| @@ -500,7 +500,7 @@ snd_emu8000_init_fm(struct snd_emu8000 *emu) | |||
| 500 | /* | 500 | /* |
| 501 | * The main initialization routine. | 501 | * The main initialization routine. |
| 502 | */ | 502 | */ |
| 503 | static void __init | 503 | static void __devinit |
| 504 | snd_emu8000_init_hw(struct snd_emu8000 *emu) | 504 | snd_emu8000_init_hw(struct snd_emu8000 *emu) |
| 505 | { | 505 | { |
| 506 | int i; | 506 | int i; |
| @@ -1019,7 +1019,7 @@ static struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = { | |||
| 1019 | /* | 1019 | /* |
| 1020 | * create and attach mixer elements for WaveTable treble/bass controls | 1020 | * create and attach mixer elements for WaveTable treble/bass controls |
| 1021 | */ | 1021 | */ |
| 1022 | static int __init | 1022 | static int __devinit |
| 1023 | snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu) | 1023 | snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu) |
| 1024 | { | 1024 | { |
| 1025 | int i, err = 0; | 1025 | int i, err = 0; |
| @@ -1069,7 +1069,7 @@ static int snd_emu8000_dev_free(struct snd_device *device) | |||
| 1069 | /* | 1069 | /* |
| 1070 | * initialize and register emu8000 synth device. | 1070 | * initialize and register emu8000 synth device. |
| 1071 | */ | 1071 | */ |
| 1072 | int __init | 1072 | int __devinit |
| 1073 | snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports, | 1073 | snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports, |
| 1074 | struct snd_seq_device **awe_ret) | 1074 | struct snd_seq_device **awe_ret) |
| 1075 | { | 1075 | { |
diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c index 80b1cf84a1ae..1be16c9700f0 100644 --- a/sound/isa/sb/emu8000_patch.c +++ b/sound/isa/sb/emu8000_patch.c | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
| 24 | #include <linux/moduleparam.h> | 24 | #include <linux/moduleparam.h> |
| 25 | 25 | ||
| 26 | static int emu8000_reset_addr = 0; | 26 | static int emu8000_reset_addr; |
| 27 | module_param(emu8000_reset_addr, int, 0444); | 27 | module_param(emu8000_reset_addr, int, 0444); |
| 28 | MODULE_PARM_DESC(emu8000_reset_addr, "reset write address at each time (makes slowdown)"); | 28 | MODULE_PARM_DESC(emu8000_reset_addr, "reset write address at each time (makes slowdown)"); |
| 29 | 29 | ||
diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 6333f900eaee..7f7f05fa518a 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c | |||
| @@ -85,7 +85,7 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */ | |||
| 85 | static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 5,6,7 */ | 85 | static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 5,6,7 */ |
| 86 | static int mic_agc[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; | 86 | static int mic_agc[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; |
| 87 | #ifdef CONFIG_SND_SB16_CSP | 87 | #ifdef CONFIG_SND_SB16_CSP |
| 88 | static int csp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 88 | static int csp[SNDRV_CARDS]; |
| 89 | #endif | 89 | #endif |
| 90 | #ifdef SNDRV_SBAWE_EMU8000 | 90 | #ifdef SNDRV_SBAWE_EMU8000 |
| 91 | static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4}; | 91 | static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4}; |
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index 9703c68e4e08..fcd638090a9e 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c | |||
| @@ -1101,7 +1101,7 @@ static int init_proc_entry(struct snd_sb_csp * p, int device) | |||
| 1101 | struct snd_info_entry *entry; | 1101 | struct snd_info_entry *entry; |
| 1102 | sprintf(name, "cspD%d", device); | 1102 | sprintf(name, "cspD%d", device); |
| 1103 | if (! snd_card_proc_new(p->chip->card, name, &entry)) | 1103 | if (! snd_card_proc_new(p->chip->card, name, &entry)) |
| 1104 | snd_info_set_text_ops(entry, p, 1024, info_read); | 1104 | snd_info_set_text_ops(entry, p, info_read); |
| 1105 | return 0; | 1105 | return 0; |
| 1106 | } | 1106 | } |
| 1107 | 1107 | ||
diff --git a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c index c549aceea294..0b67edd7ac6e 100644 --- a/sound/isa/sb/sb8_midi.c +++ b/sound/isa/sb/sb8_midi.c | |||
| @@ -32,20 +32,22 @@ | |||
| 32 | #include <sound/core.h> | 32 | #include <sound/core.h> |
| 33 | #include <sound/sb.h> | 33 | #include <sound/sb.h> |
| 34 | 34 | ||
| 35 | /* | ||
| 36 | |||
| 37 | */ | ||
| 38 | 35 | ||
| 39 | irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb * chip) | 36 | irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb *chip) |
| 40 | { | 37 | { |
| 41 | struct snd_rawmidi *rmidi; | 38 | struct snd_rawmidi *rmidi; |
| 42 | int max = 64; | 39 | int max = 64; |
| 43 | char byte; | 40 | char byte; |
| 44 | 41 | ||
| 45 | if (chip == NULL || (rmidi = chip->rmidi) == NULL) { | 42 | if (!chip) |
| 43 | return IRQ_NONE; | ||
| 44 | |||
| 45 | rmidi = chip->rmidi; | ||
| 46 | if (!rmidi) { | ||
| 46 | inb(SBP(chip, DATA_AVAIL)); /* ack interrupt */ | 47 | inb(SBP(chip, DATA_AVAIL)); /* ack interrupt */ |
| 47 | return IRQ_NONE; | 48 | return IRQ_NONE; |
| 48 | } | 49 | } |
| 50 | |||
| 49 | spin_lock(&chip->midi_input_lock); | 51 | spin_lock(&chip->midi_input_lock); |
| 50 | while (max-- > 0) { | 52 | while (max-- > 0) { |
| 51 | if (inb(SBP(chip, DATA_AVAIL)) & 0x80) { | 53 | if (inb(SBP(chip, DATA_AVAIL)) & 0x80) { |
| @@ -59,10 +61,6 @@ irqreturn_t snd_sb8dsp_midi_interrupt(struct snd_sb * chip) | |||
| 59 | return IRQ_HANDLED; | 61 | return IRQ_HANDLED; |
| 60 | } | 62 | } |
| 61 | 63 | ||
| 62 | /* | ||
| 63 | |||
| 64 | */ | ||
| 65 | |||
| 66 | static int snd_sb8dsp_midi_input_open(struct snd_rawmidi_substream *substream) | 64 | static int snd_sb8dsp_midi_input_open(struct snd_rawmidi_substream *substream) |
| 67 | { | 65 | { |
| 68 | unsigned long flags; | 66 | unsigned long flags; |
| @@ -252,10 +250,6 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre | |||
| 252 | snd_sb8dsp_midi_output_write(substream); | 250 | snd_sb8dsp_midi_output_write(substream); |
| 253 | } | 251 | } |
| 254 | 252 | ||
| 255 | /* | ||
| 256 | |||
| 257 | */ | ||
| 258 | |||
| 259 | static struct snd_rawmidi_ops snd_sb8dsp_midi_output = | 253 | static struct snd_rawmidi_ops snd_sb8dsp_midi_output = |
| 260 | { | 254 | { |
| 261 | .open = snd_sb8dsp_midi_output_open, | 255 | .open = snd_sb8dsp_midi_output_open, |
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index d2a856f0fde2..27271c9446dc 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c | |||
| @@ -897,10 +897,9 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l | |||
| 897 | struct snd_rawmidi *rawmidi; | 897 | struct snd_rawmidi *rawmidi; |
| 898 | int err; | 898 | int err; |
| 899 | 899 | ||
| 900 | #define MPU401_SHARE_HARDWARE 1 | ||
| 901 | if ((err = snd_mpu401_uart_new(card, devnum, | 900 | if ((err = snd_mpu401_uart_new(card, devnum, |
| 902 | MPU401_HW_MPU401, | 901 | MPU401_HW_MPU401, |
| 903 | port, MPU401_SHARE_HARDWARE, | 902 | port, MPU401_INFO_INTEGRATED, |
| 904 | irq, SA_INTERRUPT, | 903 | irq, SA_INTERRUPT, |
| 905 | &rawmidi)) == 0) { | 904 | &rawmidi)) == 0) { |
| 906 | struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data; | 905 | struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data; |
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index 7ae86f82c3fa..9eb27082c659 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c | |||
| @@ -50,7 +50,7 @@ static int ics2115_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 2,9,11,12,15 */ | |||
| 50 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | 50 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ |
| 51 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ | 51 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ |
| 52 | static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ | 52 | static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ |
| 53 | static int use_cs4232_midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 53 | static int use_cs4232_midi[SNDRV_CARDS]; |
| 54 | 54 | ||
| 55 | module_param_array(index, int, NULL, 0444); | 55 | module_param_array(index, int, NULL, 0444); |
| 56 | MODULE_PARM_DESC(index, "Index value for WaveFront soundcard."); | 56 | MODULE_PARM_DESC(index, "Index value for WaveFront soundcard."); |
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index a2081803a827..d37346b12dc0 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
| @@ -216,14 +216,19 @@ config SND_CS46XX_NEW_DSP | |||
| 216 | This works better than the old code, so say Y. | 216 | This works better than the old code, so say Y. |
| 217 | 217 | ||
| 218 | config SND_CS5535AUDIO | 218 | config SND_CS5535AUDIO |
| 219 | tristate "CS5535 Audio" | 219 | tristate "CS5535/CS5536 Audio" |
| 220 | depends on SND && X86 && !X86_64 | 220 | depends on SND && X86 && !X86_64 |
| 221 | select SND_PCM | 221 | select SND_PCM |
| 222 | select SND_AC97_CODEC | 222 | select SND_AC97_CODEC |
| 223 | help | 223 | help |
| 224 | Say Y here to include support for audio on CS5535 chips. It is | 224 | Say Y here to include support for audio on CS5535 chips. It is |
| 225 | referred to as NS CS5535 IO or AMD CS5535 IO companion in | 225 | referred to as NS CS5535 IO or AMD CS5535 IO companion in |
| 226 | various literature. | 226 | various literature. This driver also supports the CS5536 audio |
| 227 | device. However, for both chips, on certain boards, you may | ||
| 228 | need to use ac97_quirk=hp_only if your board has physically | ||
| 229 | mapped headphone out to master output. If that works for you, | ||
| 230 | send lspci -vvv output to the mailing list so that your board | ||
| 231 | can be identified in the quirks list. | ||
| 227 | 232 | ||
| 228 | To compile this driver as a module, choose M here: the module | 233 | To compile this driver as a module, choose M here: the module |
| 229 | will be called snd-cs5535audio. | 234 | will be called snd-cs5535audio. |
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index d05200741ac3..0abf2808d59f 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c | |||
| @@ -253,6 +253,8 @@ void snd_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short va | |||
| 253 | ac97->bus->ops->write(ac97, reg, value); | 253 | ac97->bus->ops->write(ac97, reg, value); |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | EXPORT_SYMBOL(snd_ac97_write); | ||
| 257 | |||
| 256 | /** | 258 | /** |
| 257 | * snd_ac97_read - read a value from the given register | 259 | * snd_ac97_read - read a value from the given register |
| 258 | * | 260 | * |
| @@ -281,6 +283,8 @@ static inline unsigned short snd_ac97_read_cache(struct snd_ac97 *ac97, unsigned | |||
| 281 | return ac97->regs[reg]; | 283 | return ac97->regs[reg]; |
| 282 | } | 284 | } |
| 283 | 285 | ||
| 286 | EXPORT_SYMBOL(snd_ac97_read); | ||
| 287 | |||
| 284 | /** | 288 | /** |
| 285 | * snd_ac97_write_cache - write a value on the given register and update the cache | 289 | * snd_ac97_write_cache - write a value on the given register and update the cache |
| 286 | * @ac97: the ac97 instance | 290 | * @ac97: the ac97 instance |
| @@ -302,6 +306,8 @@ void snd_ac97_write_cache(struct snd_ac97 *ac97, unsigned short reg, unsigned sh | |||
| 302 | mutex_unlock(&ac97->reg_mutex); | 306 | mutex_unlock(&ac97->reg_mutex); |
| 303 | } | 307 | } |
| 304 | 308 | ||
| 309 | EXPORT_SYMBOL(snd_ac97_write_cache); | ||
| 310 | |||
| 305 | /** | 311 | /** |
| 306 | * snd_ac97_update - update the value on the given register | 312 | * snd_ac97_update - update the value on the given register |
| 307 | * @ac97: the ac97 instance | 313 | * @ac97: the ac97 instance |
| @@ -331,6 +337,8 @@ int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short va | |||
| 331 | return change; | 337 | return change; |
| 332 | } | 338 | } |
| 333 | 339 | ||
| 340 | EXPORT_SYMBOL(snd_ac97_update); | ||
| 341 | |||
| 334 | /** | 342 | /** |
| 335 | * snd_ac97_update_bits - update the bits on the given register | 343 | * snd_ac97_update_bits - update the bits on the given register |
| 336 | * @ac97: the ac97 instance | 344 | * @ac97: the ac97 instance |
| @@ -356,6 +364,8 @@ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned sho | |||
| 356 | return change; | 364 | return change; |
| 357 | } | 365 | } |
| 358 | 366 | ||
| 367 | EXPORT_SYMBOL(snd_ac97_update_bits); | ||
| 368 | |||
| 359 | /* no lock version - see snd_ac97_updat_bits() */ | 369 | /* no lock version - see snd_ac97_updat_bits() */ |
| 360 | int snd_ac97_update_bits_nolock(struct snd_ac97 *ac97, unsigned short reg, | 370 | int snd_ac97_update_bits_nolock(struct snd_ac97 *ac97, unsigned short reg, |
| 361 | unsigned short mask, unsigned short value) | 371 | unsigned short mask, unsigned short value) |
| @@ -563,7 +573,7 @@ AC97_SINGLE("PC Speaker Playback Volume", AC97_PC_BEEP, 1, 15, 1) | |||
| 563 | }; | 573 | }; |
| 564 | 574 | ||
| 565 | static const struct snd_kcontrol_new snd_ac97_controls_mic_boost = | 575 | static const struct snd_kcontrol_new snd_ac97_controls_mic_boost = |
| 566 | AC97_SINGLE("Mic Boost (+20dB)", AC97_MIC, 6, 1, 0); | 576 | AC97_SINGLE("Mic Boost (+20dB) Switch", AC97_MIC, 6, 1, 0); |
| 567 | 577 | ||
| 568 | 578 | ||
| 569 | static const char* std_rec_sel[] = {"Mic", "CD", "Video", "Aux", "Line", "Mix", "Mix Mono", "Phone"}; | 579 | static const char* std_rec_sel[] = {"Mic", "CD", "Video", "Aux", "Line", "Mix", "Mix Mono", "Phone"}; |
| @@ -605,7 +615,7 @@ AC97_SINGLE("Simulated Stereo Enhancement", AC97_GENERAL_PURPOSE, 14, 1, 0), | |||
| 605 | AC97_SINGLE("3D Control - Switch", AC97_GENERAL_PURPOSE, 13, 1, 0), | 615 | AC97_SINGLE("3D Control - Switch", AC97_GENERAL_PURPOSE, 13, 1, 0), |
| 606 | AC97_SINGLE("Loudness (bass boost)", AC97_GENERAL_PURPOSE, 12, 1, 0), | 616 | AC97_SINGLE("Loudness (bass boost)", AC97_GENERAL_PURPOSE, 12, 1, 0), |
| 607 | AC97_ENUM("Mono Output Select", std_enum[2]), | 617 | AC97_ENUM("Mono Output Select", std_enum[2]), |
| 608 | AC97_ENUM("Mic Select", std_enum[3]), | 618 | AC97_ENUM("Mic Select Capture Switch", std_enum[3]), |
| 609 | AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0) | 619 | AC97_SINGLE("ADC/DAC Loopback", AC97_GENERAL_PURPOSE, 7, 1, 0) |
| 610 | }; | 620 | }; |
| 611 | 621 | ||
| @@ -1226,7 +1236,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
| 1226 | ac97->regs[AC97_CENTER_LFE_MASTER] = 0x8080; | 1236 | ac97->regs[AC97_CENTER_LFE_MASTER] = 0x8080; |
| 1227 | 1237 | ||
| 1228 | /* build center controls */ | 1238 | /* build center controls */ |
| 1229 | if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) { | 1239 | if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER)) |
| 1240 | && !(ac97->flags & AC97_AD_MULTI)) { | ||
| 1230 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_center[0], ac97))) < 0) | 1241 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_center[0], ac97))) < 0) |
| 1231 | return err; | 1242 | return err; |
| 1232 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_center[1], ac97))) < 0) | 1243 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_center[1], ac97))) < 0) |
| @@ -1238,7 +1249,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
| 1238 | } | 1249 | } |
| 1239 | 1250 | ||
| 1240 | /* build LFE controls */ | 1251 | /* build LFE controls */ |
| 1241 | if (snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER+1)) { | 1252 | if ((snd_ac97_try_volume_mix(ac97, AC97_CENTER_LFE_MASTER+1)) |
| 1253 | && !(ac97->flags & AC97_AD_MULTI)) { | ||
| 1242 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_lfe[0], ac97))) < 0) | 1254 | if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_lfe[0], ac97))) < 0) |
| 1243 | return err; | 1255 | return err; |
| 1244 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_lfe[1], ac97))) < 0) | 1256 | if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_lfe[1], ac97))) < 0) |
| @@ -1250,7 +1262,8 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
| 1250 | } | 1262 | } |
| 1251 | 1263 | ||
| 1252 | /* build surround controls */ | 1264 | /* build surround controls */ |
| 1253 | if (snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) { | 1265 | if ((snd_ac97_try_volume_mix(ac97, AC97_SURROUND_MASTER)) |
| 1266 | && !(ac97->flags & AC97_AD_MULTI)) { | ||
| 1254 | /* Surround Master (0x38) is with stereo mutes */ | 1267 | /* Surround Master (0x38) is with stereo mutes */ |
| 1255 | if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0) | 1268 | if ((err = snd_ac97_cmix_new_stereo(card, "Surround Playback", AC97_SURROUND_MASTER, 1, ac97)) < 0) |
| 1256 | return err; | 1269 | return err; |
| @@ -1335,9 +1348,11 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) | |||
| 1335 | } | 1348 | } |
| 1336 | 1349 | ||
| 1337 | /* build Aux controls */ | 1350 | /* build Aux controls */ |
| 1338 | if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { | 1351 | if (!(ac97->flags & AC97_HAS_NO_AUX)) { |
| 1339 | if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0) | 1352 | if (snd_ac97_try_volume_mix(ac97, AC97_AUX)) { |
| 1340 | return err; | 1353 | if ((err = snd_ac97_cmix_new(card, "Aux Playback", AC97_AUX, ac97)) < 0) |
| 1354 | return err; | ||
| 1355 | } | ||
| 1341 | } | 1356 | } |
| 1342 | 1357 | ||
| 1343 | /* build PCM controls */ | 1358 | /* build PCM controls */ |
| @@ -1682,6 +1697,7 @@ const char *snd_ac97_get_short_name(struct snd_ac97 *ac97) | |||
| 1682 | return "unknown codec"; | 1697 | return "unknown codec"; |
| 1683 | } | 1698 | } |
| 1684 | 1699 | ||
| 1700 | EXPORT_SYMBOL(snd_ac97_get_short_name); | ||
| 1685 | 1701 | ||
| 1686 | /* wait for a while until registers are accessible after RESET | 1702 | /* wait for a while until registers are accessible after RESET |
| 1687 | * return 0 if ok, negative not ready | 1703 | * return 0 if ok, negative not ready |
| @@ -1774,6 +1790,8 @@ int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops, | |||
| 1774 | return 0; | 1790 | return 0; |
| 1775 | } | 1791 | } |
| 1776 | 1792 | ||
| 1793 | EXPORT_SYMBOL(snd_ac97_bus); | ||
| 1794 | |||
| 1777 | /* stop no dev release warning */ | 1795 | /* stop no dev release warning */ |
| 1778 | static void ac97_device_release(struct device * dev) | 1796 | static void ac97_device_release(struct device * dev) |
| 1779 | { | 1797 | { |
| @@ -2117,6 +2135,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, | |||
| 2117 | return 0; | 2135 | return 0; |
| 2118 | } | 2136 | } |
| 2119 | 2137 | ||
| 2138 | EXPORT_SYMBOL(snd_ac97_mixer); | ||
| 2120 | 2139 | ||
| 2121 | /* | 2140 | /* |
| 2122 | * Power down the chip. | 2141 | * Power down the chip. |
| @@ -2166,6 +2185,8 @@ void snd_ac97_suspend(struct snd_ac97 *ac97) | |||
| 2166 | snd_ac97_powerdown(ac97); | 2185 | snd_ac97_powerdown(ac97); |
| 2167 | } | 2186 | } |
| 2168 | 2187 | ||
| 2188 | EXPORT_SYMBOL(snd_ac97_suspend); | ||
| 2189 | |||
| 2169 | /* | 2190 | /* |
| 2170 | * restore ac97 status | 2191 | * restore ac97 status |
| 2171 | */ | 2192 | */ |
| @@ -2267,6 +2288,8 @@ __reset_ready: | |||
| 2267 | snd_ac97_restore_iec958(ac97); | 2288 | snd_ac97_restore_iec958(ac97); |
| 2268 | } | 2289 | } |
| 2269 | } | 2290 | } |
| 2291 | |||
| 2292 | EXPORT_SYMBOL(snd_ac97_resume); | ||
| 2270 | #endif | 2293 | #endif |
| 2271 | 2294 | ||
| 2272 | 2295 | ||
| @@ -2590,29 +2613,7 @@ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, cons | |||
| 2590 | return 0; | 2613 | return 0; |
| 2591 | } | 2614 | } |
| 2592 | 2615 | ||
| 2593 | |||
| 2594 | /* | ||
| 2595 | * Exported symbols | ||
| 2596 | */ | ||
| 2597 | |||
| 2598 | EXPORT_SYMBOL(snd_ac97_write); | ||
| 2599 | EXPORT_SYMBOL(snd_ac97_read); | ||
| 2600 | EXPORT_SYMBOL(snd_ac97_write_cache); | ||
| 2601 | EXPORT_SYMBOL(snd_ac97_update); | ||
| 2602 | EXPORT_SYMBOL(snd_ac97_update_bits); | ||
| 2603 | EXPORT_SYMBOL(snd_ac97_get_short_name); | ||
| 2604 | EXPORT_SYMBOL(snd_ac97_bus); | ||
| 2605 | EXPORT_SYMBOL(snd_ac97_mixer); | ||
| 2606 | EXPORT_SYMBOL(snd_ac97_pcm_assign); | ||
| 2607 | EXPORT_SYMBOL(snd_ac97_pcm_open); | ||
| 2608 | EXPORT_SYMBOL(snd_ac97_pcm_close); | ||
| 2609 | EXPORT_SYMBOL(snd_ac97_pcm_double_rate_rules); | ||
| 2610 | EXPORT_SYMBOL(snd_ac97_tune_hardware); | 2616 | EXPORT_SYMBOL(snd_ac97_tune_hardware); |
| 2611 | EXPORT_SYMBOL(snd_ac97_set_rate); | ||
| 2612 | #ifdef CONFIG_PM | ||
| 2613 | EXPORT_SYMBOL(snd_ac97_resume); | ||
| 2614 | EXPORT_SYMBOL(snd_ac97_suspend); | ||
| 2615 | #endif | ||
| 2616 | 2617 | ||
| 2617 | /* | 2618 | /* |
| 2618 | * INIT part | 2619 | * INIT part |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 4d9cf37300f7..7f197c780816 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
| @@ -464,6 +464,10 @@ int patch_wolfson05(struct snd_ac97 * ac97) | |||
| 464 | { | 464 | { |
| 465 | /* WM9705, WM9710 */ | 465 | /* WM9705, WM9710 */ |
| 466 | ac97->build_ops = &patch_wolfson_wm9705_ops; | 466 | ac97->build_ops = &patch_wolfson_wm9705_ops; |
| 467 | #ifdef CONFIG_TOUCHSCREEN_WM9705 | ||
| 468 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ | ||
| 469 | ac97->flags |=3D AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; | ||
| 470 | #endif | ||
| 467 | return 0; | 471 | return 0; |
| 468 | } | 472 | } |
| 469 | 473 | ||
| @@ -1367,6 +1371,13 @@ static void ad18xx_resume(struct snd_ac97 *ac97) | |||
| 1367 | 1371 | ||
| 1368 | snd_ac97_restore_iec958(ac97); | 1372 | snd_ac97_restore_iec958(ac97); |
| 1369 | } | 1373 | } |
| 1374 | |||
| 1375 | static void ad1888_resume(struct snd_ac97 *ac97) | ||
| 1376 | { | ||
| 1377 | ad18xx_resume(ac97); | ||
| 1378 | snd_ac97_write_cache(ac97, AC97_CODEC_CLASS_REV, 0x8080); | ||
| 1379 | } | ||
| 1380 | |||
| 1370 | #endif | 1381 | #endif |
| 1371 | 1382 | ||
| 1372 | int patch_ad1819(struct snd_ac97 * ac97) | 1383 | int patch_ad1819(struct snd_ac97 * ac97) |
| @@ -1627,6 +1638,7 @@ static const struct snd_kcontrol_new snd_ac97_ad1981x_jack_sense[] = { | |||
| 1627 | * (SS vendor << 16 | device) | 1638 | * (SS vendor << 16 | device) |
| 1628 | */ | 1639 | */ |
| 1629 | static unsigned int ad1981_jacks_blacklist[] = { | 1640 | static unsigned int ad1981_jacks_blacklist[] = { |
| 1641 | 0x10140537, /* Thinkpad T41p */ | ||
| 1630 | 0x10140554, /* Thinkpad T42p/R50p */ | 1642 | 0x10140554, /* Thinkpad T42p/R50p */ |
| 1631 | 0 /* end */ | 1643 | 0 /* end */ |
| 1632 | }; | 1644 | }; |
| @@ -1839,7 +1851,7 @@ static struct snd_ac97_build_ops patch_ad1888_build_ops = { | |||
| 1839 | .build_post_spdif = patch_ad198x_post_spdif, | 1851 | .build_post_spdif = patch_ad198x_post_spdif, |
| 1840 | .build_specific = patch_ad1888_specific, | 1852 | .build_specific = patch_ad1888_specific, |
| 1841 | #ifdef CONFIG_PM | 1853 | #ifdef CONFIG_PM |
| 1842 | .resume = ad18xx_resume, | 1854 | .resume = ad1888_resume, |
| 1843 | #endif | 1855 | #endif |
| 1844 | .update_jacks = ad1888_update_jacks, | 1856 | .update_jacks = ad1888_update_jacks, |
| 1845 | }; | 1857 | }; |
| @@ -2048,7 +2060,10 @@ int patch_alc650(struct snd_ac97 * ac97) | |||
| 2048 | /* Enable SPDIF-IN only on Rev.E and above */ | 2060 | /* Enable SPDIF-IN only on Rev.E and above */ |
| 2049 | val = snd_ac97_read(ac97, AC97_ALC650_CLOCK); | 2061 | val = snd_ac97_read(ac97, AC97_ALC650_CLOCK); |
| 2050 | /* SPDIF IN with pin 47 */ | 2062 | /* SPDIF IN with pin 47 */ |
| 2051 | if (ac97->spec.dev_flags) | 2063 | if (ac97->spec.dev_flags && |
| 2064 | /* ASUS A6KM requires EAPD */ | ||
| 2065 | ! (ac97->subsystem_vendor == 0x1043 && | ||
| 2066 | ac97->subsystem_device == 0x1103)) | ||
| 2052 | val |= 0x03; /* enable */ | 2067 | val |= 0x03; /* enable */ |
| 2053 | else | 2068 | else |
| 2054 | val &= ~0x03; /* disable */ | 2069 | val &= ~0x03; /* disable */ |
diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index 512a3583b0ce..f684aa2c0067 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c | |||
| @@ -317,6 +317,8 @@ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate) | |||
| 317 | return 0; | 317 | return 0; |
| 318 | } | 318 | } |
| 319 | 319 | ||
| 320 | EXPORT_SYMBOL(snd_ac97_set_rate); | ||
| 321 | |||
| 320 | static unsigned short get_pslots(struct snd_ac97 *ac97, unsigned char *rate_table, unsigned short *spdif_slots) | 322 | static unsigned short get_pslots(struct snd_ac97 *ac97, unsigned char *rate_table, unsigned short *spdif_slots) |
| 321 | { | 323 | { |
| 322 | if (!ac97_is_audio(ac97)) | 324 | if (!ac97_is_audio(ac97)) |
| @@ -550,6 +552,8 @@ int snd_ac97_pcm_assign(struct snd_ac97_bus *bus, | |||
| 550 | return 0; | 552 | return 0; |
| 551 | } | 553 | } |
| 552 | 554 | ||
| 555 | EXPORT_SYMBOL(snd_ac97_pcm_assign); | ||
| 556 | |||
| 553 | /** | 557 | /** |
| 554 | * snd_ac97_pcm_open - opens the given AC97 pcm | 558 | * snd_ac97_pcm_open - opens the given AC97 pcm |
| 555 | * @pcm: the ac97 pcm instance | 559 | * @pcm: the ac97 pcm instance |
| @@ -633,6 +637,8 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, | |||
| 633 | return err; | 637 | return err; |
| 634 | } | 638 | } |
| 635 | 639 | ||
| 640 | EXPORT_SYMBOL(snd_ac97_pcm_open); | ||
| 641 | |||
| 636 | /** | 642 | /** |
| 637 | * snd_ac97_pcm_close - closes the given AC97 pcm | 643 | * snd_ac97_pcm_close - closes the given AC97 pcm |
| 638 | * @pcm: the ac97 pcm instance | 644 | * @pcm: the ac97 pcm instance |
| @@ -658,6 +664,8 @@ int snd_ac97_pcm_close(struct ac97_pcm *pcm) | |||
| 658 | return 0; | 664 | return 0; |
| 659 | } | 665 | } |
| 660 | 666 | ||
| 667 | EXPORT_SYMBOL(snd_ac97_pcm_close); | ||
| 668 | |||
| 661 | static int double_rate_hw_constraint_rate(struct snd_pcm_hw_params *params, | 669 | static int double_rate_hw_constraint_rate(struct snd_pcm_hw_params *params, |
| 662 | struct snd_pcm_hw_rule *rule) | 670 | struct snd_pcm_hw_rule *rule) |
| 663 | { | 671 | { |
| @@ -709,3 +717,5 @@ int snd_ac97_pcm_double_rate_rules(struct snd_pcm_runtime *runtime) | |||
| 709 | SNDRV_PCM_HW_PARAM_RATE, -1); | 717 | SNDRV_PCM_HW_PARAM_RATE, -1); |
| 710 | return err; | 718 | return err; |
| 711 | } | 719 | } |
| 720 | |||
| 721 | EXPORT_SYMBOL(snd_ac97_pcm_double_rate_rules); | ||
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 4d523df79cc7..2118df50b9d6 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c | |||
| @@ -433,7 +433,7 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97) | |||
| 433 | prefix = ac97_is_audio(ac97) ? "ac97" : "mc97"; | 433 | prefix = ac97_is_audio(ac97) ? "ac97" : "mc97"; |
| 434 | sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); | 434 | sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); |
| 435 | if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { | 435 | if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { |
| 436 | snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_read); | 436 | snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read); |
| 437 | if (snd_info_register(entry) < 0) { | 437 | if (snd_info_register(entry) < 0) { |
| 438 | snd_info_free_entry(entry); | 438 | snd_info_free_entry(entry); |
| 439 | entry = NULL; | 439 | entry = NULL; |
| @@ -442,10 +442,9 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97) | |||
| 442 | ac97->proc = entry; | 442 | ac97->proc = entry; |
| 443 | sprintf(name, "%s#%d-%d+regs", prefix, ac97->addr, ac97->num); | 443 | sprintf(name, "%s#%d-%d+regs", prefix, ac97->addr, ac97->num); |
| 444 | if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { | 444 | if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { |
| 445 | snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_regs_read); | 445 | snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read); |
| 446 | #ifdef CONFIG_SND_DEBUG | 446 | #ifdef CONFIG_SND_DEBUG |
| 447 | entry->mode |= S_IWUSR; | 447 | entry->mode |= S_IWUSR; |
| 448 | entry->c.text.write_size = 1024; | ||
| 449 | entry->c.text.write = snd_ac97_proc_regs_write; | 448 | entry->c.text.write = snd_ac97_proc_regs_write; |
| 450 | #endif | 449 | #endif |
| 451 | if (snd_info_register(entry) < 0) { | 450 | if (snd_info_register(entry) < 0) { |
diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index 0fb7b3407312..94c26ec05882 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c | |||
| @@ -453,7 +453,7 @@ static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak453 | |||
| 453 | struct snd_info_entry *entry; | 453 | struct snd_info_entry *entry; |
| 454 | 454 | ||
| 455 | if (! snd_card_proc_new(card, "ak4531", &entry)) | 455 | if (! snd_card_proc_new(card, "ak4531", &entry)) |
| 456 | snd_info_set_text_ops(entry, ak4531, 1024, snd_ak4531_proc_read); | 456 | snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); |
| 457 | } | 457 | } |
| 458 | #endif | 458 | #endif |
| 459 | 459 | ||
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index eece1c7e55a0..d42bf4570367 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c | |||
| @@ -753,7 +753,7 @@ snd_ad1889_proc_init(struct snd_ad1889 *chip) | |||
| 753 | struct snd_info_entry *entry; | 753 | struct snd_info_entry *entry; |
| 754 | 754 | ||
| 755 | if (!snd_card_proc_new(chip->card, chip->card->driver, &entry)) | 755 | if (!snd_card_proc_new(chip->card, chip->card->driver, &entry)) |
| 756 | snd_info_set_text_ops(entry, chip, 1024, snd_ad1889_proc_read); | 756 | snd_info_set_text_ops(entry, chip, snd_ad1889_proc_read); |
| 757 | } | 757 | } |
| 758 | 758 | ||
| 759 | static struct ac97_quirk ac97_quirks[] = { | 759 | static struct ac97_quirk ac97_quirks[] = { |
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index e2dbc2118902..5dfdbf6657f2 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c | |||
| @@ -49,7 +49,7 @@ MODULE_SUPPORTED_DEVICE("{{ALI,M5451,pci},{ALI,M5451}}"); | |||
| 49 | static int index = SNDRV_DEFAULT_IDX1; /* Index */ | 49 | static int index = SNDRV_DEFAULT_IDX1; /* Index */ |
| 50 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | 50 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ |
| 51 | static int pcm_channels = 32; | 51 | static int pcm_channels = 32; |
| 52 | static int spdif = 0; | 52 | static int spdif; |
| 53 | 53 | ||
| 54 | module_param(index, int, 0444); | 54 | module_param(index, int, 0444); |
| 55 | MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio."); | 55 | MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio."); |
| @@ -2173,7 +2173,7 @@ static void __devinit snd_ali_proc_init(struct snd_ali *codec) | |||
| 2173 | { | 2173 | { |
| 2174 | struct snd_info_entry *entry; | 2174 | struct snd_info_entry *entry; |
| 2175 | if(!snd_card_proc_new(codec->card, "ali5451", &entry)) | 2175 | if(!snd_card_proc_new(codec->card, "ali5451", &entry)) |
| 2176 | snd_info_set_text_ops(entry, codec, 1024, snd_ali_proc_read); | 2176 | snd_info_set_text_ops(entry, codec, snd_ali_proc_read); |
| 2177 | } | 2177 | } |
| 2178 | 2178 | ||
| 2179 | static int __devinit snd_ali_resources(struct snd_ali *codec) | 2179 | static int __devinit snd_ali_resources(struct snd_ali *codec) |
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 60423b1c678b..a9f08066459a 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c | |||
| @@ -746,8 +746,8 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, | |||
| 746 | card->shortname, chip->alt_port, chip->irq); | 746 | card->shortname, chip->alt_port, chip->irq); |
| 747 | 747 | ||
| 748 | if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000, | 748 | if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000, |
| 749 | gcr+0x30, 1, pci->irq, 0, | 749 | gcr+0x30, MPU401_INFO_INTEGRATED, |
| 750 | &chip->rmidi)) < 0) { | 750 | pci->irq, 0, &chip->rmidi)) < 0) { |
| 751 | printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", gcr+0x30); | 751 | printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", gcr+0x30); |
| 752 | goto out_err; | 752 | goto out_err; |
| 753 | } | 753 | } |
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index d0f759d86d3d..f18a8c0e4688 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c | |||
| @@ -1504,7 +1504,7 @@ static void __devinit snd_atiixp_proc_init(struct atiixp *chip) | |||
| 1504 | struct snd_info_entry *entry; | 1504 | struct snd_info_entry *entry; |
| 1505 | 1505 | ||
| 1506 | if (! snd_card_proc_new(chip->card, "atiixp", &entry)) | 1506 | if (! snd_card_proc_new(chip->card, "atiixp", &entry)) |
| 1507 | snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read); | 1507 | snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read); |
| 1508 | } | 1508 | } |
| 1509 | #else /* !CONFIG_PROC_FS */ | 1509 | #else /* !CONFIG_PROC_FS */ |
| 1510 | #define snd_atiixp_proc_init(chip) | 1510 | #define snd_atiixp_proc_init(chip) |
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 12a34c39caa7..40739057076b 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c | |||
| @@ -1177,7 +1177,7 @@ static void __devinit snd_atiixp_proc_init(struct atiixp_modem *chip) | |||
| 1177 | struct snd_info_entry *entry; | 1177 | struct snd_info_entry *entry; |
| 1178 | 1178 | ||
| 1179 | if (! snd_card_proc_new(chip->card, "atiixp-modem", &entry)) | 1179 | if (! snd_card_proc_new(chip->card, "atiixp-modem", &entry)) |
| 1180 | snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read); | 1180 | snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read); |
| 1181 | } | 1181 | } |
| 1182 | #else | 1182 | #else |
| 1183 | #define snd_atiixp_proc_init(chip) | 1183 | #define snd_atiixp_proc_init(chip) |
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index 126870ec063a..8a3b118989bf 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c | |||
| @@ -261,6 +261,13 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 261 | return err; | 261 | return err; |
| 262 | } | 262 | } |
| 263 | snd_vortex_workaround(pci, pcifix[dev]); | 263 | snd_vortex_workaround(pci, pcifix[dev]); |
| 264 | |||
| 265 | // Card details needed in snd_vortex_midi | ||
| 266 | strcpy(card->driver, CARD_NAME_SHORT); | ||
| 267 | sprintf(card->shortname, "Aureal Vortex %s", CARD_NAME_SHORT); | ||
| 268 | sprintf(card->longname, "%s at 0x%lx irq %i", | ||
| 269 | card->shortname, chip->io, chip->irq); | ||
| 270 | |||
| 264 | // (4) Alloc components. | 271 | // (4) Alloc components. |
| 265 | // ADB pcm. | 272 | // ADB pcm. |
| 266 | if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) { | 273 | if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) { |
| @@ -323,11 +330,6 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 323 | #endif | 330 | #endif |
| 324 | 331 | ||
| 325 | // (5) | 332 | // (5) |
| 326 | strcpy(card->driver, CARD_NAME_SHORT); | ||
| 327 | strcpy(card->shortname, CARD_NAME_SHORT); | ||
| 328 | sprintf(card->longname, "%s at 0x%lx irq %i", | ||
| 329 | card->shortname, chip->io, chip->irq); | ||
| 330 | |||
| 331 | if ((err = pci_read_config_word(pci, PCI_DEVICE_ID, | 333 | if ((err = pci_read_config_word(pci, PCI_DEVICE_ID, |
| 332 | &(chip->device))) < 0) { | 334 | &(chip->device))) < 0) { |
| 333 | snd_card_free(card); | 335 | snd_card_free(card); |
diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index 873f486b07b8..c75d368ea087 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.c | |||
| @@ -47,7 +47,7 @@ static int __devinit snd_vortex_midi(vortex_t * vortex) | |||
| 47 | struct snd_rawmidi *rmidi; | 47 | struct snd_rawmidi *rmidi; |
| 48 | int temp, mode; | 48 | int temp, mode; |
| 49 | struct snd_mpu401 *mpu; | 49 | struct snd_mpu401 *mpu; |
| 50 | int port; | 50 | unsigned long port; |
| 51 | 51 | ||
| 52 | #ifdef VORTEX_MPU401_LEGACY | 52 | #ifdef VORTEX_MPU401_LEGACY |
| 53 | /* EnableHardCodedMPU401Port() */ | 53 | /* EnableHardCodedMPU401Port() */ |
| @@ -70,9 +70,6 @@ static int __devinit snd_vortex_midi(vortex_t * vortex) | |||
| 70 | temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4; | 70 | temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4; |
| 71 | hwwrite(vortex->mmio, VORTEX_CTRL2, temp); | 71 | hwwrite(vortex->mmio, VORTEX_CTRL2, temp); |
| 72 | hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET); | 72 | hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET); |
| 73 | /* Set some kind of mode */ | ||
| 74 | if (mode) | ||
| 75 | hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_ENTER_UART); | ||
| 76 | 73 | ||
| 77 | /* Check if anything is OK. */ | 74 | /* Check if anything is OK. */ |
| 78 | temp = hwread(vortex->mmio, VORTEX_MIDI_DATA); | 75 | temp = hwread(vortex->mmio, VORTEX_MIDI_DATA); |
| @@ -98,7 +95,8 @@ static int __devinit snd_vortex_midi(vortex_t * vortex) | |||
| 98 | port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); | 95 | port = (unsigned long)(vortex->mmio + VORTEX_MIDI_DATA); |
| 99 | if ((temp = | 96 | if ((temp = |
| 100 | snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, | 97 | snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, |
| 101 | 1, 0, 0, &rmidi)) != 0) { | 98 | MPU401_INFO_INTEGRATED | MPU401_INFO_MMIO, |
| 99 | 0, 0, &rmidi)) != 0) { | ||
| 102 | hwwrite(vortex->mmio, VORTEX_CTRL, | 100 | hwwrite(vortex->mmio, VORTEX_CTRL, |
| 103 | (hwread(vortex->mmio, VORTEX_CTRL) & | 101 | (hwread(vortex->mmio, VORTEX_CTRL) & |
| 104 | ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); | 102 | ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); |
| @@ -107,6 +105,9 @@ static int __devinit snd_vortex_midi(vortex_t * vortex) | |||
| 107 | mpu = rmidi->private_data; | 105 | mpu = rmidi->private_data; |
| 108 | mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD); | 106 | mpu->cport = (unsigned long)(vortex->mmio + VORTEX_MIDI_CMD); |
| 109 | #endif | 107 | #endif |
| 108 | /* Overwrite MIDI name */ | ||
| 109 | snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI %d", CARD_NAME_SHORT , vortex->card->number); | ||
| 110 | |||
| 110 | vortex->rmidi = rmidi; | 111 | vortex->rmidi = rmidi; |
| 111 | return 0; | 112 | return 0; |
| 112 | } | 113 | } |
diff --git a/sound/pci/au88x0/au88x0_xtalk.c b/sound/pci/au88x0/au88x0_xtalk.c index 4534e1882ada..b4151e208b71 100644 --- a/sound/pci/au88x0/au88x0_xtalk.c +++ b/sound/pci/au88x0/au88x0_xtalk.c | |||
| @@ -66,31 +66,20 @@ static xtalk_gains_t const asXtalkGainsAllChan = { | |||
| 66 | 0 | 66 | 0 |
| 67 | //0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff,0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff | 67 | //0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff,0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff |
| 68 | }; | 68 | }; |
| 69 | static xtalk_gains_t const asXtalkGainsZeros = { | 69 | static xtalk_gains_t const asXtalkGainsZeros; |
| 70 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
| 71 | }; | ||
| 72 | 70 | ||
| 73 | static xtalk_dline_t const alXtalkDlineZeros = { | 71 | static xtalk_dline_t const alXtalkDlineZeros; |
| 74 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 75 | 0, 0, 0, | ||
| 76 | 0, 0, 0, 0, 0, 0, 0 | ||
| 77 | }; | ||
| 78 | static xtalk_dline_t const alXtalkDlineTest = { | 72 | static xtalk_dline_t const alXtalkDlineTest = { |
| 79 | 0xFC18, 0x03E8FFFF, 0x186A0, 0x7960FFFE, 1, 0xFFFFFFFF, | 73 | 0xFC18, 0x03E8FFFF, 0x186A0, 0x7960FFFE, 1, 0xFFFFFFFF, |
| 80 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 74 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 81 | 0, 0, 0, 0 | 75 | 0, 0, 0, 0 |
| 82 | }; | 76 | }; |
| 83 | 77 | ||
| 84 | static xtalk_instate_t const asXtalkInStateZeros = { 0, 0, 0, 0 }; | 78 | static xtalk_instate_t const asXtalkInStateZeros; |
| 85 | static xtalk_instate_t const asXtalkInStateTest = | 79 | static xtalk_instate_t const asXtalkInStateTest = |
| 86 | { 0xFF80, 0x0080, 0xFFFF, 0x0001 }; | 80 | { 0xFF80, 0x0080, 0xFFFF, 0x0001 }; |
| 87 | static xtalk_state_t const asXtalkOutStateZeros = { | 81 | static xtalk_state_t const asXtalkOutStateZeros; |
| 88 | {0, 0, 0, 0}, | 82 | |
| 89 | {0, 0, 0, 0}, | ||
| 90 | {0, 0, 0, 0}, | ||
| 91 | {0, 0, 0, 0}, | ||
| 92 | {0, 0, 0, 0} | ||
| 93 | }; | ||
| 94 | static short const sDiamondKLeftEq = 0x401d; | 83 | static short const sDiamondKLeftEq = 0x401d; |
| 95 | static short const sDiamondKRightEq = 0x401d; | 84 | static short const sDiamondKRightEq = 0x401d; |
| 96 | static short const sDiamondKLeftXt = 0xF90E; | 85 | static short const sDiamondKLeftXt = 0xF90E; |
| @@ -162,13 +151,7 @@ static xtalk_coefs_t const asXtalkNarrowCoefsRightXt = { | |||
| 162 | {0, 0, 0, 0, 0} | 151 | {0, 0, 0, 0, 0} |
| 163 | }; | 152 | }; |
| 164 | 153 | ||
| 165 | static xtalk_coefs_t const asXtalkCoefsZeros = { | 154 | static xtalk_coefs_t const asXtalkCoefsZeros; |
| 166 | {0, 0, 0, 0, 0}, | ||
| 167 | {0, 0, 0, 0, 0}, | ||
| 168 | {0, 0, 0, 0, 0}, | ||
| 169 | {0, 0, 0, 0, 0}, | ||
| 170 | {0, 0, 0, 0, 0} | ||
| 171 | }; | ||
| 172 | static xtalk_coefs_t const asXtalkCoefsPipe = { | 155 | static xtalk_coefs_t const asXtalkCoefsPipe = { |
| 173 | {0, 0, 0x0FA0, 0, 0}, | 156 | {0, 0, 0x0FA0, 0, 0}, |
| 174 | {0, 0, 0x0FA0, 0, 0}, | 157 | {0, 0, 0x0FA0, 0, 0}, |
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 52a364524262..6e62dafb66cd 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
| @@ -33,14 +33,21 @@ | |||
| 33 | * in the first place >:-P}), | 33 | * in the first place >:-P}), |
| 34 | * I was forced to base this driver on reverse engineering | 34 | * I was forced to base this driver on reverse engineering |
| 35 | * (3 weeks' worth of evenings filled with driver work). | 35 | * (3 weeks' worth of evenings filled with driver work). |
| 36 | * (and no, I did NOT go the easy way: to pick up a PCI128 for 9 Euros) | 36 | * (and no, I did NOT go the easy way: to pick up a SB PCI128 for 9 Euros) |
| 37 | * | 37 | * |
| 38 | * The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name | 38 | * The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name |
| 39 | * for compatibility reasons) has the following features: | 39 | * for compatibility reasons) has the following features: |
| 40 | * | 40 | * |
| 41 | * - builtin AC97 conformant codec (SNR over 80dB) | 41 | * - builtin AC97 conformant codec (SNR over 80dB) |
| 42 | * (really AC97 compliant?? I really doubt it when looking | 42 | * Note that "conformant" != "compliant"!! this chip's mixer register layout |
| 43 | * at the mixer register layout) | 43 | * *differs* from the standard AC97 layout: |
| 44 | * they chose to not implement the headphone register (which is not a | ||
| 45 | * problem since it's merely optional), yet when doing this, they committed | ||
| 46 | * the grave sin of letting other registers follow immediately instead of | ||
| 47 | * keeping a headphone dummy register, thereby shifting the mixer register | ||
| 48 | * addresses illegally. So far unfortunately it looks like the very flexible | ||
| 49 | * ALSA AC97 support is still not enough to easily compensate for such a | ||
| 50 | * grave layout violation despite all tweaks and quirks mechanisms it offers. | ||
| 44 | * - builtin genuine OPL3 | 51 | * - builtin genuine OPL3 |
| 45 | * - full duplex 16bit playback/record at independent sampling rate | 52 | * - full duplex 16bit playback/record at independent sampling rate |
| 46 | * - MPU401 (+ legacy address support) FIXME: how to enable legacy addr?? | 53 | * - MPU401 (+ legacy address support) FIXME: how to enable legacy addr?? |
| @@ -90,10 +97,15 @@ | |||
| 90 | * | 97 | * |
| 91 | * TODO | 98 | * TODO |
| 92 | * - test MPU401 MIDI playback etc. | 99 | * - test MPU401 MIDI playback etc. |
| 93 | * - power management. See e.g. intel8x0 or cs4281. | 100 | * - add some power micro-management (disable various units of the card |
| 94 | * This would be nice since the chip runs a bit hot, and it's *required* | 101 | * as long as they're unused). However this requires I/O ports which I |
| 95 | * anyway for proper ACPI power management. | 102 | * haven't figured out yet and which thus might not even exist... |
| 103 | * The standard suspend/resume functionality could probably make use of | ||
| 104 | * some improvement, too... | ||
| 96 | * - figure out what all unknown port bits are responsible for | 105 | * - figure out what all unknown port bits are responsible for |
| 106 | * - figure out some cleverly evil scheme to possibly make ALSA AC97 code | ||
| 107 | * fully accept our quite incompatible ""AC97"" mixer and thus save some | ||
| 108 | * code (but I'm not too optimistic that doing this is possible at all) | ||
| 97 | */ | 109 | */ |
| 98 | 110 | ||
| 99 | #include <sound/driver.h> | 111 | #include <sound/driver.h> |
| @@ -214,6 +226,16 @@ struct snd_azf3328 { | |||
| 214 | 226 | ||
| 215 | struct pci_dev *pci; | 227 | struct pci_dev *pci; |
| 216 | int irq; | 228 | int irq; |
| 229 | |||
| 230 | #ifdef CONFIG_PM | ||
| 231 | /* register value containers for power management | ||
| 232 | * Note: not always full I/O range preserved (just like Win driver!) */ | ||
| 233 | u16 saved_regs_codec [AZF_IO_SIZE_CODEC_PM / 2]; | ||
| 234 | u16 saved_regs_io2 [AZF_IO_SIZE_IO2_PM / 2]; | ||
| 235 | u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; | ||
| 236 | u16 saved_regs_synth[AZF_IO_SIZE_SYNTH_PM / 2]; | ||
| 237 | u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; | ||
| 238 | #endif | ||
| 217 | }; | 239 | }; |
| 218 | 240 | ||
| 219 | static const struct pci_device_id snd_azf3328_ids[] __devinitdata = { | 241 | static const struct pci_device_id snd_azf3328_ids[] __devinitdata = { |
| @@ -317,10 +339,8 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg | |||
| 317 | else | 339 | else |
| 318 | dst_vol_left &= ~0x80; | 340 | dst_vol_left &= ~0x80; |
| 319 | 341 | ||
| 320 | do | 342 | do { |
| 321 | { | 343 | if (!left_done) { |
| 322 | if (!left_done) | ||
| 323 | { | ||
| 324 | if (curr_vol_left > dst_vol_left) | 344 | if (curr_vol_left > dst_vol_left) |
| 325 | curr_vol_left--; | 345 | curr_vol_left--; |
| 326 | else | 346 | else |
| @@ -330,8 +350,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg | |||
| 330 | left_done = 1; | 350 | left_done = 1; |
| 331 | outb(curr_vol_left, portbase + 1); | 351 | outb(curr_vol_left, portbase + 1); |
| 332 | } | 352 | } |
| 333 | if (!right_done) | 353 | if (!right_done) { |
| 334 | { | ||
| 335 | if (curr_vol_right > dst_vol_right) | 354 | if (curr_vol_right > dst_vol_right) |
| 336 | curr_vol_right--; | 355 | curr_vol_right--; |
| 337 | else | 356 | else |
| @@ -346,8 +365,7 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, int reg | |||
| 346 | } | 365 | } |
| 347 | if (delay) | 366 | if (delay) |
| 348 | mdelay(delay); | 367 | mdelay(delay); |
| 349 | } | 368 | } while ((!left_done) || (!right_done)); |
| 350 | while ((!left_done) || (!right_done)); | ||
| 351 | snd_azf3328_dbgcallleave(); | 369 | snd_azf3328_dbgcallleave(); |
| 352 | } | 370 | } |
| 353 | 371 | ||
| @@ -514,15 +532,18 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, | |||
| 514 | struct snd_ctl_elem_info *uinfo) | 532 | struct snd_ctl_elem_info *uinfo) |
| 515 | { | 533 | { |
| 516 | static const char * const texts1[] = { | 534 | static const char * const texts1[] = { |
| 517 | "ModemOut1", "ModemOut2" | 535 | "Mic1", "Mic2" |
| 518 | }; | 536 | }; |
| 519 | static const char * const texts2[] = { | 537 | static const char * const texts2[] = { |
| 520 | "MonoSelectSource1", "MonoSelectSource2" | 538 | "Mix", "Mic" |
| 521 | }; | 539 | }; |
| 522 | static const char * const texts3[] = { | 540 | static const char * const texts3[] = { |
| 523 | "Mic", "CD", "Video", "Aux", | 541 | "Mic", "CD", "Video", "Aux", |
| 524 | "Line", "Mix", "Mix Mono", "Phone" | 542 | "Line", "Mix", "Mix Mono", "Phone" |
| 525 | }; | 543 | }; |
| 544 | static const char * const texts4[] = { | ||
| 545 | "pre 3D", "post 3D" | ||
| 546 | }; | ||
| 526 | struct azf3328_mixer_reg reg; | 547 | struct azf3328_mixer_reg reg; |
| 527 | 548 | ||
| 528 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 549 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
| @@ -531,14 +552,19 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol, | |||
| 531 | uinfo->value.enumerated.items = reg.enum_c; | 552 | uinfo->value.enumerated.items = reg.enum_c; |
| 532 | if (uinfo->value.enumerated.item > reg.enum_c - 1U) | 553 | if (uinfo->value.enumerated.item > reg.enum_c - 1U) |
| 533 | uinfo->value.enumerated.item = reg.enum_c - 1U; | 554 | uinfo->value.enumerated.item = reg.enum_c - 1U; |
| 534 | if (reg.reg == IDX_MIXER_ADVCTL2) | 555 | if (reg.reg == IDX_MIXER_ADVCTL2) { |
| 535 | { | 556 | switch(reg.lchan_shift) { |
| 536 | if (reg.lchan_shift == 8) /* modem out sel */ | 557 | case 8: /* modem out sel */ |
| 537 | strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]); | 558 | strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]); |
| 538 | else /* mono sel source */ | 559 | break; |
| 560 | case 9: /* mono sel source */ | ||
| 539 | strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]); | 561 | strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]); |
| 540 | } | 562 | break; |
| 541 | else | 563 | case 15: /* PCM Out Path */ |
| 564 | strcpy(uinfo->value.enumerated.name, texts4[uinfo->value.enumerated.item]); | ||
| 565 | break; | ||
| 566 | } | ||
| 567 | } else | ||
| 542 | strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item] | 568 | strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item] |
| 543 | ); | 569 | ); |
| 544 | return 0; | 570 | return 0; |
| @@ -554,12 +580,10 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol, | |||
| 554 | 580 | ||
| 555 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 581 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
| 556 | val = snd_azf3328_mixer_inw(chip, reg.reg); | 582 | val = snd_azf3328_mixer_inw(chip, reg.reg); |
| 557 | if (reg.reg == IDX_MIXER_REC_SELECT) | 583 | if (reg.reg == IDX_MIXER_REC_SELECT) { |
| 558 | { | ||
| 559 | ucontrol->value.enumerated.item[0] = (val >> 8) & (reg.enum_c - 1); | 584 | ucontrol->value.enumerated.item[0] = (val >> 8) & (reg.enum_c - 1); |
| 560 | ucontrol->value.enumerated.item[1] = (val >> 0) & (reg.enum_c - 1); | 585 | ucontrol->value.enumerated.item[1] = (val >> 0) & (reg.enum_c - 1); |
| 561 | } | 586 | } else |
| 562 | else | ||
| 563 | ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1); | 587 | ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1); |
| 564 | 588 | ||
| 565 | snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n", | 589 | snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n", |
| @@ -579,16 +603,13 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, | |||
| 579 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 603 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
| 580 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); | 604 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); |
| 581 | val = oreg; | 605 | val = oreg; |
| 582 | if (reg.reg == IDX_MIXER_REC_SELECT) | 606 | if (reg.reg == IDX_MIXER_REC_SELECT) { |
| 583 | { | ||
| 584 | if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U || | 607 | if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U || |
| 585 | ucontrol->value.enumerated.item[1] > reg.enum_c - 1U) | 608 | ucontrol->value.enumerated.item[1] > reg.enum_c - 1U) |
| 586 | return -EINVAL; | 609 | return -EINVAL; |
| 587 | val = (ucontrol->value.enumerated.item[0] << 8) | | 610 | val = (ucontrol->value.enumerated.item[0] << 8) | |
| 588 | (ucontrol->value.enumerated.item[1] << 0); | 611 | (ucontrol->value.enumerated.item[1] << 0); |
| 589 | } | 612 | } else { |
| 590 | else | ||
| 591 | { | ||
| 592 | if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U) | 613 | if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U) |
| 593 | return -EINVAL; | 614 | return -EINVAL; |
| 594 | val &= ~((reg.enum_c - 1) << reg.lchan_shift); | 615 | val &= ~((reg.enum_c - 1) << reg.lchan_shift); |
| @@ -629,13 +650,14 @@ static const struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata | |||
| 629 | AZF3328_MIXER_VOL_MONO("Modem Playback Volume", IDX_MIXER_MODEMOUT, 0x1f, 1), | 650 | AZF3328_MIXER_VOL_MONO("Modem Playback Volume", IDX_MIXER_MODEMOUT, 0x1f, 1), |
| 630 | AZF3328_MIXER_SWITCH("Modem Capture Switch", IDX_MIXER_MODEMIN, 15, 1), | 651 | AZF3328_MIXER_SWITCH("Modem Capture Switch", IDX_MIXER_MODEMIN, 15, 1), |
| 631 | AZF3328_MIXER_VOL_MONO("Modem Capture Volume", IDX_MIXER_MODEMIN, 0x1f, 1), | 652 | AZF3328_MIXER_VOL_MONO("Modem Capture Volume", IDX_MIXER_MODEMIN, 0x1f, 1), |
| 632 | AZF3328_MIXER_ENUM("Modem Out Select", IDX_MIXER_ADVCTL2, 2, 8), | 653 | AZF3328_MIXER_ENUM("Mic Select", IDX_MIXER_ADVCTL2, 2, 8), |
| 633 | AZF3328_MIXER_ENUM("Mono Select Source", IDX_MIXER_ADVCTL2, 2, 9), | 654 | AZF3328_MIXER_ENUM("Mono Output Select", IDX_MIXER_ADVCTL2, 2, 9), |
| 655 | AZF3328_MIXER_ENUM("PCM", IDX_MIXER_ADVCTL2, 2, 15), /* PCM Out Path, place in front since it controls *both* 3D and Bass/Treble! */ | ||
| 634 | AZF3328_MIXER_VOL_SPECIAL("Tone Control - Treble", IDX_MIXER_BASSTREBLE, 0x07, 1, 0), | 656 | AZF3328_MIXER_VOL_SPECIAL("Tone Control - Treble", IDX_MIXER_BASSTREBLE, 0x07, 1, 0), |
| 635 | AZF3328_MIXER_VOL_SPECIAL("Tone Control - Bass", IDX_MIXER_BASSTREBLE, 0x07, 9, 0), | 657 | AZF3328_MIXER_VOL_SPECIAL("Tone Control - Bass", IDX_MIXER_BASSTREBLE, 0x07, 9, 0), |
| 636 | AZF3328_MIXER_SWITCH("3D Control - Switch", IDX_MIXER_ADVCTL2, 13, 0), | 658 | AZF3328_MIXER_SWITCH("3D Control - Switch", IDX_MIXER_ADVCTL2, 13, 0), |
| 637 | AZF3328_MIXER_VOL_SPECIAL("3D Control - Wide", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */ | 659 | AZF3328_MIXER_VOL_SPECIAL("3D Control - Width", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */ |
| 638 | AZF3328_MIXER_VOL_SPECIAL("3D Control - Space", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */ | 660 | AZF3328_MIXER_VOL_SPECIAL("3D Control - Depth", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */ |
| 639 | #if MIXER_TESTING | 661 | #if MIXER_TESTING |
| 640 | AZF3328_MIXER_SWITCH("0", IDX_MIXER_ADVCTL2, 0, 0), | 662 | AZF3328_MIXER_SWITCH("0", IDX_MIXER_ADVCTL2, 0, 0), |
| 641 | AZF3328_MIXER_SWITCH("1", IDX_MIXER_ADVCTL2, 1, 0), | 663 | AZF3328_MIXER_SWITCH("1", IDX_MIXER_ADVCTL2, 1, 0), |
| @@ -813,22 +835,18 @@ snd_azf3328_setdmaa(struct snd_azf3328 *chip, | |||
| 813 | unsigned int is_running; | 835 | unsigned int is_running; |
| 814 | 836 | ||
| 815 | snd_azf3328_dbgcallenter(); | 837 | snd_azf3328_dbgcallenter(); |
| 816 | if (do_recording) | 838 | if (do_recording) { |
| 817 | { | ||
| 818 | /* access capture registers, i.e. skip playback reg section */ | 839 | /* access capture registers, i.e. skip playback reg section */ |
| 819 | portbase = chip->codec_port + 0x20; | 840 | portbase = chip->codec_port + 0x20; |
| 820 | is_running = chip->is_recording; | 841 | is_running = chip->is_recording; |
| 821 | } | 842 | } else { |
| 822 | else | ||
| 823 | { | ||
| 824 | /* access the playback register section */ | 843 | /* access the playback register section */ |
| 825 | portbase = chip->codec_port + 0x00; | 844 | portbase = chip->codec_port + 0x00; |
| 826 | is_running = chip->is_playing; | 845 | is_running = chip->is_playing; |
| 827 | } | 846 | } |
| 828 | 847 | ||
| 829 | /* AZF3328 uses a two buffer pointer DMA playback approach */ | 848 | /* AZF3328 uses a two buffer pointer DMA playback approach */ |
| 830 | if (!is_running) | 849 | if (!is_running) { |
| 831 | { | ||
| 832 | unsigned long addr_area2; | 850 | unsigned long addr_area2; |
| 833 | unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */ | 851 | unsigned long count_areas, count_tmp; /* width 32bit -- overflow!! */ |
| 834 | count_areas = size/2; | 852 | count_areas = size/2; |
| @@ -961,6 +979,13 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 961 | chip->is_playing = 1; | 979 | chip->is_playing = 1; |
| 962 | snd_azf3328_dbgplay("STARTED PLAYBACK\n"); | 980 | snd_azf3328_dbgplay("STARTED PLAYBACK\n"); |
| 963 | break; | 981 | break; |
| 982 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 983 | snd_azf3328_dbgplay("RESUME PLAYBACK\n"); | ||
| 984 | /* resume playback if we were active */ | ||
| 985 | if (chip->is_playing) | ||
| 986 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | ||
| 987 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); | ||
| 988 | break; | ||
| 964 | case SNDRV_PCM_TRIGGER_STOP: | 989 | case SNDRV_PCM_TRIGGER_STOP: |
| 965 | snd_azf3328_dbgplay("STOP PLAYBACK\n"); | 990 | snd_azf3328_dbgplay("STOP PLAYBACK\n"); |
| 966 | 991 | ||
| @@ -988,6 +1013,12 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 988 | chip->is_playing = 0; | 1013 | chip->is_playing = 0; |
| 989 | snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); | 1014 | snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); |
| 990 | break; | 1015 | break; |
| 1016 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 1017 | snd_azf3328_dbgplay("SUSPEND PLAYBACK\n"); | ||
| 1018 | /* make sure playback is stopped */ | ||
| 1019 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | ||
| 1020 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME); | ||
| 1021 | break; | ||
| 991 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1022 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
| 992 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); | 1023 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); |
| 993 | break; | 1024 | break; |
| @@ -995,6 +1026,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 995 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); | 1026 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); |
| 996 | break; | 1027 | break; |
| 997 | default: | 1028 | default: |
| 1029 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | ||
| 998 | return -EINVAL; | 1030 | return -EINVAL; |
| 999 | } | 1031 | } |
| 1000 | 1032 | ||
| @@ -1068,6 +1100,13 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1068 | chip->is_recording = 1; | 1100 | chip->is_recording = 1; |
| 1069 | snd_azf3328_dbgplay("STARTED CAPTURE\n"); | 1101 | snd_azf3328_dbgplay("STARTED CAPTURE\n"); |
| 1070 | break; | 1102 | break; |
| 1103 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 1104 | snd_azf3328_dbgplay("RESUME CAPTURE\n"); | ||
| 1105 | /* resume recording if we were active */ | ||
| 1106 | if (chip->is_recording) | ||
| 1107 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | ||
| 1108 | snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME); | ||
| 1109 | break; | ||
| 1071 | case SNDRV_PCM_TRIGGER_STOP: | 1110 | case SNDRV_PCM_TRIGGER_STOP: |
| 1072 | snd_azf3328_dbgplay("STOP CAPTURE\n"); | 1111 | snd_azf3328_dbgplay("STOP CAPTURE\n"); |
| 1073 | 1112 | ||
| @@ -1088,6 +1127,12 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1088 | chip->is_recording = 0; | 1127 | chip->is_recording = 0; |
| 1089 | snd_azf3328_dbgplay("STOPPED CAPTURE\n"); | 1128 | snd_azf3328_dbgplay("STOPPED CAPTURE\n"); |
| 1090 | break; | 1129 | break; |
| 1130 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 1131 | snd_azf3328_dbgplay("SUSPEND CAPTURE\n"); | ||
| 1132 | /* make sure recording is stopped */ | ||
| 1133 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | ||
| 1134 | snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) & ~DMA_RESUME); | ||
| 1135 | break; | ||
| 1091 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1136 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
| 1092 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); | 1137 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); |
| 1093 | break; | 1138 | break; |
| @@ -1095,6 +1140,7 @@ snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1095 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); | 1140 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); |
| 1096 | break; | 1141 | break; |
| 1097 | default: | 1142 | default: |
| 1143 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | ||
| 1098 | return -EINVAL; | 1144 | return -EINVAL; |
| 1099 | } | 1145 | } |
| 1100 | 1146 | ||
| @@ -1163,8 +1209,7 @@ snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
| 1163 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), | 1209 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), |
| 1164 | status); | 1210 | status); |
| 1165 | 1211 | ||
| 1166 | if (status & IRQ_TIMER) | 1212 | if (status & IRQ_TIMER) { |
| 1167 | { | ||
| 1168 | /* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */ | 1213 | /* snd_azf3328_dbgplay("timer %ld\n", inl(chip->codec_port+IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK); */ |
| 1169 | if (chip->timer) | 1214 | if (chip->timer) |
| 1170 | snd_timer_interrupt(chip->timer, chip->timer->sticks); | 1215 | snd_timer_interrupt(chip->timer, chip->timer->sticks); |
| @@ -1174,50 +1219,43 @@ snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
| 1174 | spin_unlock(&chip->reg_lock); | 1219 | spin_unlock(&chip->reg_lock); |
| 1175 | snd_azf3328_dbgplay("azt3328: timer IRQ\n"); | 1220 | snd_azf3328_dbgplay("azt3328: timer IRQ\n"); |
| 1176 | } | 1221 | } |
| 1177 | if (status & IRQ_PLAYBACK) | 1222 | if (status & IRQ_PLAYBACK) { |
| 1178 | { | ||
| 1179 | spin_lock(&chip->reg_lock); | 1223 | spin_lock(&chip->reg_lock); |
| 1180 | which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE); | 1224 | which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE); |
| 1181 | /* ack all IRQ types immediately */ | 1225 | /* ack all IRQ types immediately */ |
| 1182 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); | 1226 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); |
| 1183 | spin_unlock(&chip->reg_lock); | 1227 | spin_unlock(&chip->reg_lock); |
| 1184 | 1228 | ||
| 1185 | if (chip->pcm && chip->playback_substream) | 1229 | if (chip->pcm && chip->playback_substream) { |
| 1186 | { | ||
| 1187 | snd_pcm_period_elapsed(chip->playback_substream); | 1230 | snd_pcm_period_elapsed(chip->playback_substream); |
| 1188 | snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", | 1231 | snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", |
| 1189 | which, | 1232 | which, |
| 1190 | inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); | 1233 | inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); |
| 1191 | } | 1234 | } else |
| 1192 | else | ||
| 1193 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); | 1235 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); |
| 1194 | if (which & IRQ_PLAY_SOMETHING) | 1236 | if (which & IRQ_PLAY_SOMETHING) |
| 1195 | snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); | 1237 | snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); |
| 1196 | } | 1238 | } |
| 1197 | if (status & IRQ_RECORDING) | 1239 | if (status & IRQ_RECORDING) { |
| 1198 | { | ||
| 1199 | spin_lock(&chip->reg_lock); | 1240 | spin_lock(&chip->reg_lock); |
| 1200 | which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE); | 1241 | which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE); |
| 1201 | /* ack all IRQ types immediately */ | 1242 | /* ack all IRQ types immediately */ |
| 1202 | snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); | 1243 | snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); |
| 1203 | spin_unlock(&chip->reg_lock); | 1244 | spin_unlock(&chip->reg_lock); |
| 1204 | 1245 | ||
| 1205 | if (chip->pcm && chip->capture_substream) | 1246 | if (chip->pcm && chip->capture_substream) { |
| 1206 | { | ||
| 1207 | snd_pcm_period_elapsed(chip->capture_substream); | 1247 | snd_pcm_period_elapsed(chip->capture_substream); |
| 1208 | snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", | 1248 | snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", |
| 1209 | which, | 1249 | which, |
| 1210 | inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); | 1250 | inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); |
| 1211 | } | 1251 | } else |
| 1212 | else | ||
| 1213 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); | 1252 | snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); |
| 1214 | if (which & IRQ_REC_SOMETHING) | 1253 | if (which & IRQ_REC_SOMETHING) |
| 1215 | snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); | 1254 | snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); |
| 1216 | } | 1255 | } |
| 1217 | /* MPU401 has less critical IRQ requirements | 1256 | /* MPU401 has less critical IRQ requirements |
| 1218 | * than timer and playback/recording, right? */ | 1257 | * than timer and playback/recording, right? */ |
| 1219 | if (status & IRQ_MPU401) | 1258 | if (status & IRQ_MPU401) { |
| 1220 | { | ||
| 1221 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); | 1259 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); |
| 1222 | 1260 | ||
| 1223 | /* hmm, do we have to ack the IRQ here somehow? | 1261 | /* hmm, do we have to ack the IRQ here somehow? |
| @@ -1511,8 +1549,7 @@ snd_azf3328_timer_start(struct snd_timer *timer) | |||
| 1511 | snd_azf3328_dbgcallenter(); | 1549 | snd_azf3328_dbgcallenter(); |
| 1512 | chip = snd_timer_chip(timer); | 1550 | chip = snd_timer_chip(timer); |
| 1513 | delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK; | 1551 | delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK; |
| 1514 | if (delay < 49) | 1552 | if (delay < 49) { |
| 1515 | { | ||
| 1516 | /* uhoh, that's not good, since user-space won't know about | 1553 | /* uhoh, that's not good, since user-space won't know about |
| 1517 | * this timing tweak | 1554 | * this timing tweak |
| 1518 | * (we need to do it to avoid a lockup, though) */ | 1555 | * (we need to do it to avoid a lockup, though) */ |
| @@ -1766,9 +1803,11 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 1766 | goto out_err; | 1803 | goto out_err; |
| 1767 | } | 1804 | } |
| 1768 | 1805 | ||
| 1806 | card->private_data = chip; | ||
| 1807 | |||
| 1769 | if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, | 1808 | if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, |
| 1770 | chip->mpu_port, 1, pci->irq, 0, | 1809 | chip->mpu_port, MPU401_INFO_INTEGRATED, |
| 1771 | &chip->rmidi)) < 0) { | 1810 | pci->irq, 0, &chip->rmidi)) < 0) { |
| 1772 | snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); | 1811 | snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); |
| 1773 | goto out_err; | 1812 | goto out_err; |
| 1774 | } | 1813 | } |
| @@ -1791,6 +1830,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 1791 | } | 1830 | } |
| 1792 | } | 1831 | } |
| 1793 | 1832 | ||
| 1833 | opl3->private_data = chip; | ||
| 1834 | |||
| 1794 | sprintf(card->longname, "%s at 0x%lx, irq %i", | 1835 | sprintf(card->longname, "%s at 0x%lx, irq %i", |
| 1795 | card->shortname, chip->codec_port, chip->irq); | 1836 | card->shortname, chip->codec_port, chip->irq); |
| 1796 | 1837 | ||
| @@ -1834,11 +1875,80 @@ snd_azf3328_remove(struct pci_dev *pci) | |||
| 1834 | snd_azf3328_dbgcallleave(); | 1875 | snd_azf3328_dbgcallleave(); |
| 1835 | } | 1876 | } |
| 1836 | 1877 | ||
| 1878 | #ifdef CONFIG_PM | ||
| 1879 | static int | ||
| 1880 | snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | ||
| 1881 | { | ||
| 1882 | struct snd_card *card = pci_get_drvdata(pci); | ||
| 1883 | struct snd_azf3328 *chip = card->private_data; | ||
| 1884 | int reg; | ||
| 1885 | |||
| 1886 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
| 1887 | |||
| 1888 | snd_pcm_suspend_all(chip->pcm); | ||
| 1889 | |||
| 1890 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) | ||
| 1891 | chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2); | ||
| 1892 | |||
| 1893 | /* make sure to disable master volume etc. to prevent looping sound */ | ||
| 1894 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); | ||
| 1895 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | ||
| 1896 | |||
| 1897 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) | ||
| 1898 | chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2); | ||
| 1899 | for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) | ||
| 1900 | chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2); | ||
| 1901 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) | ||
| 1902 | chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2); | ||
| 1903 | for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) | ||
| 1904 | chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2); | ||
| 1905 | |||
| 1906 | pci_set_power_state(pci, PCI_D3hot); | ||
| 1907 | pci_disable_device(pci); | ||
| 1908 | pci_save_state(pci); | ||
| 1909 | return 0; | ||
| 1910 | } | ||
| 1911 | |||
| 1912 | static int | ||
| 1913 | snd_azf3328_resume(struct pci_dev *pci) | ||
| 1914 | { | ||
| 1915 | struct snd_card *card = pci_get_drvdata(pci); | ||
| 1916 | struct snd_azf3328 *chip = card->private_data; | ||
| 1917 | int reg; | ||
| 1918 | |||
| 1919 | pci_restore_state(pci); | ||
| 1920 | pci_enable_device(pci); | ||
| 1921 | pci_set_power_state(pci, PCI_D0); | ||
| 1922 | pci_set_master(pci); | ||
| 1923 | |||
| 1924 | for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) | ||
| 1925 | outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2); | ||
| 1926 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) | ||
| 1927 | outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2); | ||
| 1928 | for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) | ||
| 1929 | outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2); | ||
| 1930 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) | ||
| 1931 | outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2); | ||
| 1932 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) | ||
| 1933 | outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2); | ||
| 1934 | |||
| 1935 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
| 1936 | return 0; | ||
| 1937 | } | ||
| 1938 | #endif | ||
| 1939 | |||
| 1940 | |||
| 1941 | |||
| 1942 | |||
| 1837 | static struct pci_driver driver = { | 1943 | static struct pci_driver driver = { |
| 1838 | .name = "AZF3328", | 1944 | .name = "AZF3328", |
| 1839 | .id_table = snd_azf3328_ids, | 1945 | .id_table = snd_azf3328_ids, |
| 1840 | .probe = snd_azf3328_probe, | 1946 | .probe = snd_azf3328_probe, |
| 1841 | .remove = __devexit_p(snd_azf3328_remove), | 1947 | .remove = __devexit_p(snd_azf3328_remove), |
| 1948 | #ifdef CONFIG_PM | ||
| 1949 | .suspend = snd_azf3328_suspend, | ||
| 1950 | .resume = snd_azf3328_resume, | ||
| 1951 | #endif | ||
| 1842 | }; | 1952 | }; |
| 1843 | 1953 | ||
| 1844 | static int __init | 1954 | static int __init |
diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h index f489bdaf6d40..b4f3e3cd006b 100644 --- a/sound/pci/azt3328.h +++ b/sound/pci/azt3328.h | |||
| @@ -5,6 +5,9 @@ | |||
| 5 | 5 | ||
| 6 | /*** main I/O area port indices ***/ | 6 | /*** main I/O area port indices ***/ |
| 7 | /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ | 7 | /* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ |
| 8 | #define AZF_IO_SIZE_CODEC 0x80 | ||
| 9 | #define AZF_IO_SIZE_CODEC_PM 0x70 | ||
| 10 | |||
| 8 | /* the driver initialisation suggests a layout of 4 main areas: | 11 | /* the driver initialisation suggests a layout of 4 main areas: |
| 9 | * from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe MPU401??). | 12 | * from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe MPU401??). |
| 10 | * And another area from 0x60 to 0x6f (DirectX timer, IRQ management, | 13 | * And another area from 0x60 to 0x6f (DirectX timer, IRQ management, |
| @@ -87,7 +90,7 @@ | |||
| 87 | #define IDX_IO_REC_DMA_CURROFS 0x34 /* PU:0x00000000 */ | 90 | #define IDX_IO_REC_DMA_CURROFS 0x34 /* PU:0x00000000 */ |
| 88 | #define IDX_IO_REC_SOUNDFORMAT 0x36 /* PU:0x0000 */ | 91 | #define IDX_IO_REC_SOUNDFORMAT 0x36 /* PU:0x0000 */ |
| 89 | 92 | ||
| 90 | /** hmm, what is this I/O area for? MPU401?? (after playback, recording, ???, timer) **/ | 93 | /** hmm, what is this I/O area for? MPU401?? or external DAC via I2S?? (after playback, recording, ???, timer) **/ |
| 91 | #define IDX_IO_SOMETHING_FLAGS 0x40 /* gets set to 0x34 just like port 0x0 and 0x20 on card init, PU:0x0000 */ | 94 | #define IDX_IO_SOMETHING_FLAGS 0x40 /* gets set to 0x34 just like port 0x0 and 0x20 on card init, PU:0x0000 */ |
| 92 | /* general */ | 95 | /* general */ |
| 93 | #define IDX_IO_42H 0x42 /* PU:0x0001 */ | 96 | #define IDX_IO_42H 0x42 /* PU:0x0001 */ |
| @@ -107,7 +110,8 @@ | |||
| 107 | #define IRQ_UNKNOWN2 0x0080 /* probably unused */ | 110 | #define IRQ_UNKNOWN2 0x0080 /* probably unused */ |
| 108 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ | 111 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ |
| 109 | #define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */ | 112 | #define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */ |
| 110 | #define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated; actually inhibits PCM playback!!! maybe power management?? */ | 113 | #define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); actually inhibits PCM playback!!! maybe power management?? */ |
| 114 | #define IO_6A_PAUSE_PLAYBACK 0x0200 /* bit 9; sure, this pauses playback, but what the heck is this really about?? */ | ||
| 111 | #define IDX_IO_6CH 0x6C | 115 | #define IDX_IO_6CH 0x6C |
| 112 | #define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */ | 116 | #define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */ |
| 113 | /* further I/O indices not saved/restored, so probably not used */ | 117 | /* further I/O indices not saved/restored, so probably not used */ |
| @@ -115,15 +119,25 @@ | |||
| 115 | 119 | ||
| 116 | /*** I/O 2 area port indices ***/ | 120 | /*** I/O 2 area port indices ***/ |
| 117 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ | 121 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ |
| 122 | #define AZF_IO_SIZE_IO2 0x08 | ||
| 123 | #define AZF_IO_SIZE_IO2_PM 0x06 | ||
| 124 | |||
| 118 | #define IDX_IO2_LEGACY_ADDR 0x04 | 125 | #define IDX_IO2_LEGACY_ADDR 0x04 |
| 119 | #define LEGACY_SOMETHING 0x01 /* OPL3?? */ | 126 | #define LEGACY_SOMETHING 0x01 /* OPL3?? */ |
| 120 | #define LEGACY_JOY 0x08 | 127 | #define LEGACY_JOY 0x08 |
| 121 | 128 | ||
| 129 | #define AZF_IO_SIZE_MPU 0x04 | ||
| 130 | #define AZF_IO_SIZE_MPU_PM 0x04 | ||
| 131 | |||
| 132 | #define AZF_IO_SIZE_SYNTH 0x08 | ||
| 133 | #define AZF_IO_SIZE_SYNTH_PM 0x06 | ||
| 122 | 134 | ||
| 123 | /*** mixer I/O area port indices ***/ | 135 | /*** mixer I/O area port indices ***/ |
| 124 | /* (only 0x22 of 0x40 bytes saved/restored by Windows driver) | 136 | /* (only 0x22 of 0x40 bytes saved/restored by Windows driver) |
| 125 | * generally spoken: AC97 register index = AZF3328 mixer reg index + 2 | 137 | * UNFORTUNATELY azf3328 is NOT truly AC97 compliant: see main file intro */ |
| 126 | * (in other words: AZF3328 NOT fully AC97 compliant) */ | 138 | #define AZF_IO_SIZE_MIXER 0x40 |
| 139 | #define AZF_IO_SIZE_MIXER_PM 0x22 | ||
| 140 | |||
| 127 | #define MIXER_VOLUME_RIGHT_MASK 0x001f | 141 | #define MIXER_VOLUME_RIGHT_MASK 0x001f |
| 128 | #define MIXER_VOLUME_LEFT_MASK 0x1f00 | 142 | #define MIXER_VOLUME_LEFT_MASK 0x1f00 |
| 129 | #define MIXER_MUTE_MASK 0x8000 | 143 | #define MIXER_MUTE_MASK 0x8000 |
| @@ -156,14 +170,14 @@ | |||
| 156 | #define IDX_MIXER_ADVCTL1 0x1e | 170 | #define IDX_MIXER_ADVCTL1 0x1e |
| 157 | /* unlisted bits are unmodifiable */ | 171 | /* unlisted bits are unmodifiable */ |
| 158 | #define MIXER_ADVCTL1_3DWIDTH_MASK 0x000e | 172 | #define MIXER_ADVCTL1_3DWIDTH_MASK 0x000e |
| 159 | #define MIXER_ADVCTL1_HIFI3D_MASK 0x0300 | 173 | #define MIXER_ADVCTL1_HIFI3D_MASK 0x0300 /* yup, this is missing the high bit that official AC97 contains, plus it doesn't have linear bit value range behaviour but instead acts weirdly (possibly we're dealing with two *different* 3D settings here??) */ |
| 160 | #define IDX_MIXER_ADVCTL2 0x20 /* resembles AC97_GENERAL_PURPOSE reg! */ | 174 | #define IDX_MIXER_ADVCTL2 0x20 /* subset of AC97_GENERAL_PURPOSE reg! */ |
| 161 | /* unlisted bits are unmodifiable */ | 175 | /* unlisted bits are unmodifiable */ |
| 162 | #define MIXER_ADVCTL2_BIT7 0x0080 /* WaveOut 3D Bypass? mutes WaveOut at LineOut */ | 176 | #define MIXER_ADVCTL2_LPBK 0x0080 /* Loopback mode -- Win driver: "WaveOut3DBypass"? mutes WaveOut at LineOut */ |
| 163 | #define MIXER_ADVCTL2_BIT8 0x0100 /* is this Modem Out Select? */ | 177 | #define MIXER_ADVCTL2_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 -- Win driver: "ModemOutSelect"?? */ |
| 164 | #define MIXER_ADVCTL2_BIT9 0x0200 /* Mono Select Source? */ | 178 | #define MIXER_ADVCTL2_MIX 0x0200 /* Mono output select 0=Mix, 1=Mic; Win driver: "MonoSelectSource"?? */ |
| 165 | #define MIXER_ADVCTL2_BIT13 0x2000 /* 3D enable? */ | 179 | #define MIXER_ADVCTL2_3D 0x2000 /* 3D Enhancement 1=on */ |
| 166 | #define MIXER_ADVCTL2_BIT15 0x8000 /* unknown */ | 180 | #define MIXER_ADVCTL2_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */ |
| 167 | 181 | ||
| 168 | #define IDX_MIXER_SOMETHING30H 0x30 /* used, but unknown??? */ | 182 | #define IDX_MIXER_SOMETHING30H 0x30 /* used, but unknown??? */ |
| 169 | 183 | ||
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 9ee07d4aac1e..c33642d8d9a1 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c | |||
| @@ -44,7 +44,7 @@ MODULE_SUPPORTED_DEVICE("{{Brooktree,Bt878}," | |||
| 44 | static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */ | 44 | static int index[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -2}; /* Exclude the first card */ |
| 45 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 45 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
| 46 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ | 46 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ |
| 47 | static int digital_rate[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* digital input rate */ | 47 | static int digital_rate[SNDRV_CARDS]; /* digital input rate */ |
| 48 | static int load_all; /* allow to load the non-whitelisted cards */ | 48 | static int load_all; /* allow to load the non-whitelisted cards */ |
| 49 | 49 | ||
| 50 | module_param_array(index, int, NULL, 0444); | 50 | module_param_array(index, int, NULL, 0444); |
| @@ -781,10 +781,12 @@ static struct pci_device_id snd_bt87x_ids[] __devinitdata = { | |||
| 781 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, 32000), | 781 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, 32000), |
| 782 | /* Viewcast Osprey 200 */ | 782 | /* Viewcast Osprey 200 */ |
| 783 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100), | 783 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100), |
| 784 | /* AVerMedia Studio No. 103, 203, ...? */ | ||
| 785 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000), | ||
| 786 | /* Leadtek Winfast tv 2000xp delux */ | 784 | /* Leadtek Winfast tv 2000xp delux */ |
| 787 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, 32000), | 785 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, 32000), |
| 786 | /* Voodoo TV 200 */ | ||
| 787 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, 32000), | ||
| 788 | /* AVerMedia Studio No. 103, 203, ...? */ | ||
| 789 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, 48000), | ||
| 788 | { } | 790 | { } |
| 789 | }; | 791 | }; |
| 790 | MODULE_DEVICE_TABLE(pci, snd_bt87x_ids); | 792 | MODULE_DEVICE_TABLE(pci, snd_bt87x_ids); |
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index c8131ea92ed6..9cb66c59f523 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h | |||
| @@ -537,9 +537,9 @@ | |||
| 537 | #endif | 537 | #endif |
| 538 | 538 | ||
| 539 | #define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux | 539 | #define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux |
| 540 | #define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used) | ||
| 540 | #define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux | 541 | #define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux |
| 541 | #define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux | 542 | #define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux |
| 542 | #define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used) | ||
| 543 | #define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux | 543 | #define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux |
| 544 | 544 | ||
| 545 | #define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ | 545 | #define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ |
| @@ -604,6 +604,8 @@ struct snd_ca0106 { | |||
| 604 | u32 spdif_bits[4]; /* s/pdif out setup */ | 604 | u32 spdif_bits[4]; /* s/pdif out setup */ |
| 605 | int spdif_enable; | 605 | int spdif_enable; |
| 606 | int capture_source; | 606 | int capture_source; |
| 607 | int i2c_capture_source; | ||
| 608 | u8 i2c_capture_volume[4][2]; | ||
| 607 | int capture_mic_line_in; | 609 | int capture_mic_line_in; |
| 608 | 610 | ||
| 609 | struct snd_dma_buffer buffer; | 611 | struct snd_dma_buffer buffer; |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index fd8bfebfbd54..59bf9bd02534 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
| @@ -186,8 +186,8 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
| 186 | /* New Audigy SE. Has a different DAC. */ | 186 | /* New Audigy SE. Has a different DAC. */ |
| 187 | /* SB0570: | 187 | /* SB0570: |
| 188 | * CTRL:CA0106-DAT | 188 | * CTRL:CA0106-DAT |
| 189 | * ADC: WM8768GEDS | 189 | * ADC: WM8775EDS |
| 190 | * DAC: WM8775EDS | 190 | * DAC: WM8768GEDS |
| 191 | */ | 191 | */ |
| 192 | { .serial = 0x100a1102, | 192 | { .serial = 0x100a1102, |
| 193 | .name = "Audigy SE [SB0570]", | 193 | .name = "Audigy SE [SB0570]", |
| @@ -195,9 +195,14 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
| 195 | .i2c_adc = 1, | 195 | .i2c_adc = 1, |
| 196 | .spi_dac = 1 } , | 196 | .spi_dac = 1 } , |
| 197 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ | 197 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ |
| 198 | /* SB0438 | ||
| 199 | * CTRL:CA0106-DAT | ||
| 200 | * ADC: WM8775SEDS | ||
| 201 | * DAC: CS4382-KQZ | ||
| 202 | */ | ||
| 198 | { .serial = 0x10091462, | 203 | { .serial = 0x10091462, |
| 199 | .name = "MSI K8N Diamond MB [SB0438]", | 204 | .name = "MSI K8N Diamond MB [SB0438]", |
| 200 | .gpio_type = 1, | 205 | .gpio_type = 2, |
| 201 | .i2c_adc = 1 } , | 206 | .i2c_adc = 1 } , |
| 202 | /* Shuttle XPC SD31P which has an onboard Creative Labs | 207 | /* Shuttle XPC SD31P which has an onboard Creative Labs |
| 203 | * Sound Blaster Live! 24-bit EAX | 208 | * Sound Blaster Live! 24-bit EAX |
| @@ -326,6 +331,7 @@ int snd_ca0106_spi_write(struct snd_ca0106 * emu, | |||
| 326 | return 0; | 331 | return 0; |
| 327 | } | 332 | } |
| 328 | 333 | ||
| 334 | /* The ADC does not support i2c read, so only write is implemented */ | ||
| 329 | int snd_ca0106_i2c_write(struct snd_ca0106 *emu, | 335 | int snd_ca0106_i2c_write(struct snd_ca0106 *emu, |
| 330 | u32 reg, | 336 | u32 reg, |
| 331 | u32 value) | 337 | u32 value) |
| @@ -340,6 +346,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, | |||
| 340 | } | 346 | } |
| 341 | 347 | ||
| 342 | tmp = reg << 25 | value << 16; | 348 | tmp = reg << 25 | value << 16; |
| 349 | // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); | ||
| 343 | /* Not sure what this I2C channel controls. */ | 350 | /* Not sure what this I2C channel controls. */ |
| 344 | /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */ | 351 | /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */ |
| 345 | 352 | ||
| @@ -348,8 +355,9 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, | |||
| 348 | 355 | ||
| 349 | for (retry = 0; retry < 10; retry++) { | 356 | for (retry = 0; retry < 10; retry++) { |
| 350 | /* Send the data to i2c */ | 357 | /* Send the data to i2c */ |
| 351 | tmp = snd_ca0106_ptr_read(emu, I2C_A, 0); | 358 | //tmp = snd_ca0106_ptr_read(emu, I2C_A, 0); |
| 352 | tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); | 359 | //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); |
| 360 | tmp = 0; | ||
| 353 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); | 361 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); |
| 354 | snd_ca0106_ptr_write(emu, I2C_A, 0, tmp); | 362 | snd_ca0106_ptr_write(emu, I2C_A, 0, tmp); |
| 355 | 363 | ||
| @@ -1181,7 +1189,7 @@ static unsigned int spi_dac_init[] = { | |||
| 1181 | 0x02ff, | 1189 | 0x02ff, |
| 1182 | 0x0400, | 1190 | 0x0400, |
| 1183 | 0x0520, | 1191 | 0x0520, |
| 1184 | 0x0600, | 1192 | 0x0620, /* Set 24 bit. Was 0x0600 */ |
| 1185 | 0x08ff, | 1193 | 0x08ff, |
| 1186 | 0x0aff, | 1194 | 0x0aff, |
| 1187 | 0x0cff, | 1195 | 0x0cff, |
| @@ -1200,6 +1208,22 @@ static unsigned int spi_dac_init[] = { | |||
| 1200 | 0x1400, | 1208 | 0x1400, |
| 1201 | }; | 1209 | }; |
| 1202 | 1210 | ||
| 1211 | static unsigned int i2c_adc_init[][2] = { | ||
| 1212 | { 0x17, 0x00 }, /* Reset */ | ||
| 1213 | { 0x07, 0x00 }, /* Timeout */ | ||
| 1214 | { 0x0b, 0x22 }, /* Interface control */ | ||
| 1215 | { 0x0c, 0x22 }, /* Master mode control */ | ||
| 1216 | { 0x0d, 0x08 }, /* Powerdown control */ | ||
| 1217 | { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */ | ||
| 1218 | { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */ | ||
| 1219 | { 0x10, 0x7b }, /* ALC Control 1 */ | ||
| 1220 | { 0x11, 0x00 }, /* ALC Control 2 */ | ||
| 1221 | { 0x12, 0x32 }, /* ALC Control 3 */ | ||
| 1222 | { 0x13, 0x00 }, /* Noise gate control */ | ||
| 1223 | { 0x14, 0xa6 }, /* Limiter control */ | ||
| 1224 | { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */ | ||
| 1225 | }; | ||
| 1226 | |||
| 1203 | static int __devinit snd_ca0106_create(struct snd_card *card, | 1227 | static int __devinit snd_ca0106_create(struct snd_card *card, |
| 1204 | struct pci_dev *pci, | 1228 | struct pci_dev *pci, |
| 1205 | struct snd_ca0106 **rchip) | 1229 | struct snd_ca0106 **rchip) |
| @@ -1361,7 +1385,12 @@ static int __devinit snd_ca0106_create(struct snd_card *card, | |||
| 1361 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ | 1385 | snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ |
| 1362 | chip->capture_source = 3; /* Set CAPTURE_SOURCE */ | 1386 | chip->capture_source = 3; /* Set CAPTURE_SOURCE */ |
| 1363 | 1387 | ||
| 1364 | if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ | 1388 | if (chip->details->gpio_type == 2) { /* The SB0438 use GPIO differently. */ |
| 1389 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ | ||
| 1390 | outl(0x0, chip->port+GPIO); | ||
| 1391 | //outl(0x00f0e000, chip->port+GPIO); /* Analog */ | ||
| 1392 | outl(0x005f5301, chip->port+GPIO); /* Analog */ | ||
| 1393 | } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ | ||
| 1365 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ | 1394 | /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ |
| 1366 | outl(0x0, chip->port+GPIO); | 1395 | outl(0x0, chip->port+GPIO); |
| 1367 | //outl(0x00f0e000, chip->port+GPIO); /* Analog */ | 1396 | //outl(0x00f0e000, chip->port+GPIO); /* Analog */ |
| @@ -1379,7 +1408,19 @@ static int __devinit snd_ca0106_create(struct snd_card *card, | |||
| 1379 | outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ | 1408 | outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ |
| 1380 | 1409 | ||
| 1381 | if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ | 1410 | if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ |
| 1382 | snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ | 1411 | int size, n; |
| 1412 | |||
| 1413 | size = ARRAY_SIZE(i2c_adc_init); | ||
| 1414 | //snd_printk("I2C:array size=0x%x\n", size); | ||
| 1415 | for (n=0; n < size; n++) { | ||
| 1416 | snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); | ||
| 1417 | } | ||
| 1418 | for (n=0; n < 4; n++) { | ||
| 1419 | chip->i2c_capture_volume[n][0]= 0xcf; | ||
| 1420 | chip->i2c_capture_volume[n][1]= 0xcf; | ||
| 1421 | } | ||
| 1422 | chip->i2c_capture_source=2; /* Line in */ | ||
| 1423 | //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ | ||
| 1383 | } | 1424 | } |
| 1384 | if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ | 1425 | if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ |
| 1385 | int size, n; | 1426 | int size, n; |
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 06fe055674fb..146eed70dce6 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
| @@ -171,6 +171,76 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, | |||
| 171 | return change; | 171 | return change; |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol, | ||
| 175 | struct snd_ctl_elem_info *uinfo) | ||
| 176 | { | ||
| 177 | static char *texts[6] = { | ||
| 178 | "Phone", "Mic", "Line in", "Aux" | ||
| 179 | }; | ||
| 180 | |||
| 181 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 182 | uinfo->count = 1; | ||
| 183 | uinfo->value.enumerated.items = 4; | ||
| 184 | if (uinfo->value.enumerated.item > 3) | ||
| 185 | uinfo->value.enumerated.item = 3; | ||
| 186 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol, | ||
| 191 | struct snd_ctl_elem_value *ucontrol) | ||
| 192 | { | ||
| 193 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | ||
| 194 | |||
| 195 | ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; | ||
| 196 | return 0; | ||
| 197 | } | ||
| 198 | |||
| 199 | static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, | ||
| 200 | struct snd_ctl_elem_value *ucontrol) | ||
| 201 | { | ||
| 202 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | ||
| 203 | unsigned int source_id; | ||
| 204 | unsigned int ngain, ogain; | ||
| 205 | int change = 0; | ||
| 206 | u32 source; | ||
| 207 | /* If the capture source has changed, | ||
| 208 | * update the capture volume from the cached value | ||
| 209 | * for the particular source. | ||
| 210 | */ | ||
| 211 | source_id = ucontrol->value.enumerated.item[0] ; | ||
| 212 | change = (emu->i2c_capture_source != source_id); | ||
| 213 | if (change) { | ||
| 214 | snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | ||
| 215 | ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ | ||
| 216 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ | ||
| 217 | if (ngain != ogain) | ||
| 218 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); | ||
| 219 | ngain = emu->i2c_capture_volume[source_id][1]; /* Left */ | ||
| 220 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */ | ||
| 221 | if (ngain != ogain) | ||
| 222 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | ||
| 223 | source = 1 << source_id; | ||
| 224 | snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ | ||
| 225 | emu->i2c_capture_source = source_id; | ||
| 226 | } | ||
| 227 | return change; | ||
| 228 | } | ||
| 229 | |||
| 230 | static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol, | ||
| 231 | struct snd_ctl_elem_info *uinfo) | ||
| 232 | { | ||
| 233 | static char *texts[2] = { "Side out", "Line in" }; | ||
| 234 | |||
| 235 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 236 | uinfo->count = 1; | ||
| 237 | uinfo->value.enumerated.items = 2; | ||
| 238 | if (uinfo->value.enumerated.item > 1) | ||
| 239 | uinfo->value.enumerated.item = 1; | ||
| 240 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
| 241 | return 0; | ||
| 242 | } | ||
| 243 | |||
| 174 | static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol, | 244 | static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol, |
| 175 | struct snd_ctl_elem_info *uinfo) | 245 | struct snd_ctl_elem_info *uinfo) |
| 176 | { | 246 | { |
| @@ -207,16 +277,16 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, | |||
| 207 | if (change) { | 277 | if (change) { |
| 208 | emu->capture_mic_line_in = val; | 278 | emu->capture_mic_line_in = val; |
| 209 | if (val) { | 279 | if (val) { |
| 210 | snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */ | 280 | //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ |
| 211 | tmp = inl(emu->port+GPIO) & ~0x400; | 281 | tmp = inl(emu->port+GPIO) & ~0x400; |
| 212 | tmp = tmp | 0x400; | 282 | tmp = tmp | 0x400; |
| 213 | outl(tmp, emu->port+GPIO); | 283 | outl(tmp, emu->port+GPIO); |
| 214 | snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); | 284 | //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); |
| 215 | } else { | 285 | } else { |
| 216 | snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */ | 286 | //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ |
| 217 | tmp = inl(emu->port+GPIO) & ~0x400; | 287 | tmp = inl(emu->port+GPIO) & ~0x400; |
| 218 | outl(tmp, emu->port+GPIO); | 288 | outl(tmp, emu->port+GPIO); |
| 219 | snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); | 289 | //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); |
| 220 | } | 290 | } |
| 221 | } | 291 | } |
| 222 | return change; | 292 | return change; |
| @@ -225,12 +295,22 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, | |||
| 225 | static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata = | 295 | static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata = |
| 226 | { | 296 | { |
| 227 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 297 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 228 | .name = "Mic/Line in Capture", | 298 | .name = "Shared Mic/Line in Capture Switch", |
| 229 | .info = snd_ca0106_capture_mic_line_in_info, | 299 | .info = snd_ca0106_capture_mic_line_in_info, |
| 230 | .get = snd_ca0106_capture_mic_line_in_get, | 300 | .get = snd_ca0106_capture_mic_line_in_get, |
| 231 | .put = snd_ca0106_capture_mic_line_in_put | 301 | .put = snd_ca0106_capture_mic_line_in_put |
| 232 | }; | 302 | }; |
| 233 | 303 | ||
| 304 | static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out __devinitdata = | ||
| 305 | { | ||
| 306 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 307 | .name = "Shared Line in/Side out Capture Switch", | ||
| 308 | .info = snd_ca0106_capture_line_in_side_out_info, | ||
| 309 | .get = snd_ca0106_capture_mic_line_in_get, | ||
| 310 | .put = snd_ca0106_capture_mic_line_in_put | ||
| 311 | }; | ||
| 312 | |||
| 313 | |||
| 234 | static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol, | 314 | static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol, |
| 235 | struct snd_ctl_elem_info *uinfo) | 315 | struct snd_ctl_elem_info *uinfo) |
| 236 | { | 316 | { |
| @@ -329,15 +409,81 @@ static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol, | |||
| 329 | return 1; | 409 | return 1; |
| 330 | } | 410 | } |
| 331 | 411 | ||
| 412 | static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol, | ||
| 413 | struct snd_ctl_elem_info *uinfo) | ||
| 414 | { | ||
| 415 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 416 | uinfo->count = 2; | ||
| 417 | uinfo->value.integer.min = 0; | ||
| 418 | uinfo->value.integer.max = 255; | ||
| 419 | return 0; | ||
| 420 | } | ||
| 421 | |||
| 422 | static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol, | ||
| 423 | struct snd_ctl_elem_value *ucontrol) | ||
| 424 | { | ||
| 425 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | ||
| 426 | int source_id; | ||
| 427 | |||
| 428 | source_id = kcontrol->private_value; | ||
| 429 | |||
| 430 | ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; | ||
| 431 | ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; | ||
| 432 | return 0; | ||
| 433 | } | ||
| 434 | |||
| 435 | static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, | ||
| 436 | struct snd_ctl_elem_value *ucontrol) | ||
| 437 | { | ||
| 438 | struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); | ||
| 439 | unsigned int ogain; | ||
| 440 | unsigned int ngain; | ||
| 441 | int source_id; | ||
| 442 | int change = 0; | ||
| 443 | |||
| 444 | source_id = kcontrol->private_value; | ||
| 445 | ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ | ||
| 446 | ngain = ucontrol->value.integer.value[0]; | ||
| 447 | if (ngain > 0xff) | ||
| 448 | return 0; | ||
| 449 | if (ogain != ngain) { | ||
| 450 | if (emu->i2c_capture_source == source_id) | ||
| 451 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); | ||
| 452 | emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; | ||
| 453 | change = 1; | ||
| 454 | } | ||
| 455 | ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ | ||
| 456 | ngain = ucontrol->value.integer.value[1]; | ||
| 457 | if (ngain > 0xff) | ||
| 458 | return 0; | ||
| 459 | if (ogain != ngain) { | ||
| 460 | if (emu->i2c_capture_source == source_id) | ||
| 461 | snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | ||
| 462 | emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; | ||
| 463 | change = 1; | ||
| 464 | } | ||
| 465 | |||
| 466 | return change; | ||
| 467 | } | ||
| 468 | |||
| 332 | #define CA_VOLUME(xname,chid,reg) \ | 469 | #define CA_VOLUME(xname,chid,reg) \ |
| 333 | { \ | 470 | { \ |
| 334 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 471 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
| 335 | .info = snd_ca0106_volume_info, \ | 472 | .info = snd_ca0106_volume_info, \ |
| 336 | .get = snd_ca0106_volume_get, \ | 473 | .get = snd_ca0106_volume_get, \ |
| 337 | .put = snd_ca0106_volume_put, \ | 474 | .put = snd_ca0106_volume_put, \ |
| 338 | .private_value = ((chid) << 8) | (reg) \ | 475 | .private_value = ((chid) << 8) | (reg) \ |
| 339 | } | 476 | } |
| 340 | 477 | ||
| 478 | #define I2C_VOLUME(xname,chid) \ | ||
| 479 | { \ | ||
| 480 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
| 481 | .info = snd_ca0106_i2c_volume_info, \ | ||
| 482 | .get = snd_ca0106_i2c_volume_get, \ | ||
| 483 | .put = snd_ca0106_i2c_volume_put, \ | ||
| 484 | .private_value = chid \ | ||
| 485 | } | ||
| 486 | |||
| 341 | 487 | ||
| 342 | static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { | 488 | static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { |
| 343 | CA_VOLUME("Analog Front Playback Volume", | 489 | CA_VOLUME("Analog Front Playback Volume", |
| @@ -361,6 +507,11 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { | |||
| 361 | CA_VOLUME("CAPTURE feedback Playback Volume", | 507 | CA_VOLUME("CAPTURE feedback Playback Volume", |
| 362 | 1, CAPTURE_CONTROL), | 508 | 1, CAPTURE_CONTROL), |
| 363 | 509 | ||
| 510 | I2C_VOLUME("Phone Capture Volume", 0), | ||
| 511 | I2C_VOLUME("Mic Capture Volume", 1), | ||
| 512 | I2C_VOLUME("Line in Capture Volume", 2), | ||
| 513 | I2C_VOLUME("Aux Capture Volume", 3), | ||
| 514 | |||
| 364 | { | 515 | { |
| 365 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | 516 | .access = SNDRV_CTL_ELEM_ACCESS_READ, |
| 366 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 517 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| @@ -378,12 +529,19 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { | |||
| 378 | }, | 529 | }, |
| 379 | { | 530 | { |
| 380 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 531 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 381 | .name = "Capture Source", | 532 | .name = "Digital Capture Source", |
| 382 | .info = snd_ca0106_capture_source_info, | 533 | .info = snd_ca0106_capture_source_info, |
| 383 | .get = snd_ca0106_capture_source_get, | 534 | .get = snd_ca0106_capture_source_get, |
| 384 | .put = snd_ca0106_capture_source_put | 535 | .put = snd_ca0106_capture_source_put |
| 385 | }, | 536 | }, |
| 386 | { | 537 | { |
| 538 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 539 | .name = "Capture Source", | ||
| 540 | .info = snd_ca0106_i2c_capture_source_info, | ||
| 541 | .get = snd_ca0106_i2c_capture_source_get, | ||
| 542 | .put = snd_ca0106_i2c_capture_source_put | ||
| 543 | }, | ||
| 544 | { | ||
| 387 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 545 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
| 388 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | 546 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), |
| 389 | .count = 4, | 547 | .count = 4, |
| @@ -477,7 +635,10 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) | |||
| 477 | return err; | 635 | return err; |
| 478 | } | 636 | } |
| 479 | if (emu->details->i2c_adc == 1) { | 637 | if (emu->details->i2c_adc == 1) { |
| 480 | err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); | 638 | if (emu->details->gpio_type == 1) |
| 639 | err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); | ||
| 640 | else /* gpio_type == 2 */ | ||
| 641 | err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu)); | ||
| 481 | if (err < 0) | 642 | if (err < 0) |
| 482 | return err; | 643 | return err; |
| 483 | } | 644 | } |
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 63757273bfb7..75ca421eb3a1 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c | |||
| @@ -431,33 +431,30 @@ int __devinit snd_ca0106_proc_init(struct snd_ca0106 * emu) | |||
| 431 | struct snd_info_entry *entry; | 431 | struct snd_info_entry *entry; |
| 432 | 432 | ||
| 433 | if(! snd_card_proc_new(emu->card, "iec958", &entry)) | 433 | if(! snd_card_proc_new(emu->card, "iec958", &entry)) |
| 434 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_iec958); | 434 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_iec958); |
| 435 | if(! snd_card_proc_new(emu->card, "ca0106_reg32", &entry)) { | 435 | if(! snd_card_proc_new(emu->card, "ca0106_reg32", &entry)) { |
| 436 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read32); | 436 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read32); |
| 437 | entry->c.text.write_size = 64; | ||
| 438 | entry->c.text.write = snd_ca0106_proc_reg_write32; | 437 | entry->c.text.write = snd_ca0106_proc_reg_write32; |
| 439 | entry->mode |= S_IWUSR; | 438 | entry->mode |= S_IWUSR; |
| 440 | } | 439 | } |
| 441 | if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry)) | 440 | if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry)) |
| 442 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read16); | 441 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read16); |
| 443 | if(! snd_card_proc_new(emu->card, "ca0106_reg8", &entry)) | 442 | if(! snd_card_proc_new(emu->card, "ca0106_reg8", &entry)) |
| 444 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read8); | 443 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read8); |
| 445 | if(! snd_card_proc_new(emu->card, "ca0106_regs1", &entry)) { | 444 | if(! snd_card_proc_new(emu->card, "ca0106_regs1", &entry)) { |
| 446 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read1); | 445 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read1); |
| 447 | entry->c.text.write_size = 64; | ||
| 448 | entry->c.text.write = snd_ca0106_proc_reg_write; | 446 | entry->c.text.write = snd_ca0106_proc_reg_write; |
| 449 | entry->mode |= S_IWUSR; | 447 | entry->mode |= S_IWUSR; |
| 450 | // entry->private_data = emu; | 448 | // entry->private_data = emu; |
| 451 | } | 449 | } |
| 452 | if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { | 450 | if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { |
| 453 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_i2c_write); | 451 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_i2c_write); |
| 454 | entry->c.text.write_size = 64; | ||
| 455 | entry->c.text.write = snd_ca0106_proc_i2c_write; | 452 | entry->c.text.write = snd_ca0106_proc_i2c_write; |
| 456 | entry->mode |= S_IWUSR; | 453 | entry->mode |= S_IWUSR; |
| 457 | // entry->private_data = emu; | 454 | // entry->private_data = emu; |
| 458 | } | 455 | } |
| 459 | if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) | 456 | if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) |
| 460 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read2); | 457 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read2); |
| 461 | return 0; | 458 | return 0; |
| 462 | } | 459 | } |
| 463 | 460 | ||
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index e5ce2dabd081..0938c158b5c9 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
| @@ -2121,7 +2121,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = { | |||
| 2121 | CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7), | 2121 | CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7), |
| 2122 | CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7), | 2122 | CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7), |
| 2123 | CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0), | 2123 | CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0), |
| 2124 | CMIPCI_DOUBLE("PC Speaker Playnack Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0), | 2124 | CMIPCI_DOUBLE("PC Speaker Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0), |
| 2125 | CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0), | 2125 | CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0), |
| 2126 | }; | 2126 | }; |
| 2127 | 2127 | ||
| @@ -2602,7 +2602,7 @@ static void __devinit snd_cmipci_proc_init(struct cmipci *cm) | |||
| 2602 | struct snd_info_entry *entry; | 2602 | struct snd_info_entry *entry; |
| 2603 | 2603 | ||
| 2604 | if (! snd_card_proc_new(cm->card, "cmipci", &entry)) | 2604 | if (! snd_card_proc_new(cm->card, "cmipci", &entry)) |
| 2605 | snd_info_set_text_ops(entry, cm, 1024, snd_cmipci_proc_read); | 2605 | snd_info_set_text_ops(entry, cm, snd_cmipci_proc_read); |
| 2606 | } | 2606 | } |
| 2607 | #else /* !CONFIG_PROC_FS */ | 2607 | #else /* !CONFIG_PROC_FS */ |
| 2608 | static inline void snd_cmipci_proc_init(struct cmipci *cm) {} | 2608 | static inline void snd_cmipci_proc_init(struct cmipci *cm) {} |
| @@ -2932,7 +2932,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc | |||
| 2932 | } | 2932 | } |
| 2933 | 2933 | ||
| 2934 | integrated_midi = snd_cmipci_read_b(cm, CM_REG_MPU_PCI) != 0xff; | 2934 | integrated_midi = snd_cmipci_read_b(cm, CM_REG_MPU_PCI) != 0xff; |
| 2935 | if (integrated_midi) | 2935 | if (integrated_midi && mpu_port[dev] == 1) |
| 2936 | iomidi = cm->iobase + CM_REG_MPU_PCI; | 2936 | iomidi = cm->iobase + CM_REG_MPU_PCI; |
| 2937 | else { | 2937 | else { |
| 2938 | iomidi = mpu_port[dev]; | 2938 | iomidi = mpu_port[dev]; |
| @@ -2981,7 +2981,9 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc | |||
| 2981 | 2981 | ||
| 2982 | if (iomidi > 0) { | 2982 | if (iomidi > 0) { |
| 2983 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, | 2983 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_CMIPCI, |
| 2984 | iomidi, integrated_midi, | 2984 | iomidi, |
| 2985 | (integrated_midi ? | ||
| 2986 | MPU401_INFO_INTEGRATED : 0), | ||
| 2985 | cm->irq, 0, &cm->rmidi)) < 0) { | 2987 | cm->irq, 0, &cm->rmidi)) < 0) { |
| 2986 | printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi); | 2988 | printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi); |
| 2987 | } | 2989 | } |
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index b3c94d83450a..e77a4ce314b7 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
| @@ -1184,7 +1184,7 @@ static void __devinit snd_cs4281_proc_init(struct cs4281 * chip) | |||
| 1184 | struct snd_info_entry *entry; | 1184 | struct snd_info_entry *entry; |
| 1185 | 1185 | ||
| 1186 | if (! snd_card_proc_new(chip->card, "cs4281", &entry)) | 1186 | if (! snd_card_proc_new(chip->card, "cs4281", &entry)) |
| 1187 | snd_info_set_text_ops(entry, chip, 1024, snd_cs4281_proc_read); | 1187 | snd_info_set_text_ops(entry, chip, snd_cs4281_proc_read); |
| 1188 | if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) { | 1188 | if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) { |
| 1189 | entry->content = SNDRV_INFO_CONTENT_DATA; | 1189 | entry->content = SNDRV_INFO_CONTENT_DATA; |
| 1190 | entry->private_data = chip; | 1190 | entry->private_data = chip; |
| @@ -1379,6 +1379,13 @@ static int __devinit snd_cs4281_create(struct snd_card *card, | |||
| 1379 | chip->ba0_addr = pci_resource_start(pci, 0); | 1379 | chip->ba0_addr = pci_resource_start(pci, 0); |
| 1380 | chip->ba1_addr = pci_resource_start(pci, 1); | 1380 | chip->ba1_addr = pci_resource_start(pci, 1); |
| 1381 | 1381 | ||
| 1382 | chip->ba0 = ioremap_nocache(chip->ba0_addr, pci_resource_len(pci, 0)); | ||
| 1383 | chip->ba1 = ioremap_nocache(chip->ba1_addr, pci_resource_len(pci, 1)); | ||
| 1384 | if (!chip->ba0 || !chip->ba1) { | ||
| 1385 | snd_cs4281_free(chip); | ||
| 1386 | return -ENOMEM; | ||
| 1387 | } | ||
| 1388 | |||
| 1382 | if (request_irq(pci->irq, snd_cs4281_interrupt, SA_INTERRUPT|SA_SHIRQ, | 1389 | if (request_irq(pci->irq, snd_cs4281_interrupt, SA_INTERRUPT|SA_SHIRQ, |
| 1383 | "CS4281", chip)) { | 1390 | "CS4281", chip)) { |
| 1384 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); | 1391 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); |
| @@ -1387,13 +1394,6 @@ static int __devinit snd_cs4281_create(struct snd_card *card, | |||
| 1387 | } | 1394 | } |
| 1388 | chip->irq = pci->irq; | 1395 | chip->irq = pci->irq; |
| 1389 | 1396 | ||
| 1390 | chip->ba0 = ioremap_nocache(chip->ba0_addr, pci_resource_len(pci, 0)); | ||
| 1391 | chip->ba1 = ioremap_nocache(chip->ba1_addr, pci_resource_len(pci, 1)); | ||
| 1392 | if (!chip->ba0 || !chip->ba1) { | ||
| 1393 | snd_cs4281_free(chip); | ||
| 1394 | return -ENOMEM; | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | tmp = snd_cs4281_chip_init(chip); | 1397 | tmp = snd_cs4281_chip_init(chip); |
| 1398 | if (tmp) { | 1398 | if (tmp) { |
| 1399 | snd_cs4281_free(chip); | 1399 | snd_cs4281_free(chip); |
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 848d772ae3c6..772dc52bfeb2 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c | |||
| @@ -48,8 +48,8 @@ MODULE_SUPPORTED_DEVICE("{{Cirrus Logic,Sound Fusion (CS4280)}," | |||
| 48 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 48 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
| 49 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 49 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
| 50 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ | 50 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ |
| 51 | static int external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 51 | static int external_amp[SNDRV_CARDS]; |
| 52 | static int thinkpad[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 52 | static int thinkpad[SNDRV_CARDS]; |
| 53 | static int mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; | 53 | static int mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; |
| 54 | 54 | ||
| 55 | module_param_array(index, int, NULL, 0444); | 55 | module_param_array(index, int, NULL, 0444); |
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 69dbf542a6de..5c2114439204 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c | |||
| @@ -2877,14 +2877,15 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip) | |||
| 2877 | if (chip->region.idx[0].resource) | 2877 | if (chip->region.idx[0].resource) |
| 2878 | snd_cs46xx_hw_stop(chip); | 2878 | snd_cs46xx_hw_stop(chip); |
| 2879 | 2879 | ||
| 2880 | if (chip->irq >= 0) | ||
| 2881 | free_irq(chip->irq, chip); | ||
| 2882 | |||
| 2880 | for (idx = 0; idx < 5; idx++) { | 2883 | for (idx = 0; idx < 5; idx++) { |
| 2881 | struct snd_cs46xx_region *region = &chip->region.idx[idx]; | 2884 | struct snd_cs46xx_region *region = &chip->region.idx[idx]; |
| 2882 | if (region->remap_addr) | 2885 | if (region->remap_addr) |
| 2883 | iounmap(region->remap_addr); | 2886 | iounmap(region->remap_addr); |
| 2884 | release_and_free_resource(region->resource); | 2887 | release_and_free_resource(region->resource); |
| 2885 | } | 2888 | } |
| 2886 | if (chip->irq >= 0) | ||
| 2887 | free_irq(chip->irq, chip); | ||
| 2888 | 2889 | ||
| 2889 | if (chip->active_ctrl) | 2890 | if (chip->active_ctrl) |
| 2890 | chip->active_ctrl(chip, -chip->amplifier); | 2891 | chip->active_ctrl(chip, -chip->amplifier); |
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index f407d2a5ce3b..5c9711c0265c 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c | |||
| @@ -767,7 +767,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
| 767 | if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) { | 767 | if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) { |
| 768 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 768 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 769 | entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 769 | entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; |
| 770 | entry->c.text.read_size = 512; | ||
| 771 | 770 | ||
| 772 | if (snd_info_register(entry) < 0) { | 771 | if (snd_info_register(entry) < 0) { |
| 773 | snd_info_free_entry(entry); | 772 | snd_info_free_entry(entry); |
| @@ -784,7 +783,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
| 784 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 783 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 785 | entry->private_data = chip; | 784 | entry->private_data = chip; |
| 786 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 785 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; |
| 787 | entry->c.text.read_size = 512; | ||
| 788 | entry->c.text.read = cs46xx_dsp_proc_symbol_table_read; | 786 | entry->c.text.read = cs46xx_dsp_proc_symbol_table_read; |
| 789 | if (snd_info_register(entry) < 0) { | 787 | if (snd_info_register(entry) < 0) { |
| 790 | snd_info_free_entry(entry); | 788 | snd_info_free_entry(entry); |
| @@ -797,7 +795,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
| 797 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 795 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 798 | entry->private_data = chip; | 796 | entry->private_data = chip; |
| 799 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 797 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; |
| 800 | entry->c.text.read_size = 512; | ||
| 801 | entry->c.text.read = cs46xx_dsp_proc_modules_read; | 798 | entry->c.text.read = cs46xx_dsp_proc_modules_read; |
| 802 | if (snd_info_register(entry) < 0) { | 799 | if (snd_info_register(entry) < 0) { |
| 803 | snd_info_free_entry(entry); | 800 | snd_info_free_entry(entry); |
| @@ -810,7 +807,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
| 810 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 807 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 811 | entry->private_data = chip; | 808 | entry->private_data = chip; |
| 812 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 809 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; |
| 813 | entry->c.text.read_size = 512; | ||
| 814 | entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read; | 810 | entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read; |
| 815 | if (snd_info_register(entry) < 0) { | 811 | if (snd_info_register(entry) < 0) { |
| 816 | snd_info_free_entry(entry); | 812 | snd_info_free_entry(entry); |
| @@ -823,7 +819,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
| 823 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 819 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 824 | entry->private_data = chip; | 820 | entry->private_data = chip; |
| 825 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 821 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; |
| 826 | entry->c.text.read_size = 512; | ||
| 827 | entry->c.text.read = cs46xx_dsp_proc_sample_dump_read; | 822 | entry->c.text.read = cs46xx_dsp_proc_sample_dump_read; |
| 828 | if (snd_info_register(entry) < 0) { | 823 | if (snd_info_register(entry) < 0) { |
| 829 | snd_info_free_entry(entry); | 824 | snd_info_free_entry(entry); |
| @@ -836,7 +831,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
| 836 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 831 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 837 | entry->private_data = chip; | 832 | entry->private_data = chip; |
| 838 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 833 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; |
| 839 | entry->c.text.read_size = 512; | ||
| 840 | entry->c.text.read = cs46xx_dsp_proc_task_tree_read; | 834 | entry->c.text.read = cs46xx_dsp_proc_task_tree_read; |
| 841 | if (snd_info_register(entry) < 0) { | 835 | if (snd_info_register(entry) < 0) { |
| 842 | snd_info_free_entry(entry); | 836 | snd_info_free_entry(entry); |
| @@ -849,7 +843,6 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
| 849 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 843 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 850 | entry->private_data = chip; | 844 | entry->private_data = chip; |
| 851 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 845 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; |
| 852 | entry->c.text.read_size = 1024; | ||
| 853 | entry->c.text.read = cs46xx_dsp_proc_scb_read; | 846 | entry->c.text.read = cs46xx_dsp_proc_scb_read; |
| 854 | if (snd_info_register(entry) < 0) { | 847 | if (snd_info_register(entry) < 0) { |
| 855 | snd_info_free_entry(entry); | 848 | snd_info_free_entry(entry); |
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 2c4ee45fe10c..3844d18af19c 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c | |||
| @@ -267,7 +267,6 @@ void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip, | |||
| 267 | entry->private_data = scb_info; | 267 | entry->private_data = scb_info; |
| 268 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 268 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; |
| 269 | 269 | ||
| 270 | entry->c.text.read_size = 512; | ||
| 271 | entry->c.text.read = cs46xx_dsp_proc_scb_info_read; | 270 | entry->c.text.read = cs46xx_dsp_proc_scb_info_read; |
| 272 | 271 | ||
| 273 | if (snd_info_register(entry) < 0) { | 272 | if (snd_info_register(entry) < 0) { |
diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index 08d8ee6547d3..2911a8adc1f2 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile | |||
| @@ -4,5 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o | 5 | snd-cs5535audio-objs := cs5535audio.o cs5535audio_pcm.o |
| 6 | 6 | ||
| 7 | ifdef CONFIG_PM | ||
| 8 | snd-cs5535audio-objs += cs5535audio_pm.o | ||
| 9 | endif | ||
| 10 | |||
| 7 | # Toplevel Module Dependency | 11 | # Toplevel Module Dependency |
| 8 | obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o | 12 | obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o |
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 2c1213a35dcc..91c18a11fe87 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Driver for audio on multifunction CS5535 companion device | 2 | * Driver for audio on multifunction CS5535/6 companion device |
| 3 | * Copyright (C) Jaya Kumar | 3 | * Copyright (C) Jaya Kumar |
| 4 | * | 4 | * |
| 5 | * Based on Jaroslav Kysela and Takashi Iwai's examples. | 5 | * Based on Jaroslav Kysela and Takashi Iwai's examples. |
| @@ -40,16 +40,36 @@ | |||
| 40 | 40 | ||
| 41 | #define DRIVER_NAME "cs5535audio" | 41 | #define DRIVER_NAME "cs5535audio" |
| 42 | 42 | ||
| 43 | static char *ac97_quirk; | ||
| 44 | module_param(ac97_quirk, charp, 0444); | ||
| 45 | MODULE_PARM_DESC(ac97_quirk, "AC'97 board specific workarounds."); | ||
| 46 | |||
| 47 | static struct ac97_quirk ac97_quirks[] __devinitdata = { | ||
| 48 | #if 0 /* Not yet confirmed if all 5536 boards are HP only */ | ||
| 49 | { | ||
| 50 | .subvendor = PCI_VENDOR_ID_AMD, | ||
| 51 | .subdevice = PCI_DEVICE_ID_AMD_CS5536_AUDIO, | ||
| 52 | .name = "AMD RDK", | ||
| 53 | .type = AC97_TUNE_HP_ONLY | ||
| 54 | }, | ||
| 55 | #endif | ||
| 56 | {} | ||
| 57 | }; | ||
| 43 | 58 | ||
| 44 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 59 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
| 45 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 60 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
| 46 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 61 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
| 47 | 62 | ||
| 63 | module_param_array(index, int, NULL, 0444); | ||
| 64 | MODULE_PARM_DESC(index, "Index value for " DRIVER_NAME); | ||
| 65 | module_param_array(id, charp, NULL, 0444); | ||
| 66 | MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME); | ||
| 67 | module_param_array(enable, bool, NULL, 0444); | ||
| 68 | MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME); | ||
| 69 | |||
| 48 | static struct pci_device_id snd_cs5535audio_ids[] __devinitdata = { | 70 | static struct pci_device_id snd_cs5535audio_ids[] __devinitdata = { |
| 49 | { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO, | 71 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) }, |
| 50 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | 72 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) }, |
| 51 | { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO, | ||
| 52 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, | ||
| 53 | {} | 73 | {} |
| 54 | }; | 74 | }; |
| 55 | 75 | ||
| @@ -90,7 +110,8 @@ static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au, | |||
| 90 | udelay(1); | 110 | udelay(1); |
| 91 | } while (--timeout); | 111 | } while (--timeout); |
| 92 | if (!timeout) | 112 | if (!timeout) |
| 93 | snd_printk(KERN_ERR "Failure reading cs5535 codec\n"); | 113 | snd_printk(KERN_ERR "Failure reading codec reg 0x%x," |
| 114 | "Last value=0x%x\n", reg, val); | ||
| 94 | 115 | ||
| 95 | return (unsigned short) val; | 116 | return (unsigned short) val; |
| 96 | } | 117 | } |
| @@ -148,6 +169,8 @@ static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au) | |||
| 148 | return err; | 169 | return err; |
| 149 | } | 170 | } |
| 150 | 171 | ||
| 172 | snd_ac97_tune_hardware(cs5535au->ac97, ac97_quirks, ac97_quirk); | ||
| 173 | |||
| 151 | return 0; | 174 | return 0; |
| 152 | } | 175 | } |
| 153 | 176 | ||
| @@ -347,6 +370,8 @@ static int __devinit snd_cs5535audio_probe(struct pci_dev *pci, | |||
| 347 | if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0) | 370 | if ((err = snd_cs5535audio_create(card, pci, &cs5535au)) < 0) |
| 348 | goto probefail_out; | 371 | goto probefail_out; |
| 349 | 372 | ||
| 373 | card->private_data = cs5535au; | ||
| 374 | |||
| 350 | if ((err = snd_cs5535audio_mixer(cs5535au)) < 0) | 375 | if ((err = snd_cs5535audio_mixer(cs5535au)) < 0) |
| 351 | goto probefail_out; | 376 | goto probefail_out; |
| 352 | 377 | ||
| @@ -383,6 +408,10 @@ static struct pci_driver driver = { | |||
| 383 | .id_table = snd_cs5535audio_ids, | 408 | .id_table = snd_cs5535audio_ids, |
| 384 | .probe = snd_cs5535audio_probe, | 409 | .probe = snd_cs5535audio_probe, |
| 385 | .remove = __devexit_p(snd_cs5535audio_remove), | 410 | .remove = __devexit_p(snd_cs5535audio_remove), |
| 411 | #ifdef CONFIG_PM | ||
| 412 | .suspend = snd_cs5535audio_suspend, | ||
| 413 | .resume = snd_cs5535audio_resume, | ||
| 414 | #endif | ||
| 386 | }; | 415 | }; |
| 387 | 416 | ||
| 388 | static int __init alsa_card_cs5535audio_init(void) | 417 | static int __init alsa_card_cs5535audio_init(void) |
diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 5e55a1a1ed65..4fd1f31a6cf9 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h | |||
| @@ -74,6 +74,8 @@ | |||
| 74 | #define PRM_RDY_STS 0x00800000 | 74 | #define PRM_RDY_STS 0x00800000 |
| 75 | #define ACC_CODEC_CNTL_WR_CMD (~0x80000000) | 75 | #define ACC_CODEC_CNTL_WR_CMD (~0x80000000) |
| 76 | #define ACC_CODEC_CNTL_RD_CMD 0x80000000 | 76 | #define ACC_CODEC_CNTL_RD_CMD 0x80000000 |
| 77 | #define ACC_CODEC_CNTL_LNK_SHUTDOWN 0x00040000 | ||
| 78 | #define ACC_CODEC_CNTL_LNK_WRM_RST 0x00020000 | ||
| 77 | #define PRD_JMP 0x2000 | 79 | #define PRD_JMP 0x2000 |
| 78 | #define PRD_EOP 0x4000 | 80 | #define PRD_EOP 0x4000 |
| 79 | #define PRD_EOT 0x8000 | 81 | #define PRD_EOT 0x8000 |
| @@ -88,6 +90,7 @@ struct cs5535audio_dma_ops { | |||
| 88 | void (*disable_dma)(struct cs5535audio *cs5535au); | 90 | void (*disable_dma)(struct cs5535audio *cs5535au); |
| 89 | void (*pause_dma)(struct cs5535audio *cs5535au); | 91 | void (*pause_dma)(struct cs5535audio *cs5535au); |
| 90 | void (*setup_prd)(struct cs5535audio *cs5535au, u32 prd_addr); | 92 | void (*setup_prd)(struct cs5535audio *cs5535au, u32 prd_addr); |
| 93 | u32 (*read_prd)(struct cs5535audio *cs5535au); | ||
| 91 | u32 (*read_dma_pntr)(struct cs5535audio *cs5535au); | 94 | u32 (*read_dma_pntr)(struct cs5535audio *cs5535au); |
| 92 | }; | 95 | }; |
| 93 | 96 | ||
| @@ -103,11 +106,14 @@ struct cs5535audio_dma { | |||
| 103 | struct snd_pcm_substream *substream; | 106 | struct snd_pcm_substream *substream; |
| 104 | unsigned int buf_addr, buf_bytes; | 107 | unsigned int buf_addr, buf_bytes; |
| 105 | unsigned int period_bytes, periods; | 108 | unsigned int period_bytes, periods; |
| 109 | int suspended; | ||
| 110 | u32 saved_prd; | ||
| 106 | }; | 111 | }; |
| 107 | 112 | ||
| 108 | struct cs5535audio { | 113 | struct cs5535audio { |
| 109 | struct snd_card *card; | 114 | struct snd_card *card; |
| 110 | struct snd_ac97 *ac97; | 115 | struct snd_ac97 *ac97; |
| 116 | struct snd_pcm *pcm; | ||
| 111 | int irq; | 117 | int irq; |
| 112 | struct pci_dev *pci; | 118 | struct pci_dev *pci; |
| 113 | unsigned long port; | 119 | unsigned long port; |
| @@ -117,6 +123,8 @@ struct cs5535audio { | |||
| 117 | struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; | 123 | struct cs5535audio_dma dmas[NUM_CS5535AUDIO_DMAS]; |
| 118 | }; | 124 | }; |
| 119 | 125 | ||
| 126 | int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state); | ||
| 127 | int snd_cs5535audio_resume(struct pci_dev *pci); | ||
| 120 | int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); | 128 | int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); |
| 121 | 129 | ||
| 122 | #endif /* __SOUND_CS5535AUDIO_H */ | 130 | #endif /* __SOUND_CS5535AUDIO_H */ |
diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 60bb82b2ff47..f0a48693d687 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c | |||
| @@ -43,7 +43,8 @@ static struct snd_pcm_hardware snd_cs5535audio_playback = | |||
| 43 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 43 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
| 44 | SNDRV_PCM_INFO_MMAP_VALID | | 44 | SNDRV_PCM_INFO_MMAP_VALID | |
| 45 | SNDRV_PCM_INFO_PAUSE | | 45 | SNDRV_PCM_INFO_PAUSE | |
| 46 | SNDRV_PCM_INFO_SYNC_START | 46 | SNDRV_PCM_INFO_SYNC_START | |
| 47 | SNDRV_PCM_INFO_RESUME | ||
| 47 | ), | 48 | ), |
| 48 | .formats = ( | 49 | .formats = ( |
| 49 | SNDRV_PCM_FMTBIT_S16_LE | 50 | SNDRV_PCM_FMTBIT_S16_LE |
| @@ -193,6 +194,11 @@ static void cs5535audio_playback_setup_prd(struct cs5535audio *cs5535au, | |||
| 193 | cs_writel(cs5535au, ACC_BM0_PRD, prd_addr); | 194 | cs_writel(cs5535au, ACC_BM0_PRD, prd_addr); |
| 194 | } | 195 | } |
| 195 | 196 | ||
| 197 | static u32 cs5535audio_playback_read_prd(struct cs5535audio *cs5535au) | ||
| 198 | { | ||
| 199 | return cs_readl(cs5535au, ACC_BM0_PRD); | ||
| 200 | } | ||
| 201 | |||
| 196 | static u32 cs5535audio_playback_read_dma_pntr(struct cs5535audio *cs5535au) | 202 | static u32 cs5535audio_playback_read_dma_pntr(struct cs5535audio *cs5535au) |
| 197 | { | 203 | { |
| 198 | return cs_readl(cs5535au, ACC_BM0_PNTR); | 204 | return cs_readl(cs5535au, ACC_BM0_PNTR); |
| @@ -219,6 +225,11 @@ static void cs5535audio_capture_setup_prd(struct cs5535audio *cs5535au, | |||
| 219 | cs_writel(cs5535au, ACC_BM1_PRD, prd_addr); | 225 | cs_writel(cs5535au, ACC_BM1_PRD, prd_addr); |
| 220 | } | 226 | } |
| 221 | 227 | ||
| 228 | static u32 cs5535audio_capture_read_prd(struct cs5535audio *cs5535au) | ||
| 229 | { | ||
| 230 | return cs_readl(cs5535au, ACC_BM1_PRD); | ||
| 231 | } | ||
| 232 | |||
| 222 | static u32 cs5535audio_capture_read_dma_pntr(struct cs5535audio *cs5535au) | 233 | static u32 cs5535audio_capture_read_dma_pntr(struct cs5535audio *cs5535au) |
| 223 | { | 234 | { |
| 224 | return cs_readl(cs5535au, ACC_BM1_PNTR); | 235 | return cs_readl(cs5535au, ACC_BM1_PNTR); |
| @@ -285,9 +296,17 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 285 | case SNDRV_PCM_TRIGGER_START: | 296 | case SNDRV_PCM_TRIGGER_START: |
| 286 | dma->ops->enable_dma(cs5535au); | 297 | dma->ops->enable_dma(cs5535au); |
| 287 | break; | 298 | break; |
| 299 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 300 | dma->ops->enable_dma(cs5535au); | ||
| 301 | dma->suspended = 0; | ||
| 302 | break; | ||
| 288 | case SNDRV_PCM_TRIGGER_STOP: | 303 | case SNDRV_PCM_TRIGGER_STOP: |
| 289 | dma->ops->disable_dma(cs5535au); | 304 | dma->ops->disable_dma(cs5535au); |
| 290 | break; | 305 | break; |
| 306 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 307 | dma->ops->disable_dma(cs5535au); | ||
| 308 | dma->suspended = 1; | ||
| 309 | break; | ||
| 291 | default: | 310 | default: |
| 292 | snd_printk(KERN_ERR "unhandled trigger\n"); | 311 | snd_printk(KERN_ERR "unhandled trigger\n"); |
| 293 | err = -EINVAL; | 312 | err = -EINVAL; |
| @@ -375,6 +394,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = { | |||
| 375 | .enable_dma = cs5535audio_playback_enable_dma, | 394 | .enable_dma = cs5535audio_playback_enable_dma, |
| 376 | .disable_dma = cs5535audio_playback_disable_dma, | 395 | .disable_dma = cs5535audio_playback_disable_dma, |
| 377 | .setup_prd = cs5535audio_playback_setup_prd, | 396 | .setup_prd = cs5535audio_playback_setup_prd, |
| 397 | .read_prd = cs5535audio_playback_read_prd, | ||
| 378 | .pause_dma = cs5535audio_playback_pause_dma, | 398 | .pause_dma = cs5535audio_playback_pause_dma, |
| 379 | .read_dma_pntr = cs5535audio_playback_read_dma_pntr, | 399 | .read_dma_pntr = cs5535audio_playback_read_dma_pntr, |
| 380 | }; | 400 | }; |
| @@ -384,6 +404,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = { | |||
| 384 | .enable_dma = cs5535audio_capture_enable_dma, | 404 | .enable_dma = cs5535audio_capture_enable_dma, |
| 385 | .disable_dma = cs5535audio_capture_disable_dma, | 405 | .disable_dma = cs5535audio_capture_disable_dma, |
| 386 | .setup_prd = cs5535audio_capture_setup_prd, | 406 | .setup_prd = cs5535audio_capture_setup_prd, |
| 407 | .read_prd = cs5535audio_capture_read_prd, | ||
| 387 | .pause_dma = cs5535audio_capture_pause_dma, | 408 | .pause_dma = cs5535audio_capture_pause_dma, |
| 388 | .read_dma_pntr = cs5535audio_capture_read_dma_pntr, | 409 | .read_dma_pntr = cs5535audio_capture_read_dma_pntr, |
| 389 | }; | 410 | }; |
| @@ -413,6 +434,7 @@ int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535au) | |||
| 413 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 434 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
| 414 | snd_dma_pci_data(cs5535au->pci), | 435 | snd_dma_pci_data(cs5535au->pci), |
| 415 | 64*1024, 128*1024); | 436 | 64*1024, 128*1024); |
| 437 | cs5535au->pcm = pcm; | ||
| 416 | 438 | ||
| 417 | return 0; | 439 | return 0; |
| 418 | } | 440 | } |
diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c new file mode 100644 index 000000000000..aad0e69db9c1 --- /dev/null +++ b/sound/pci/cs5535audio/cs5535audio_pm.c | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | /* | ||
| 2 | * Power management for audio on multifunction CS5535 companion device | ||
| 3 | * Copyright (C) Jaya Kumar | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/pci.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <sound/driver.h> | ||
| 26 | #include <sound/core.h> | ||
| 27 | #include <sound/control.h> | ||
| 28 | #include <sound/initval.h> | ||
| 29 | #include <sound/asoundef.h> | ||
| 30 | #include <sound/pcm.h> | ||
| 31 | #include <sound/ac97_codec.h> | ||
| 32 | #include "cs5535audio.h" | ||
| 33 | |||
| 34 | static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au) | ||
| 35 | { | ||
| 36 | /* | ||
| 37 | we depend on snd_ac97_suspend to tell the | ||
| 38 | AC97 codec to shutdown. the amd spec suggests | ||
| 39 | that the LNK_SHUTDOWN be done at the same time | ||
| 40 | that the codec power-down is issued. instead, | ||
| 41 | we do it just after rather than at the same | ||
| 42 | time. excluding codec specific build_ops->suspend | ||
| 43 | ac97 powerdown hits: | ||
| 44 | 0x8000 EAPD | ||
| 45 | 0x4000 Headphone amplifier | ||
| 46 | 0x0300 ADC & DAC | ||
| 47 | 0x0400 Analog Mixer powerdown (Vref on) | ||
| 48 | I am not sure if this is the best that we can do. | ||
| 49 | The remainder to be investigated are: | ||
| 50 | - analog mixer (vref off) 0x0800 | ||
| 51 | - AC-link powerdown 0x1000 | ||
| 52 | - codec internal clock 0x2000 | ||
| 53 | */ | ||
| 54 | |||
| 55 | /* set LNK_SHUTDOWN to shutdown AC link */ | ||
| 56 | cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_SHUTDOWN); | ||
| 57 | |||
| 58 | } | ||
| 59 | |||
| 60 | int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state) | ||
| 61 | { | ||
| 62 | struct snd_card *card = pci_get_drvdata(pci); | ||
| 63 | struct cs5535audio *cs5535au = card->private_data; | ||
| 64 | int i; | ||
| 65 | |||
| 66 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
| 67 | for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { | ||
| 68 | struct cs5535audio_dma *dma = &cs5535au->dmas[i]; | ||
| 69 | if (dma && dma->substream && !dma->suspended) | ||
| 70 | dma->saved_prd = dma->ops->read_prd(cs5535au); | ||
| 71 | } | ||
| 72 | snd_pcm_suspend_all(cs5535au->pcm); | ||
| 73 | snd_ac97_suspend(cs5535au->ac97); | ||
| 74 | /* save important regs, then disable aclink in hw */ | ||
| 75 | snd_cs5535audio_stop_hardware(cs5535au); | ||
| 76 | pci_disable_device(pci); | ||
| 77 | pci_save_state(pci); | ||
| 78 | |||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | int snd_cs5535audio_resume(struct pci_dev *pci) | ||
| 83 | { | ||
| 84 | struct snd_card *card = pci_get_drvdata(pci); | ||
| 85 | struct cs5535audio *cs5535au = card->private_data; | ||
| 86 | u32 tmp; | ||
| 87 | int timeout; | ||
| 88 | int i; | ||
| 89 | |||
| 90 | pci_restore_state(pci); | ||
| 91 | pci_enable_device(pci); | ||
| 92 | pci_set_master(pci); | ||
| 93 | |||
| 94 | /* set LNK_WRM_RST to reset AC link */ | ||
| 95 | cs_writel(cs5535au, ACC_CODEC_CNTL, ACC_CODEC_CNTL_LNK_WRM_RST); | ||
| 96 | |||
| 97 | timeout = 50; | ||
| 98 | do { | ||
| 99 | tmp = cs_readl(cs5535au, ACC_CODEC_STATUS); | ||
| 100 | if (tmp & PRM_RDY_STS) | ||
| 101 | break; | ||
| 102 | udelay(1); | ||
| 103 | } while (--timeout); | ||
| 104 | |||
| 105 | if (!timeout) | ||
| 106 | snd_printk(KERN_ERR "Failure getting AC Link ready\n"); | ||
| 107 | |||
| 108 | /* we depend on ac97 to perform the codec power up */ | ||
| 109 | snd_ac97_resume(cs5535au->ac97); | ||
| 110 | /* set up rate regs, dma. actual initiation is done in trig */ | ||
| 111 | for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { | ||
| 112 | struct cs5535audio_dma *dma = &cs5535au->dmas[i]; | ||
| 113 | if (dma && dma->substream && dma->suspended) { | ||
| 114 | dma->substream->ops->prepare(dma->substream); | ||
| 115 | dma->ops->setup_prd(cs5535au, dma->saved_prd); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
| 120 | |||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 42b11ba1d210..549673ea14a9 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
| @@ -46,13 +46,13 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS}," | |||
| 46 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 46 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
| 47 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 47 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
| 48 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ | 48 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ |
| 49 | static int extin[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 49 | static int extin[SNDRV_CARDS]; |
| 50 | static int extout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 50 | static int extout[SNDRV_CARDS]; |
| 51 | static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4}; | 51 | static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4}; |
| 52 | static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64}; | 52 | static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64}; |
| 53 | static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128}; | 53 | static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128}; |
| 54 | static int enable_ir[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 54 | static int enable_ir[SNDRV_CARDS]; |
| 55 | static uint subsystem[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; /* Force card subsystem model */ | 55 | static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */ |
| 56 | 56 | ||
| 57 | module_param_array(index, int, NULL, 0444); | 57 | module_param_array(index, int, NULL, 0444); |
| 58 | MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); | 58 | MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 6bfa08436efa..42a358f989c3 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
| @@ -777,14 +777,6 @@ static int snd_emu10k1_dev_free(struct snd_device *device) | |||
| 777 | 777 | ||
| 778 | static struct snd_emu_chip_details emu_chip_details[] = { | 778 | static struct snd_emu_chip_details emu_chip_details[] = { |
| 779 | /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ | 779 | /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ |
| 780 | /* Audigy4 SB0400 */ | ||
| 781 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102, | ||
| 782 | .driver = "Audigy2", .name = "Audigy 4 [SB0400]", | ||
| 783 | .id = "Audigy2", | ||
| 784 | .emu10k2_chip = 1, | ||
| 785 | .ca0108_chip = 1, | ||
| 786 | .spk71 = 1, | ||
| 787 | .ac97_chip = 1} , | ||
| 788 | /* Tested by James@superbug.co.uk 3rd July 2005 */ | 780 | /* Tested by James@superbug.co.uk 3rd July 2005 */ |
| 789 | /* DSP: CA0108-IAT | 781 | /* DSP: CA0108-IAT |
| 790 | * DAC: CS4382-KQ | 782 | * DAC: CS4382-KQ |
| @@ -799,13 +791,59 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
| 799 | .ca0108_chip = 1, | 791 | .ca0108_chip = 1, |
| 800 | .spk71 = 1, | 792 | .spk71 = 1, |
| 801 | .ac97_chip = 1} , | 793 | .ac97_chip = 1} , |
| 794 | /* Audigy4 (Not PRO) SB0610 */ | ||
| 795 | /* Tested by James@superbug.co.uk 4th April 2006 */ | ||
| 796 | /* A_IOCFG bits | ||
| 797 | * Output | ||
| 798 | * 0: ? | ||
| 799 | * 1: ? | ||
| 800 | * 2: ? | ||
| 801 | * 3: 0 - Digital Out, 1 - Line in | ||
| 802 | * 4: ? | ||
| 803 | * 5: ? | ||
| 804 | * 6: ? | ||
| 805 | * 7: ? | ||
| 806 | * Input | ||
| 807 | * 8: ? | ||
| 808 | * 9: ? | ||
| 809 | * A: Green jack sense (Front) | ||
| 810 | * B: ? | ||
| 811 | * C: Black jack sense (Rear/Side Right) | ||
| 812 | * D: Yellow jack sense (Center/LFE/Side Left) | ||
| 813 | * E: ? | ||
| 814 | * F: ? | ||
| 815 | * | ||
| 816 | * Digital Out/Line in switch using A_IOCFG bit 3 (0x08) | ||
| 817 | * 0 - Digital Out | ||
| 818 | * 1 - Line in | ||
| 819 | */ | ||
| 820 | /* Mic input not tested. | ||
| 821 | * Analog CD input not tested | ||
| 822 | * Digital Out not tested. | ||
| 823 | * Line in working. | ||
| 824 | * Audio output 5.1 working. Side outputs not working. | ||
| 825 | */ | ||
| 826 | /* DSP: CA10300-IAT LF | ||
| 827 | * DAC: Cirrus Logic CS4382-KQZ | ||
| 828 | * ADC: Philips 1361T | ||
| 829 | * AC97: Sigmatel STAC9750 | ||
| 830 | * CA0151: None | ||
| 831 | */ | ||
| 832 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102, | ||
| 833 | .driver = "Audigy2", .name = "Audigy 4 [SB0610]", | ||
| 834 | .id = "Audigy2", | ||
| 835 | .emu10k2_chip = 1, | ||
| 836 | .ca0108_chip = 1, | ||
| 837 | .spk71 = 1, | ||
| 838 | .adc_1361t = 1, /* 24 bit capture instead of 16bit */ | ||
| 839 | .ac97_chip = 1} , | ||
| 802 | /* Audigy 2 ZS Notebook Cardbus card.*/ | 840 | /* Audigy 2 ZS Notebook Cardbus card.*/ |
| 803 | /* Tested by James@superbug.co.uk 22th December 2005 */ | 841 | /* Tested by James@superbug.co.uk 22th December 2005 */ |
| 804 | /* Audio output 7.1/Headphones working. | 842 | /* Audio output 7.1/Headphones working. |
| 805 | * Digital output working. (AC3 not checked, only PCM) | 843 | * Digital output working. (AC3 not checked, only PCM) |
| 806 | * Audio inputs not tested. | 844 | * Audio inputs not tested. |
| 807 | */ | 845 | */ |
| 808 | /* DSP: Tiny2 | 846 | /* DSP: Tina2 |
| 809 | * DAC: Wolfson WM8768/WM8568 | 847 | * DAC: Wolfson WM8768/WM8568 |
| 810 | * ADC: Wolfson WM8775 | 848 | * ADC: Wolfson WM8775 |
| 811 | * AC97: None | 849 | * AC97: None |
| @@ -1421,16 +1459,3 @@ void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu) | |||
| 1421 | } | 1459 | } |
| 1422 | } | 1460 | } |
| 1423 | #endif | 1461 | #endif |
| 1424 | |||
| 1425 | /* memory.c */ | ||
| 1426 | EXPORT_SYMBOL(snd_emu10k1_synth_alloc); | ||
| 1427 | EXPORT_SYMBOL(snd_emu10k1_synth_free); | ||
| 1428 | EXPORT_SYMBOL(snd_emu10k1_synth_bzero); | ||
| 1429 | EXPORT_SYMBOL(snd_emu10k1_synth_copy_from_user); | ||
| 1430 | EXPORT_SYMBOL(snd_emu10k1_memblk_map); | ||
| 1431 | /* voice.c */ | ||
| 1432 | EXPORT_SYMBOL(snd_emu10k1_voice_alloc); | ||
| 1433 | EXPORT_SYMBOL(snd_emu10k1_voice_free); | ||
| 1434 | /* io.c */ | ||
| 1435 | EXPORT_SYMBOL(snd_emu10k1_ptr_read); | ||
| 1436 | EXPORT_SYMBOL(snd_emu10k1_ptr_write); | ||
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index d51290c18167..0fb27e4be07b 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
| @@ -1055,8 +1055,7 @@ static int __devinit snd_emu10k1x_proc_init(struct emu10k1x * emu) | |||
| 1055 | struct snd_info_entry *entry; | 1055 | struct snd_info_entry *entry; |
| 1056 | 1056 | ||
| 1057 | if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry)) { | 1057 | if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry)) { |
| 1058 | snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read); | 1058 | snd_info_set_text_ops(entry, emu, snd_emu10k1x_proc_reg_read); |
| 1059 | entry->c.text.write_size = 64; | ||
| 1060 | entry->c.text.write = snd_emu10k1x_proc_reg_write; | 1059 | entry->c.text.write = snd_emu10k1x_proc_reg_write; |
| 1061 | entry->mode |= S_IWUSR; | 1060 | entry->mode |= S_IWUSR; |
| 1062 | entry->private_data = emu; | 1061 | entry->private_data = emu; |
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 2a9d12d10680..c31f3d0877fa 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c | |||
| @@ -777,6 +777,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
| 777 | }; | 777 | }; |
| 778 | static char *audigy_remove_ctls[] = { | 778 | static char *audigy_remove_ctls[] = { |
| 779 | /* Master/PCM controls on ac97 of Audigy has no effect */ | 779 | /* Master/PCM controls on ac97 of Audigy has no effect */ |
| 780 | /* On the Audigy2 the AC97 playback is piped into | ||
| 781 | * the Philips ADC for 24bit capture */ | ||
| 780 | "PCM Playback Switch", | 782 | "PCM Playback Switch", |
| 781 | "PCM Playback Volume", | 783 | "PCM Playback Volume", |
| 782 | "Master Mono Playback Switch", | 784 | "Master Mono Playback Switch", |
| @@ -804,6 +806,47 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
| 804 | "AMic Playback Volume", "Mic Playback Volume", | 806 | "AMic Playback Volume", "Mic Playback Volume", |
| 805 | NULL | 807 | NULL |
| 806 | }; | 808 | }; |
| 809 | static char *audigy_remove_ctls_1361t_adc[] = { | ||
| 810 | /* On the Audigy2 the AC97 playback is piped into | ||
| 811 | * the Philips ADC for 24bit capture */ | ||
| 812 | "PCM Playback Switch", | ||
| 813 | "PCM Playback Volume", | ||
| 814 | "Master Mono Playback Switch", | ||
| 815 | "Master Mono Playback Volume", | ||
| 816 | "Capture Source", | ||
| 817 | "Capture Switch", | ||
| 818 | "Capture Volume", | ||
| 819 | "Mic Capture Volume", | ||
| 820 | "Headphone Playback Switch", | ||
| 821 | "Headphone Playback Volume", | ||
| 822 | "3D Control - Center", | ||
| 823 | "3D Control - Depth", | ||
| 824 | "3D Control - Switch", | ||
| 825 | "Line2 Playback Volume", | ||
| 826 | "Line2 Capture Volume", | ||
| 827 | NULL | ||
| 828 | }; | ||
| 829 | static char *audigy_rename_ctls_1361t_adc[] = { | ||
| 830 | "Master Playback Switch", "Master Capture Switch", | ||
| 831 | "Master Playback Volume", "Master Capture Volume", | ||
| 832 | "Wave Master Playback Volume", "Master Playback Volume", | ||
| 833 | "PC Speaker Playback Switch", "PC Speaker Capture Switch", | ||
| 834 | "PC Speaker Playback Volume", "PC Speaker Capture Volume", | ||
| 835 | "Phone Playback Switch", "Phone Capture Switch", | ||
| 836 | "Phone Playback Volume", "Phone Capture Volume", | ||
| 837 | "Mic Playback Switch", "Mic Capture Switch", | ||
| 838 | "Mic Playback Volume", "Mic Capture Volume", | ||
| 839 | "Line Playback Switch", "Line Capture Switch", | ||
| 840 | "Line Playback Volume", "Line Capture Volume", | ||
| 841 | "CD Playback Switch", "CD Capture Switch", | ||
| 842 | "CD Playback Volume", "CD Capture Volume", | ||
| 843 | "Aux Playback Switch", "Aux Capture Switch", | ||
| 844 | "Aux Playback Volume", "Aux Capture Volume", | ||
| 845 | "Video Playback Switch", "Video Capture Switch", | ||
| 846 | "Video Playback Volume", "Video Capture Volume", | ||
| 847 | |||
| 848 | NULL | ||
| 849 | }; | ||
| 807 | 850 | ||
| 808 | if (emu->card_capabilities->ac97_chip) { | 851 | if (emu->card_capabilities->ac97_chip) { |
| 809 | struct snd_ac97_bus *pbus; | 852 | struct snd_ac97_bus *pbus; |
| @@ -834,7 +877,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
| 834 | snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); | 877 | snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); |
| 835 | /* set capture source to mic */ | 878 | /* set capture source to mic */ |
| 836 | snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); | 879 | snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); |
| 837 | c = audigy_remove_ctls; | 880 | if (emu->card_capabilities->adc_1361t) |
| 881 | c = audigy_remove_ctls_1361t_adc; | ||
| 882 | else | ||
| 883 | c = audigy_remove_ctls; | ||
| 838 | } else { | 884 | } else { |
| 839 | /* | 885 | /* |
| 840 | * Credits for cards based on STAC9758: | 886 | * Credits for cards based on STAC9758: |
| @@ -863,11 +909,15 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
| 863 | } | 909 | } |
| 864 | 910 | ||
| 865 | if (emu->audigy) | 911 | if (emu->audigy) |
| 866 | c = audigy_rename_ctls; | 912 | if (emu->card_capabilities->adc_1361t) |
| 913 | c = audigy_rename_ctls_1361t_adc; | ||
| 914 | else | ||
| 915 | c = audigy_rename_ctls; | ||
| 867 | else | 916 | else |
| 868 | c = emu10k1_rename_ctls; | 917 | c = emu10k1_rename_ctls; |
| 869 | for (; *c; c += 2) | 918 | for (; *c; c += 2) |
| 870 | rename_ctl(card, c[0], c[1]); | 919 | rename_ctl(card, c[0], c[1]); |
| 920 | |||
| 871 | if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ | 921 | if (emu->card_capabilities->subsystem == 0x20071102) { /* Audigy 4 Pro */ |
| 872 | rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); | 922 | rename_ctl(card, "Line2 Capture Volume", "Line1/Mic Capture Volume"); |
| 873 | rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); | 923 | rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); |
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 90f1c52703a1..b939e03aaedf 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c | |||
| @@ -532,57 +532,51 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) | |||
| 532 | struct snd_info_entry *entry; | 532 | struct snd_info_entry *entry; |
| 533 | #ifdef CONFIG_SND_DEBUG | 533 | #ifdef CONFIG_SND_DEBUG |
| 534 | if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { | 534 | if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { |
| 535 | snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read); | 535 | snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); |
| 536 | entry->c.text.write_size = 64; | ||
| 537 | entry->c.text.write = snd_emu_proc_io_reg_write; | 536 | entry->c.text.write = snd_emu_proc_io_reg_write; |
| 538 | entry->mode |= S_IWUSR; | 537 | entry->mode |= S_IWUSR; |
| 539 | } | 538 | } |
| 540 | if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { | 539 | if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { |
| 541 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a); | 540 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00a); |
| 542 | entry->c.text.write_size = 64; | ||
| 543 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; | 541 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; |
| 544 | entry->mode |= S_IWUSR; | 542 | entry->mode |= S_IWUSR; |
| 545 | } | 543 | } |
| 546 | if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { | 544 | if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { |
| 547 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b); | 545 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00b); |
| 548 | entry->c.text.write_size = 64; | ||
| 549 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; | 546 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; |
| 550 | entry->mode |= S_IWUSR; | 547 | entry->mode |= S_IWUSR; |
| 551 | } | 548 | } |
| 552 | if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { | 549 | if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { |
| 553 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a); | 550 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20a); |
| 554 | entry->c.text.write_size = 64; | ||
| 555 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; | 551 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; |
| 556 | entry->mode |= S_IWUSR; | 552 | entry->mode |= S_IWUSR; |
| 557 | } | 553 | } |
| 558 | if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { | 554 | if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { |
| 559 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b); | 555 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20b); |
| 560 | entry->c.text.write_size = 64; | ||
| 561 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; | 556 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; |
| 562 | entry->mode |= S_IWUSR; | 557 | entry->mode |= S_IWUSR; |
| 563 | } | 558 | } |
| 564 | if (! snd_card_proc_new(emu->card, "ptr_regs20c", &entry)) { | 559 | if (! snd_card_proc_new(emu->card, "ptr_regs20c", &entry)) { |
| 565 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20c); | 560 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20c); |
| 566 | entry->c.text.write_size = 64; | ||
| 567 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; | 561 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; |
| 568 | entry->mode |= S_IWUSR; | 562 | entry->mode |= S_IWUSR; |
| 569 | } | 563 | } |
| 570 | #endif | 564 | #endif |
| 571 | 565 | ||
| 572 | if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) | 566 | if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) |
| 573 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read); | 567 | snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_read); |
| 574 | 568 | ||
| 575 | if (emu->card_capabilities->emu10k2_chip) { | 569 | if (emu->card_capabilities->emu10k2_chip) { |
| 576 | if (! snd_card_proc_new(emu->card, "spdif-in", &entry)) | 570 | if (! snd_card_proc_new(emu->card, "spdif-in", &entry)) |
| 577 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_spdif_read); | 571 | snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_spdif_read); |
| 578 | } | 572 | } |
| 579 | if (emu->card_capabilities->ca0151_chip) { | 573 | if (emu->card_capabilities->ca0151_chip) { |
| 580 | if (! snd_card_proc_new(emu->card, "capture-rates", &entry)) | 574 | if (! snd_card_proc_new(emu->card, "capture-rates", &entry)) |
| 581 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_rates_read); | 575 | snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_rates_read); |
| 582 | } | 576 | } |
| 583 | 577 | ||
| 584 | if (! snd_card_proc_new(emu->card, "voices", &entry)) | 578 | if (! snd_card_proc_new(emu->card, "voices", &entry)) |
| 585 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read); | 579 | snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_voices_read); |
| 586 | 580 | ||
| 587 | if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) { | 581 | if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) { |
| 588 | entry->content = SNDRV_INFO_CONTENT_DATA; | 582 | entry->content = SNDRV_INFO_CONTENT_DATA; |
| @@ -616,7 +610,6 @@ int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) | |||
| 616 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 610 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 617 | entry->private_data = emu; | 611 | entry->private_data = emu; |
| 618 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | 612 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; |
| 619 | entry->c.text.read_size = 128*1024; | ||
| 620 | entry->c.text.read = snd_emu10k1_proc_acode_read; | 613 | entry->c.text.read = snd_emu10k1_proc_acode_read; |
| 621 | } | 614 | } |
| 622 | return 0; | 615 | return 0; |
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index ef5304df8c11..029e7856c43b 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c | |||
| @@ -62,6 +62,8 @@ unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, un | |||
| 62 | } | 62 | } |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | EXPORT_SYMBOL(snd_emu10k1_ptr_read); | ||
| 66 | |||
| 65 | void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data) | 67 | void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data) |
| 66 | { | 68 | { |
| 67 | unsigned int regptr; | 69 | unsigned int regptr; |
| @@ -92,6 +94,8 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i | |||
| 92 | } | 94 | } |
| 93 | } | 95 | } |
| 94 | 96 | ||
| 97 | EXPORT_SYMBOL(snd_emu10k1_ptr_write); | ||
| 98 | |||
| 95 | unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, | 99 | unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, |
| 96 | unsigned int reg, | 100 | unsigned int reg, |
| 97 | unsigned int chn) | 101 | unsigned int chn) |
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index e7ec98649f04..4fcaefe5a3c5 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c | |||
| @@ -287,6 +287,8 @@ int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *b | |||
| 287 | return err; | 287 | return err; |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | EXPORT_SYMBOL(snd_emu10k1_memblk_map); | ||
| 291 | |||
| 290 | /* | 292 | /* |
| 291 | * page allocation for DMA | 293 | * page allocation for DMA |
| 292 | */ | 294 | */ |
| @@ -387,6 +389,7 @@ snd_emu10k1_synth_alloc(struct snd_emu10k1 *hw, unsigned int size) | |||
| 387 | return (struct snd_util_memblk *)blk; | 389 | return (struct snd_util_memblk *)blk; |
| 388 | } | 390 | } |
| 389 | 391 | ||
| 392 | EXPORT_SYMBOL(snd_emu10k1_synth_alloc); | ||
| 390 | 393 | ||
| 391 | /* | 394 | /* |
| 392 | * free a synth sample area | 395 | * free a synth sample area |
| @@ -409,6 +412,7 @@ snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk) | |||
| 409 | return 0; | 412 | return 0; |
| 410 | } | 413 | } |
| 411 | 414 | ||
| 415 | EXPORT_SYMBOL(snd_emu10k1_synth_free); | ||
| 412 | 416 | ||
| 413 | /* check new allocation range */ | 417 | /* check new allocation range */ |
| 414 | static void get_single_page_range(struct snd_util_memhdr *hdr, | 418 | static void get_single_page_range(struct snd_util_memhdr *hdr, |
| @@ -540,6 +544,8 @@ int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk | |||
| 540 | return 0; | 544 | return 0; |
| 541 | } | 545 | } |
| 542 | 546 | ||
| 547 | EXPORT_SYMBOL(snd_emu10k1_synth_bzero); | ||
| 548 | |||
| 543 | /* | 549 | /* |
| 544 | * copy_from_user(blk + offset, data, size) | 550 | * copy_from_user(blk + offset, data, size) |
| 545 | */ | 551 | */ |
| @@ -568,3 +574,5 @@ int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_me | |||
| 568 | } while (offset < end_offset); | 574 | } while (offset < end_offset); |
| 569 | return 0; | 575 | return 0; |
| 570 | } | 576 | } |
| 577 | |||
| 578 | EXPORT_SYMBOL(snd_emu10k1_synth_copy_from_user); | ||
diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h new file mode 100644 index 000000000000..7ddb5be632cf --- /dev/null +++ b/sound/pci/emu10k1/p17v.h | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> | ||
| 3 | * Driver p17v chips | ||
| 4 | * Version: 0.01 | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | /******************************************************************************/ | ||
| 23 | /* Audigy2Value Tina (P17V) pointer-offset register set, | ||
| 24 | * accessed through the PTR20 and DATA24 registers */ | ||
| 25 | /******************************************************************************/ | ||
| 26 | |||
| 27 | /* 00 - 07: Not used */ | ||
| 28 | #define P17V_PLAYBACK_FIFO_PTR 0x08 /* Current playback fifo pointer | ||
| 29 | * and number of sound samples in cache. | ||
| 30 | */ | ||
| 31 | /* 09 - 12: Not used */ | ||
| 32 | #define P17V_CAPTURE_FIFO_PTR 0x13 /* Current capture fifo pointer | ||
| 33 | * and number of sound samples in cache. | ||
| 34 | */ | ||
| 35 | /* 14 - 17: Not used */ | ||
| 36 | #define P17V_PB_CHN_SEL 0x18 /* P17v playback channel select */ | ||
| 37 | #define P17V_SE_SLOT_SEL_L 0x19 /* Sound Engine slot select low */ | ||
| 38 | #define P17V_SE_SLOT_SEL_H 0x1a /* Sound Engine slot select high */ | ||
| 39 | /* 1b - 1f: Not used */ | ||
| 40 | /* 20 - 2f: Not used */ | ||
| 41 | /* 30 - 3b: Not used */ | ||
| 42 | #define P17V_SPI 0x3c /* SPI interface register */ | ||
| 43 | #define P17V_I2C_ADDR 0x3d /* I2C Address */ | ||
| 44 | #define P17V_I2C_0 0x3e /* I2C Data */ | ||
| 45 | #define P17V_I2C_1 0x3f /* I2C Data */ | ||
| 46 | |||
| 47 | #define P17V_START_AUDIO 0x40 /* Start Audio bit */ | ||
| 48 | /* 41 - 47: Reserved */ | ||
| 49 | #define P17V_START_CAPTURE 0x48 /* Start Capture bit */ | ||
| 50 | #define P17V_CAPTURE_FIFO_BASE 0x49 /* Record FIFO base address */ | ||
| 51 | #define P17V_CAPTURE_FIFO_SIZE 0x4a /* Record FIFO buffer size */ | ||
| 52 | #define P17V_CAPTURE_FIFO_INDEX 0x4b /* Record FIFO capture index */ | ||
| 53 | #define P17V_CAPTURE_VOL_H 0x4c /* P17v capture volume control */ | ||
| 54 | #define P17V_CAPTURE_VOL_L 0x4d /* P17v capture volume control */ | ||
| 55 | /* 4e - 4f: Not used */ | ||
| 56 | /* 50 - 5f: Not used */ | ||
| 57 | #define P17V_SRCSel 0x60 /* SRC48 and SRCMulti sample rate select | ||
| 58 | * and output select | ||
| 59 | */ | ||
| 60 | #define P17V_MIXER_AC97_10K1_VOL_L 0x61 /* 10K to Mixer_AC97 input volume control */ | ||
| 61 | #define P17V_MIXER_AC97_10K1_VOL_H 0x62 /* 10K to Mixer_AC97 input volume control */ | ||
| 62 | #define P17V_MIXER_AC97_P17V_VOL_L 0x63 /* P17V to Mixer_AC97 input volume control */ | ||
| 63 | #define P17V_MIXER_AC97_P17V_VOL_H 0x64 /* P17V to Mixer_AC97 input volume control */ | ||
| 64 | #define P17V_MIXER_AC97_SRP_REC_VOL_L 0x65 /* SRP Record to Mixer_AC97 input volume control */ | ||
| 65 | #define P17V_MIXER_AC97_SRP_REC_VOL_H 0x66 /* SRP Record to Mixer_AC97 input volume control */ | ||
| 66 | /* 67 - 68: Reserved */ | ||
| 67 | #define P17V_MIXER_Spdif_10K1_VOL_L 0x69 /* 10K to Mixer_Spdif input volume control */ | ||
| 68 | #define P17V_MIXER_Spdif_10K1_VOL_H 0x6A /* 10K to Mixer_Spdif input volume control */ | ||
| 69 | #define P17V_MIXER_Spdif_P17V_VOL_L 0x6B /* P17V to Mixer_Spdif input volume control */ | ||
| 70 | #define P17V_MIXER_Spdif_P17V_VOL_H 0x6C /* P17V to Mixer_Spdif input volume control */ | ||
| 71 | #define P17V_MIXER_Spdif_SRP_REC_VOL_L 0x6D /* SRP Record to Mixer_Spdif input volume control */ | ||
| 72 | #define P17V_MIXER_Spdif_SRP_REC_VOL_H 0x6E /* SRP Record to Mixer_Spdif input volume control */ | ||
| 73 | /* 6f - 70: Reserved */ | ||
| 74 | #define P17V_MIXER_I2S_10K1_VOL_L 0x71 /* 10K to Mixer_I2S input volume control */ | ||
| 75 | #define P17V_MIXER_I2S_10K1_VOL_H 0x72 /* 10K to Mixer_I2S input volume control */ | ||
| 76 | #define P17V_MIXER_I2S_P17V_VOL_L 0x73 /* P17V to Mixer_I2S input volume control */ | ||
| 77 | #define P17V_MIXER_I2S_P17V_VOL_H 0x74 /* P17V to Mixer_I2S input volume control */ | ||
| 78 | #define P17V_MIXER_I2S_SRP_REC_VOL_L 0x75 /* SRP Record to Mixer_I2S input volume control */ | ||
| 79 | #define P17V_MIXER_I2S_SRP_REC_VOL_H 0x76 /* SRP Record to Mixer_I2S input volume control */ | ||
| 80 | /* 77 - 78: Reserved */ | ||
| 81 | #define P17V_MIXER_AC97_ENABLE 0x79 /* Mixer AC97 input audio enable */ | ||
| 82 | #define P17V_MIXER_SPDIF_ENABLE 0x7A /* Mixer SPDIF input audio enable */ | ||
| 83 | #define P17V_MIXER_I2S_ENABLE 0x7B /* Mixer I2S input audio enable */ | ||
| 84 | #define P17V_AUDIO_OUT_ENABLE 0x7C /* Audio out enable */ | ||
| 85 | #define P17V_MIXER_ATT 0x7D /* SRP Mixer Attenuation Select */ | ||
| 86 | #define P17V_SRP_RECORD_SRR 0x7E /* SRP Record channel source Select */ | ||
| 87 | #define P17V_SOFT_RESET_SRP_MIXER 0x7F /* SRP and mixer soft reset */ | ||
| 88 | |||
| 89 | #define P17V_AC97_OUT_MASTER_VOL_L 0x80 /* AC97 Output master volume control */ | ||
| 90 | #define P17V_AC97_OUT_MASTER_VOL_H 0x81 /* AC97 Output master volume control */ | ||
| 91 | #define P17V_SPDIF_OUT_MASTER_VOL_L 0x82 /* SPDIF Output master volume control */ | ||
| 92 | #define P17V_SPDIF_OUT_MASTER_VOL_H 0x83 /* SPDIF Output master volume control */ | ||
| 93 | #define P17V_I2S_OUT_MASTER_VOL_L 0x84 /* I2S Output master volume control */ | ||
| 94 | #define P17V_I2S_OUT_MASTER_VOL_H 0x85 /* I2S Output master volume control */ | ||
| 95 | /* 86 - 87: Not used */ | ||
| 96 | #define P17V_I2S_CHANNEL_SWAP_PHASE_INVERSE 0x88 /* I2S out mono channel swap | ||
| 97 | * and phase inverse */ | ||
| 98 | #define P17V_SPDIF_CHANNEL_SWAP_PHASE_INVERSE 0x89 /* SPDIF out mono channel swap | ||
| 99 | * and phase inverse */ | ||
| 100 | /* 8A: Not used */ | ||
| 101 | #define P17V_SRP_P17V_ESR 0x8B /* SRP_P17V estimated sample rate and rate lock */ | ||
| 102 | #define P17V_SRP_REC_ESR 0x8C /* SRP_REC estimated sample rate and rate lock */ | ||
| 103 | #define P17V_SRP_BYPASS 0x8D /* srps channel bypass and srps bypass */ | ||
| 104 | /* 8E - 92: Not used */ | ||
| 105 | #define P17V_I2S_SRC_SEL 0x93 /* I2SIN mode sel */ | ||
| 106 | |||
| 107 | |||
| 108 | |||
| 109 | |||
| 110 | |||
| 111 | |||
diff --git a/sound/pci/emu10k1/tina2.h b/sound/pci/emu10k1/tina2.h index 5c43abf03e89..f2d8eb6c89e1 100644 --- a/sound/pci/emu10k1/tina2.h +++ b/sound/pci/emu10k1/tina2.h | |||
| @@ -1,11 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> | 2 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> |
| 3 | * Driver p16v chips | 3 | * Driver tina2 chips |
| 4 | * Version: 0.21 | 4 | * Version: 0.1 |
| 5 | * | ||
| 6 | * | ||
| 7 | * This code was initally based on code from ALSA's emu10k1x.c which is: | ||
| 8 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> | ||
| 9 | * | 5 | * |
| 10 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index 56ffb7dc3ee2..94eca82dd4fc 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c | |||
| @@ -139,6 +139,8 @@ int snd_emu10k1_voice_alloc(struct snd_emu10k1 *emu, int type, int number, | |||
| 139 | return result; | 139 | return result; |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | EXPORT_SYMBOL(snd_emu10k1_voice_alloc); | ||
| 143 | |||
| 142 | int snd_emu10k1_voice_free(struct snd_emu10k1 *emu, | 144 | int snd_emu10k1_voice_free(struct snd_emu10k1 *emu, |
| 143 | struct snd_emu10k1_voice *pvoice) | 145 | struct snd_emu10k1_voice *pvoice) |
| 144 | { | 146 | { |
| @@ -153,3 +155,5 @@ int snd_emu10k1_voice_free(struct snd_emu10k1 *emu, | |||
| 153 | spin_unlock_irqrestore(&emu->voice_lock, flags); | 155 | spin_unlock_irqrestore(&emu->voice_lock, flags); |
| 154 | return 0; | 156 | return 0; |
| 155 | } | 157 | } |
| 158 | |||
| 159 | EXPORT_SYMBOL(snd_emu10k1_voice_free); | ||
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index ca9e34e88f62..9d46bbee2a40 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c | |||
| @@ -1915,7 +1915,7 @@ static void __devinit snd_ensoniq_proc_init(struct ensoniq * ensoniq) | |||
| 1915 | struct snd_info_entry *entry; | 1915 | struct snd_info_entry *entry; |
| 1916 | 1916 | ||
| 1917 | if (! snd_card_proc_new(ensoniq->card, "audiopci", &entry)) | 1917 | if (! snd_card_proc_new(ensoniq->card, "audiopci", &entry)) |
| 1918 | snd_info_set_text_ops(entry, ensoniq, 1024, snd_ensoniq_proc_read); | 1918 | snd_info_set_text_ops(entry, ensoniq, snd_ensoniq_proc_read); |
| 1919 | } | 1919 | } |
| 1920 | 1920 | ||
| 1921 | /* | 1921 | /* |
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 6f9094ca4fb4..ca6603fe0b11 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c | |||
| @@ -1756,7 +1756,8 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, | |||
| 1756 | } | 1756 | } |
| 1757 | } | 1757 | } |
| 1758 | if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, | 1758 | if (snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, |
| 1759 | chip->mpu_port, 1, chip->irq, 0, &chip->rmidi) < 0) { | 1759 | chip->mpu_port, MPU401_INFO_INTEGRATED, |
| 1760 | chip->irq, 0, &chip->rmidi) < 0) { | ||
| 1760 | printk(KERN_ERR "es1938: unable to initialize MPU-401\n"); | 1761 | printk(KERN_ERR "es1938: unable to initialize MPU-401\n"); |
| 1761 | } else { | 1762 | } else { |
| 1762 | // this line is vital for MIDI interrupt handling on ess-solo1 | 1763 | // this line is vital for MIDI interrupt handling on ess-solo1 |
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 5ff4175c7b6d..bfa0876e715e 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c | |||
| @@ -132,7 +132,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * | |||
| 132 | static int total_bufsize[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1024 }; | 132 | static int total_bufsize[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1024 }; |
| 133 | static int pcm_substreams_p[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4 }; | 133 | static int pcm_substreams_p[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4 }; |
| 134 | static int pcm_substreams_c[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1 }; | 134 | static int pcm_substreams_c[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1 }; |
| 135 | static int clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 135 | static int clock[SNDRV_CARDS]; |
| 136 | static int use_pm[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; | 136 | static int use_pm[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; |
| 137 | static int enable_mpu[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; | 137 | static int enable_mpu[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; |
| 138 | #ifdef SUPPORT_JOYSTICK | 138 | #ifdef SUPPORT_JOYSTICK |
| @@ -2727,7 +2727,8 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci, | |||
| 2727 | } | 2727 | } |
| 2728 | if (enable_mpu[dev]) { | 2728 | if (enable_mpu[dev]) { |
| 2729 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, | 2729 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, |
| 2730 | chip->io_port + ESM_MPU401_PORT, 1, | 2730 | chip->io_port + ESM_MPU401_PORT, |
| 2731 | MPU401_INFO_INTEGRATED, | ||
| 2731 | chip->irq, 0, &chip->rmidi)) < 0) { | 2732 | chip->irq, 0, &chip->rmidi)) < 0) { |
| 2732 | printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n"); | 2733 | printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n"); |
| 2733 | } | 2734 | } |
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index d72fc28c580e..0afa573dd244 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c | |||
| @@ -56,7 +56,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * | |||
| 56 | * 3 = MediaForte 64-PCR | 56 | * 3 = MediaForte 64-PCR |
| 57 | * High 16-bits are video (radio) device number + 1 | 57 | * High 16-bits are video (radio) device number + 1 |
| 58 | */ | 58 | */ |
| 59 | static int tea575x_tuner[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; | 59 | static int tea575x_tuner[SNDRV_CARDS]; |
| 60 | 60 | ||
| 61 | module_param_array(index, int, NULL, 0444); | 61 | module_param_array(index, int, NULL, 0444); |
| 62 | MODULE_PARM_DESC(index, "Index value for the FM801 soundcard."); | 62 | MODULE_PARM_DESC(index, "Index value for the FM801 soundcard."); |
| @@ -1448,7 +1448,8 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, | |||
| 1448 | return err; | 1448 | return err; |
| 1449 | } | 1449 | } |
| 1450 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801, | 1450 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801, |
| 1451 | FM801_REG(chip, MPU401_DATA), 1, | 1451 | FM801_REG(chip, MPU401_DATA), |
| 1452 | MPU401_INFO_INTEGRATED, | ||
| 1452 | chip->irq, 0, &chip->rmidi)) < 0) { | 1453 | chip->irq, 0, &chip->rmidi)) < 0) { |
| 1453 | snd_card_free(card); | 1454 | snd_card_free(card); |
| 1454 | return err; | 1455 | return err; |
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index ddfb5ff7fb8f..dbacba6177db 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | snd-hda-intel-objs := hda_intel.o | 1 | snd-hda-intel-objs := hda_intel.o |
| 2 | snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o | 2 | snd-hda-codec-objs := hda_codec.o hda_generic.o patch_realtek.o patch_cmedia.o patch_analog.o patch_sigmatel.o patch_si3054.o patch_atihdmi.o |
| 3 | ifdef CONFIG_PROC_FS | 3 | ifdef CONFIG_PROC_FS |
| 4 | snd-hda-codec-objs += hda_proc.o | 4 | snd-hda-codec-objs += hda_proc.o |
| 5 | endif | 5 | endif |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5bee3b536478..8c2a8174ece1 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
| @@ -86,6 +86,8 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, int dire | |||
| 86 | return res; | 86 | return res; |
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | EXPORT_SYMBOL(snd_hda_codec_read); | ||
| 90 | |||
| 89 | /** | 91 | /** |
| 90 | * snd_hda_codec_write - send a single command without waiting for response | 92 | * snd_hda_codec_write - send a single command without waiting for response |
| 91 | * @codec: the HDA codec | 93 | * @codec: the HDA codec |
| @@ -108,6 +110,8 @@ int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, | |||
| 108 | return err; | 110 | return err; |
| 109 | } | 111 | } |
| 110 | 112 | ||
| 113 | EXPORT_SYMBOL(snd_hda_codec_write); | ||
| 114 | |||
| 111 | /** | 115 | /** |
| 112 | * snd_hda_sequence_write - sequence writes | 116 | * snd_hda_sequence_write - sequence writes |
| 113 | * @codec: the HDA codec | 117 | * @codec: the HDA codec |
| @@ -122,6 +126,8 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) | |||
| 122 | snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); | 126 | snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); |
| 123 | } | 127 | } |
| 124 | 128 | ||
| 129 | EXPORT_SYMBOL(snd_hda_sequence_write); | ||
| 130 | |||
| 125 | /** | 131 | /** |
| 126 | * snd_hda_get_sub_nodes - get the range of sub nodes | 132 | * snd_hda_get_sub_nodes - get the range of sub nodes |
| 127 | * @codec: the HDA codec | 133 | * @codec: the HDA codec |
| @@ -140,6 +146,8 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *sta | |||
| 140 | return (int)(parm & 0x7fff); | 146 | return (int)(parm & 0x7fff); |
| 141 | } | 147 | } |
| 142 | 148 | ||
| 149 | EXPORT_SYMBOL(snd_hda_get_sub_nodes); | ||
| 150 | |||
| 143 | /** | 151 | /** |
| 144 | * snd_hda_get_connections - get connection list | 152 | * snd_hda_get_connections - get connection list |
| 145 | * @codec: the HDA codec | 153 | * @codec: the HDA codec |
| @@ -256,6 +264,8 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) | |||
| 256 | return 0; | 264 | return 0; |
| 257 | } | 265 | } |
| 258 | 266 | ||
| 267 | EXPORT_SYMBOL(snd_hda_queue_unsol_event); | ||
| 268 | |||
| 259 | /* | 269 | /* |
| 260 | * process queueud unsolicited events | 270 | * process queueud unsolicited events |
| 261 | */ | 271 | */ |
| @@ -384,6 +394,7 @@ int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, | |||
| 384 | return 0; | 394 | return 0; |
| 385 | } | 395 | } |
| 386 | 396 | ||
| 397 | EXPORT_SYMBOL(snd_hda_bus_new); | ||
| 387 | 398 | ||
| 388 | /* | 399 | /* |
| 389 | * find a matching codec preset | 400 | * find a matching codec preset |
| @@ -587,6 +598,8 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, | |||
| 587 | return 0; | 598 | return 0; |
| 588 | } | 599 | } |
| 589 | 600 | ||
| 601 | EXPORT_SYMBOL(snd_hda_codec_new); | ||
| 602 | |||
| 590 | /** | 603 | /** |
| 591 | * snd_hda_codec_setup_stream - set up the codec for streaming | 604 | * snd_hda_codec_setup_stream - set up the codec for streaming |
| 592 | * @codec: the CODEC to set up | 605 | * @codec: the CODEC to set up |
| @@ -609,6 +622,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, u32 stre | |||
| 609 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); | 622 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, format); |
| 610 | } | 623 | } |
| 611 | 624 | ||
| 625 | EXPORT_SYMBOL(snd_hda_codec_setup_stream); | ||
| 612 | 626 | ||
| 613 | /* | 627 | /* |
| 614 | * amp access functions | 628 | * amp access functions |
| @@ -1294,6 +1308,7 @@ int snd_hda_build_controls(struct hda_bus *bus) | |||
| 1294 | return 0; | 1308 | return 0; |
| 1295 | } | 1309 | } |
| 1296 | 1310 | ||
| 1311 | EXPORT_SYMBOL(snd_hda_build_controls); | ||
| 1297 | 1312 | ||
| 1298 | /* | 1313 | /* |
| 1299 | * stream formats | 1314 | * stream formats |
| @@ -1382,6 +1397,8 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, | |||
| 1382 | return val; | 1397 | return val; |
| 1383 | } | 1398 | } |
| 1384 | 1399 | ||
| 1400 | EXPORT_SYMBOL(snd_hda_calc_stream_format); | ||
| 1401 | |||
| 1385 | /** | 1402 | /** |
| 1386 | * snd_hda_query_supported_pcm - query the supported PCM rates and formats | 1403 | * snd_hda_query_supported_pcm - query the supported PCM rates and formats |
| 1387 | * @codec: the HDA codec | 1404 | * @codec: the HDA codec |
| @@ -1663,6 +1680,7 @@ int snd_hda_build_pcms(struct hda_bus *bus) | |||
| 1663 | return 0; | 1680 | return 0; |
| 1664 | } | 1681 | } |
| 1665 | 1682 | ||
| 1683 | EXPORT_SYMBOL(snd_hda_build_pcms); | ||
| 1666 | 1684 | ||
| 1667 | /** | 1685 | /** |
| 1668 | * snd_hda_check_board_config - compare the current codec with the config table | 1686 | * snd_hda_check_board_config - compare the current codec with the config table |
| @@ -2165,6 +2183,8 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) | |||
| 2165 | return 0; | 2183 | return 0; |
| 2166 | } | 2184 | } |
| 2167 | 2185 | ||
| 2186 | EXPORT_SYMBOL(snd_hda_suspend); | ||
| 2187 | |||
| 2168 | /** | 2188 | /** |
| 2169 | * snd_hda_resume - resume the codecs | 2189 | * snd_hda_resume - resume the codecs |
| 2170 | * @bus: the HDA bus | 2190 | * @bus: the HDA bus |
| @@ -2187,6 +2207,8 @@ int snd_hda_resume(struct hda_bus *bus) | |||
| 2187 | return 0; | 2207 | return 0; |
| 2188 | } | 2208 | } |
| 2189 | 2209 | ||
| 2210 | EXPORT_SYMBOL(snd_hda_resume); | ||
| 2211 | |||
| 2190 | /** | 2212 | /** |
| 2191 | * snd_hda_resume_ctls - resume controls in the new control list | 2213 | * snd_hda_resume_ctls - resume controls in the new control list |
| 2192 | * @codec: the HDA codec | 2214 | * @codec: the HDA codec |
| @@ -2247,25 +2269,6 @@ int snd_hda_resume_spdif_in(struct hda_codec *codec) | |||
| 2247 | #endif | 2269 | #endif |
| 2248 | 2270 | ||
| 2249 | /* | 2271 | /* |
| 2250 | * symbols exported for controller modules | ||
| 2251 | */ | ||
| 2252 | EXPORT_SYMBOL(snd_hda_codec_read); | ||
| 2253 | EXPORT_SYMBOL(snd_hda_codec_write); | ||
| 2254 | EXPORT_SYMBOL(snd_hda_sequence_write); | ||
| 2255 | EXPORT_SYMBOL(snd_hda_get_sub_nodes); | ||
| 2256 | EXPORT_SYMBOL(snd_hda_queue_unsol_event); | ||
| 2257 | EXPORT_SYMBOL(snd_hda_bus_new); | ||
| 2258 | EXPORT_SYMBOL(snd_hda_codec_new); | ||
| 2259 | EXPORT_SYMBOL(snd_hda_codec_setup_stream); | ||
| 2260 | EXPORT_SYMBOL(snd_hda_calc_stream_format); | ||
| 2261 | EXPORT_SYMBOL(snd_hda_build_pcms); | ||
| 2262 | EXPORT_SYMBOL(snd_hda_build_controls); | ||
| 2263 | #ifdef CONFIG_PM | ||
| 2264 | EXPORT_SYMBOL(snd_hda_suspend); | ||
| 2265 | EXPORT_SYMBOL(snd_hda_resume); | ||
| 2266 | #endif | ||
| 2267 | |||
| 2268 | /* | ||
| 2269 | * INIT part | 2272 | * INIT part |
| 2270 | */ | 2273 | */ |
| 2271 | 2274 | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e821d65afa11..4070b5cd9b6b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
| @@ -82,6 +82,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | |||
| 82 | "{Intel, ICH8}," | 82 | "{Intel, ICH8}," |
| 83 | "{ATI, SB450}," | 83 | "{ATI, SB450}," |
| 84 | "{ATI, SB600}," | 84 | "{ATI, SB600}," |
| 85 | "{ATI, RS600}," | ||
| 85 | "{VIA, VT8251}," | 86 | "{VIA, VT8251}," |
| 86 | "{VIA, VT8237A}," | 87 | "{VIA, VT8237A}," |
| 87 | "{SiS, SIS966}," | 88 | "{SiS, SIS966}," |
| @@ -167,6 +168,12 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
| 167 | #define ULI_PLAYBACK_INDEX 5 | 168 | #define ULI_PLAYBACK_INDEX 5 |
| 168 | #define ULI_NUM_PLAYBACK 6 | 169 | #define ULI_NUM_PLAYBACK 6 |
| 169 | 170 | ||
| 171 | /* ATI HDMI has 1 playback and 0 capture */ | ||
| 172 | #define ATIHDMI_CAPTURE_INDEX 0 | ||
| 173 | #define ATIHDMI_NUM_CAPTURE 0 | ||
| 174 | #define ATIHDMI_PLAYBACK_INDEX 0 | ||
| 175 | #define ATIHDMI_NUM_PLAYBACK 1 | ||
| 176 | |||
| 170 | /* this number is statically defined for simplicity */ | 177 | /* this number is statically defined for simplicity */ |
| 171 | #define MAX_AZX_DEV 16 | 178 | #define MAX_AZX_DEV 16 |
| 172 | 179 | ||
| @@ -331,6 +338,7 @@ struct azx { | |||
| 331 | enum { | 338 | enum { |
| 332 | AZX_DRIVER_ICH, | 339 | AZX_DRIVER_ICH, |
| 333 | AZX_DRIVER_ATI, | 340 | AZX_DRIVER_ATI, |
| 341 | AZX_DRIVER_ATIHDMI, | ||
| 334 | AZX_DRIVER_VIA, | 342 | AZX_DRIVER_VIA, |
| 335 | AZX_DRIVER_SIS, | 343 | AZX_DRIVER_SIS, |
| 336 | AZX_DRIVER_ULI, | 344 | AZX_DRIVER_ULI, |
| @@ -340,6 +348,7 @@ enum { | |||
| 340 | static char *driver_short_names[] __devinitdata = { | 348 | static char *driver_short_names[] __devinitdata = { |
| 341 | [AZX_DRIVER_ICH] = "HDA Intel", | 349 | [AZX_DRIVER_ICH] = "HDA Intel", |
| 342 | [AZX_DRIVER_ATI] = "HDA ATI SB", | 350 | [AZX_DRIVER_ATI] = "HDA ATI SB", |
| 351 | [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", | ||
| 343 | [AZX_DRIVER_VIA] = "HDA VIA VT82xx", | 352 | [AZX_DRIVER_VIA] = "HDA VIA VT82xx", |
| 344 | [AZX_DRIVER_SIS] = "HDA SIS966", | 353 | [AZX_DRIVER_SIS] = "HDA SIS966", |
| 345 | [AZX_DRIVER_ULI] = "HDA ULI M5461", | 354 | [AZX_DRIVER_ULI] = "HDA ULI M5461", |
| @@ -1393,10 +1402,10 @@ static int azx_free(struct azx *chip) | |||
| 1393 | msleep(1); | 1402 | msleep(1); |
| 1394 | } | 1403 | } |
| 1395 | 1404 | ||
| 1396 | if (chip->remap_addr) | ||
| 1397 | iounmap(chip->remap_addr); | ||
| 1398 | if (chip->irq >= 0) | 1405 | if (chip->irq >= 0) |
| 1399 | free_irq(chip->irq, (void*)chip); | 1406 | free_irq(chip->irq, (void*)chip); |
| 1407 | if (chip->remap_addr) | ||
| 1408 | iounmap(chip->remap_addr); | ||
| 1400 | 1409 | ||
| 1401 | if (chip->bdl.area) | 1410 | if (chip->bdl.area) |
| 1402 | snd_dma_free_pages(&chip->bdl); | 1411 | snd_dma_free_pages(&chip->bdl); |
| @@ -1495,6 +1504,12 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
| 1495 | chip->playback_index_offset = ULI_PLAYBACK_INDEX; | 1504 | chip->playback_index_offset = ULI_PLAYBACK_INDEX; |
| 1496 | chip->capture_index_offset = ULI_CAPTURE_INDEX; | 1505 | chip->capture_index_offset = ULI_CAPTURE_INDEX; |
| 1497 | break; | 1506 | break; |
| 1507 | case AZX_DRIVER_ATIHDMI: | ||
| 1508 | chip->playback_streams = ATIHDMI_NUM_PLAYBACK; | ||
| 1509 | chip->capture_streams = ATIHDMI_NUM_CAPTURE; | ||
| 1510 | chip->playback_index_offset = ATIHDMI_PLAYBACK_INDEX; | ||
| 1511 | chip->capture_index_offset = ATIHDMI_CAPTURE_INDEX; | ||
| 1512 | break; | ||
| 1498 | default: | 1513 | default: |
| 1499 | chip->playback_streams = ICH6_NUM_PLAYBACK; | 1514 | chip->playback_streams = ICH6_NUM_PLAYBACK; |
| 1500 | chip->capture_streams = ICH6_NUM_CAPTURE; | 1515 | chip->capture_streams = ICH6_NUM_CAPTURE; |
| @@ -1621,6 +1636,7 @@ static struct pci_device_id azx_ids[] __devinitdata = { | |||
| 1621 | { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ | 1636 | { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */ |
| 1622 | { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ | 1637 | { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */ |
| 1623 | { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ | 1638 | { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */ |
| 1639 | { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */ | ||
| 1624 | { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ | 1640 | { 0x1106, 0x3288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_VIA }, /* VIA VT8251/VT8237A */ |
| 1625 | { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ | 1641 | { 0x1039, 0x7502, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_SIS }, /* SIS966 */ |
| 1626 | { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ | 1642 | { 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */ |
diff --git a/sound/pci/hda/hda_patch.h b/sound/pci/hda/hda_patch.h index acaef3c811b8..0b668793face 100644 --- a/sound/pci/hda/hda_patch.h +++ b/sound/pci/hda/hda_patch.h | |||
| @@ -12,6 +12,8 @@ extern struct hda_codec_preset snd_hda_preset_analog[]; | |||
| 12 | extern struct hda_codec_preset snd_hda_preset_sigmatel[]; | 12 | extern struct hda_codec_preset snd_hda_preset_sigmatel[]; |
| 13 | /* SiLabs 3054/3055 modem codecs */ | 13 | /* SiLabs 3054/3055 modem codecs */ |
| 14 | extern struct hda_codec_preset snd_hda_preset_si3054[]; | 14 | extern struct hda_codec_preset snd_hda_preset_si3054[]; |
| 15 | /* ATI HDMI codecs */ | ||
| 16 | extern struct hda_codec_preset snd_hda_preset_atihdmi[]; | ||
| 15 | 17 | ||
| 16 | static const struct hda_codec_preset *hda_preset_tables[] = { | 18 | static const struct hda_codec_preset *hda_preset_tables[] = { |
| 17 | snd_hda_preset_realtek, | 19 | snd_hda_preset_realtek, |
| @@ -19,5 +21,6 @@ static const struct hda_codec_preset *hda_preset_tables[] = { | |||
| 19 | snd_hda_preset_analog, | 21 | snd_hda_preset_analog, |
| 20 | snd_hda_preset_sigmatel, | 22 | snd_hda_preset_sigmatel, |
| 21 | snd_hda_preset_si3054, | 23 | snd_hda_preset_si3054, |
| 24 | snd_hda_preset_atihdmi, | ||
| 22 | NULL | 25 | NULL |
| 23 | }; | 26 | }; |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index ca514a6a5875..c2f0fe85bf35 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
| @@ -182,6 +182,10 @@ static void print_pin_caps(struct snd_info_buffer *buffer, | |||
| 182 | snd_iprintf(buffer, " OUT"); | 182 | snd_iprintf(buffer, " OUT"); |
| 183 | if (caps & AC_PINCAP_HP_DRV) | 183 | if (caps & AC_PINCAP_HP_DRV) |
| 184 | snd_iprintf(buffer, " HP"); | 184 | snd_iprintf(buffer, " HP"); |
| 185 | if (caps & AC_PINCAP_EAPD) | ||
| 186 | snd_iprintf(buffer, " EAPD"); | ||
| 187 | if (caps & AC_PINCAP_PRES_DETECT) | ||
| 188 | snd_iprintf(buffer, " Detect"); | ||
| 185 | snd_iprintf(buffer, "\n"); | 189 | snd_iprintf(buffer, "\n"); |
| 186 | caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); | 190 | caps = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONFIG_DEFAULT, 0); |
| 187 | snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, | 191 | snd_iprintf(buffer, " Pin Default 0x%08x: [%s] %s at %s %s\n", caps, |
| @@ -318,7 +322,7 @@ int snd_hda_codec_proc_new(struct hda_codec *codec) | |||
| 318 | if (err < 0) | 322 | if (err < 0) |
| 319 | return err; | 323 | return err; |
| 320 | 324 | ||
| 321 | snd_info_set_text_ops(entry, codec, 32 * 1024, print_codec_info); | 325 | snd_info_set_text_ops(entry, codec, print_codec_info); |
| 322 | return 0; | 326 | return 0; |
| 323 | } | 327 | } |
| 324 | 328 | ||
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 40f000ba1362..dd4e00a82b55 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
| @@ -789,6 +789,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { | |||
| 789 | { .modelname = "3stack", .config = AD1986A_3STACK }, | 789 | { .modelname = "3stack", .config = AD1986A_3STACK }, |
| 790 | { .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84, | 790 | { .pci_subvendor = 0x10de, .pci_subdevice = 0xcb84, |
| 791 | .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ | 791 | .config = AD1986A_3STACK }, /* ASUS A8N-VM CSM */ |
| 792 | { .pci_subvendor = 0x1043, .pci_subdevice = 0x81b3, | ||
| 793 | .config = AD1986A_3STACK }, /* ASUS P5RD2-VM / P5GPL-X SE */ | ||
| 792 | { .modelname = "laptop", .config = AD1986A_LAPTOP }, | 794 | { .modelname = "laptop", .config = AD1986A_LAPTOP }, |
| 793 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, | 795 | { .pci_subvendor = 0x144d, .pci_subdevice = 0xc01e, |
| 794 | .config = AD1986A_LAPTOP }, /* FSC V2060 */ | 796 | .config = AD1986A_LAPTOP }, /* FSC V2060 */ |
| @@ -809,6 +811,8 @@ static struct hda_board_config ad1986a_cfg_tbl[] = { | |||
| 809 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */ | 811 | .config = AD1986A_LAPTOP_EAPD }, /* ASUS Z62F */ |
| 810 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x30af, | 812 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x30af, |
| 811 | .config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */ | 813 | .config = AD1986A_LAPTOP_EAPD }, /* HP Compaq Presario B2800 */ |
| 814 | { .pci_subvendor = 0x17aa, .pci_subdevice = 0x2066, | ||
| 815 | .config = AD1986A_LAPTOP_EAPD }, /* Lenovo 3000 N100-07684JU */ | ||
| 812 | {} | 816 | {} |
| 813 | }; | 817 | }; |
| 814 | 818 | ||
| @@ -963,7 +967,7 @@ static struct snd_kcontrol_new ad1983_mixers[] = { | |||
| 963 | }, | 967 | }, |
| 964 | { | 968 | { |
| 965 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 969 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 966 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route", | 970 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
| 967 | .info = ad1983_spdif_route_info, | 971 | .info = ad1983_spdif_route_info, |
| 968 | .get = ad1983_spdif_route_get, | 972 | .get = ad1983_spdif_route_get, |
| 969 | .put = ad1983_spdif_route_put, | 973 | .put = ad1983_spdif_route_put, |
| @@ -1103,7 +1107,7 @@ static struct snd_kcontrol_new ad1981_mixers[] = { | |||
| 1103 | /* identical with AD1983 */ | 1107 | /* identical with AD1983 */ |
| 1104 | { | 1108 | { |
| 1105 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1109 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1106 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Route", | 1110 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
| 1107 | .info = ad1983_spdif_route_info, | 1111 | .info = ad1983_spdif_route_info, |
| 1108 | .get = ad1983_spdif_route_get, | 1112 | .get = ad1983_spdif_route_get, |
| 1109 | .put = ad1983_spdif_route_put, | 1113 | .put = ad1983_spdif_route_put, |
| @@ -1329,13 +1333,60 @@ static int ad1981_hp_init(struct hda_codec *codec) | |||
| 1329 | return 0; | 1333 | return 0; |
| 1330 | } | 1334 | } |
| 1331 | 1335 | ||
| 1336 | /* configuration for Lenovo Thinkpad T60 */ | ||
| 1337 | static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { | ||
| 1338 | HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT), | ||
| 1339 | HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT), | ||
| 1340 | HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), | ||
| 1341 | HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), | ||
| 1342 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), | ||
| 1343 | HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), | ||
| 1344 | HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), | ||
| 1345 | HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), | ||
| 1346 | HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT), | ||
| 1347 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), | ||
| 1348 | HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), | ||
| 1349 | { | ||
| 1350 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 1351 | .name = "Capture Source", | ||
| 1352 | .info = ad198x_mux_enum_info, | ||
| 1353 | .get = ad198x_mux_enum_get, | ||
| 1354 | .put = ad198x_mux_enum_put, | ||
| 1355 | }, | ||
| 1356 | /* identical with AD1983 */ | ||
| 1357 | { | ||
| 1358 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 1359 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", | ||
| 1360 | .info = ad1983_spdif_route_info, | ||
| 1361 | .get = ad1983_spdif_route_get, | ||
| 1362 | .put = ad1983_spdif_route_put, | ||
| 1363 | }, | ||
| 1364 | { } /* end */ | ||
| 1365 | }; | ||
| 1366 | |||
| 1367 | static struct hda_input_mux ad1981_thinkpad_capture_source = { | ||
| 1368 | .num_items = 3, | ||
| 1369 | .items = { | ||
| 1370 | { "Mic", 0x0 }, | ||
| 1371 | { "Mix", 0x2 }, | ||
| 1372 | { "CD", 0x4 }, | ||
| 1373 | }, | ||
| 1374 | }; | ||
| 1375 | |||
| 1332 | /* models */ | 1376 | /* models */ |
| 1333 | enum { AD1981_BASIC, AD1981_HP }; | 1377 | enum { AD1981_BASIC, AD1981_HP, AD1981_THINKPAD }; |
| 1334 | 1378 | ||
| 1335 | static struct hda_board_config ad1981_cfg_tbl[] = { | 1379 | static struct hda_board_config ad1981_cfg_tbl[] = { |
| 1336 | { .modelname = "hp", .config = AD1981_HP }, | 1380 | { .modelname = "hp", .config = AD1981_HP }, |
| 1337 | /* All HP models */ | 1381 | /* All HP models */ |
| 1338 | { .pci_subvendor = 0x103c, .config = AD1981_HP }, | 1382 | { .pci_subvendor = 0x103c, .config = AD1981_HP }, |
| 1383 | { .pci_subvendor = 0x30b0, .pci_subdevice = 0x103c, | ||
| 1384 | .config = AD1981_HP }, /* HP nx6320 (reversed SSID, H/W bug) */ | ||
| 1385 | { .modelname = "thinkpad", .config = AD1981_THINKPAD }, | ||
| 1386 | /* Lenovo Thinkpad T60/X60/Z6xx */ | ||
| 1387 | { .pci_subvendor = 0x17aa, .config = AD1981_THINKPAD }, | ||
| 1388 | { .pci_subvendor = 0x1014, .pci_subdevice = 0x0597, | ||
| 1389 | .config = AD1981_THINKPAD }, /* Z60m/t */ | ||
| 1339 | { .modelname = "basic", .config = AD1981_BASIC }, | 1390 | { .modelname = "basic", .config = AD1981_BASIC }, |
| 1340 | {} | 1391 | {} |
| 1341 | }; | 1392 | }; |
| @@ -1381,6 +1432,10 @@ static int patch_ad1981(struct hda_codec *codec) | |||
| 1381 | codec->patch_ops.init = ad1981_hp_init; | 1432 | codec->patch_ops.init = ad1981_hp_init; |
| 1382 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; | 1433 | codec->patch_ops.unsol_event = ad1981_hp_unsol_event; |
| 1383 | break; | 1434 | break; |
| 1435 | case AD1981_THINKPAD: | ||
| 1436 | spec->mixers[0] = ad1981_thinkpad_mixers; | ||
| 1437 | spec->input_mux = &ad1981_thinkpad_capture_source; | ||
| 1438 | break; | ||
| 1384 | } | 1439 | } |
| 1385 | 1440 | ||
| 1386 | return 0; | 1441 | return 0; |
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c new file mode 100644 index 000000000000..a27440ffd1c8 --- /dev/null +++ b/sound/pci/hda/patch_atihdmi.c | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | /* | ||
| 2 | * Universal Interface for Intel High Definition Audio Codec | ||
| 3 | * | ||
| 4 | * HD audio interface patch for ATI HDMI codecs | ||
| 5 | * | ||
| 6 | * Copyright (c) 2006 ATI Technologies Inc. | ||
| 7 | * | ||
| 8 | * | ||
| 9 | * This driver is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This driver is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU General Public License | ||
| 20 | * along with this program; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <sound/driver.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/delay.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/pci.h> | ||
| 29 | #include <sound/core.h> | ||
| 30 | #include "hda_codec.h" | ||
| 31 | #include "hda_local.h" | ||
| 32 | |||
| 33 | struct atihdmi_spec { | ||
| 34 | struct hda_multi_out multiout; | ||
| 35 | |||
| 36 | struct hda_pcm pcm_rec; | ||
| 37 | }; | ||
| 38 | |||
| 39 | static struct hda_verb atihdmi_basic_init[] = { | ||
| 40 | /* enable digital output on pin widget */ | ||
| 41 | { 0x03, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
| 42 | {} /* terminator */ | ||
| 43 | }; | ||
| 44 | |||
| 45 | /* | ||
| 46 | * Controls | ||
| 47 | */ | ||
| 48 | static int atihdmi_build_controls(struct hda_codec *codec) | ||
| 49 | { | ||
| 50 | struct atihdmi_spec *spec = codec->spec; | ||
| 51 | int err; | ||
| 52 | |||
| 53 | err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); | ||
| 54 | if (err < 0) | ||
| 55 | return err; | ||
| 56 | |||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | static int atihdmi_init(struct hda_codec *codec) | ||
| 61 | { | ||
| 62 | snd_hda_sequence_write(codec, atihdmi_basic_init); | ||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | #ifdef CONFIG_PM | ||
| 67 | /* | ||
| 68 | * resume | ||
| 69 | */ | ||
| 70 | static int atihdmi_resume(struct hda_codec *codec) | ||
| 71 | { | ||
| 72 | atihdmi_init(codec); | ||
| 73 | snd_hda_resume_spdif_out(codec); | ||
| 74 | |||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | #endif | ||
| 78 | |||
| 79 | /* | ||
| 80 | * Digital out | ||
| 81 | */ | ||
| 82 | static int atihdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
| 83 | struct hda_codec *codec, | ||
| 84 | struct snd_pcm_substream *substream) | ||
| 85 | { | ||
| 86 | struct atihdmi_spec *spec = codec->spec; | ||
| 87 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
| 88 | } | ||
| 89 | |||
| 90 | static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
| 91 | struct hda_codec *codec, | ||
| 92 | struct snd_pcm_substream *substream) | ||
| 93 | { | ||
| 94 | struct atihdmi_spec *spec = codec->spec; | ||
| 95 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
| 96 | } | ||
| 97 | |||
| 98 | static struct hda_pcm_stream atihdmi_pcm_digital_playback = { | ||
| 99 | .substreams = 1, | ||
| 100 | .channels_min = 2, | ||
| 101 | .channels_max = 2, | ||
| 102 | .nid = 0x2, /* NID to query formats and rates and setup streams */ | ||
| 103 | .ops = { | ||
| 104 | .open = atihdmi_dig_playback_pcm_open, | ||
| 105 | .close = atihdmi_dig_playback_pcm_close | ||
| 106 | }, | ||
| 107 | }; | ||
| 108 | |||
| 109 | static int atihdmi_build_pcms(struct hda_codec *codec) | ||
| 110 | { | ||
| 111 | struct atihdmi_spec *spec = codec->spec; | ||
| 112 | struct hda_pcm *info = &spec->pcm_rec; | ||
| 113 | |||
| 114 | codec->num_pcms = 1; | ||
| 115 | codec->pcm_info = info; | ||
| 116 | |||
| 117 | info->name = "ATI HDMI"; | ||
| 118 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = atihdmi_pcm_digital_playback; | ||
| 119 | |||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | static void atihdmi_free(struct hda_codec *codec) | ||
| 124 | { | ||
| 125 | kfree(codec->spec); | ||
| 126 | } | ||
| 127 | |||
| 128 | static struct hda_codec_ops atihdmi_patch_ops = { | ||
| 129 | .build_controls = atihdmi_build_controls, | ||
| 130 | .build_pcms = atihdmi_build_pcms, | ||
| 131 | .init = atihdmi_init, | ||
| 132 | .free = atihdmi_free, | ||
| 133 | #ifdef CONFIG_PM | ||
| 134 | .resume = atihdmi_resume, | ||
| 135 | #endif | ||
| 136 | }; | ||
| 137 | |||
| 138 | static int patch_atihdmi(struct hda_codec *codec) | ||
| 139 | { | ||
| 140 | struct atihdmi_spec *spec; | ||
| 141 | |||
| 142 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
| 143 | if (spec == NULL) | ||
| 144 | return -ENOMEM; | ||
| 145 | |||
| 146 | codec->spec = spec; | ||
| 147 | |||
| 148 | spec->multiout.num_dacs = 0; /* no analog */ | ||
| 149 | spec->multiout.max_channels = 2; | ||
| 150 | spec->multiout.dig_out_nid = 0x2; /* NID for copying analog to digital, | ||
| 151 | * seems to be unused in pure-digital | ||
| 152 | * case. */ | ||
| 153 | |||
| 154 | codec->patch_ops = atihdmi_patch_ops; | ||
| 155 | |||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | /* | ||
| 160 | * patch entries | ||
| 161 | */ | ||
| 162 | struct hda_codec_preset snd_hda_preset_atihdmi[] = { | ||
| 163 | { .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi }, | ||
| 164 | {} /* terminator */ | ||
| 165 | }; | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f0e9a9c90780..98b9f16c26ff 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
| @@ -2174,6 +2174,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { | |||
| 2174 | 2174 | ||
| 2175 | { .modelname = "lg", .config = ALC880_LG }, | 2175 | { .modelname = "lg", .config = ALC880_LG }, |
| 2176 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG }, | 2176 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x003b, .config = ALC880_LG }, |
| 2177 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0068, .config = ALC880_LG }, | ||
| 2177 | 2178 | ||
| 2178 | { .modelname = "lg-lw", .config = ALC880_LG_LW }, | 2179 | { .modelname = "lg-lw", .config = ALC880_LG_LW }, |
| 2179 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW }, | 2180 | { .pci_subvendor = 0x1854, .pci_subdevice = 0x0018, .config = ALC880_LG_LW }, |
| @@ -3105,6 +3106,7 @@ static struct hda_verb alc260_init_verbs[] = { | |||
| 3105 | { } | 3106 | { } |
| 3106 | }; | 3107 | }; |
| 3107 | 3108 | ||
| 3109 | #if 0 /* should be identical with alc260_init_verbs? */ | ||
| 3108 | static struct hda_verb alc260_hp_init_verbs[] = { | 3110 | static struct hda_verb alc260_hp_init_verbs[] = { |
| 3109 | /* Headphone and output */ | 3111 | /* Headphone and output */ |
| 3110 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, | 3112 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0}, |
| @@ -3151,6 +3153,7 @@ static struct hda_verb alc260_hp_init_verbs[] = { | |||
| 3151 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, | 3153 | {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))}, |
| 3152 | { } | 3154 | { } |
| 3153 | }; | 3155 | }; |
| 3156 | #endif | ||
| 3154 | 3157 | ||
| 3155 | static struct hda_verb alc260_hp_3013_init_verbs[] = { | 3158 | static struct hda_verb alc260_hp_3013_init_verbs[] = { |
| 3156 | /* Line out and output */ | 3159 | /* Line out and output */ |
| @@ -3822,12 +3825,16 @@ static struct hda_board_config alc260_cfg_tbl[] = { | |||
| 3822 | { .modelname = "basic", .config = ALC260_BASIC }, | 3825 | { .modelname = "basic", .config = ALC260_BASIC }, |
| 3823 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb, | 3826 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81bb, |
| 3824 | .config = ALC260_BASIC }, /* Sony VAIO */ | 3827 | .config = ALC260_BASIC }, /* Sony VAIO */ |
| 3828 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cc, | ||
| 3829 | .config = ALC260_BASIC }, /* Sony VAIO VGN-S3HP */ | ||
| 3830 | { .pci_subvendor = 0x104d, .pci_subdevice = 0x81cd, | ||
| 3831 | .config = ALC260_BASIC }, /* Sony VAIO */ | ||
| 3825 | { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729, | 3832 | { .pci_subvendor = 0x152d, .pci_subdevice = 0x0729, |
| 3826 | .config = ALC260_BASIC }, /* CTL Travel Master U553W */ | 3833 | .config = ALC260_BASIC }, /* CTL Travel Master U553W */ |
| 3827 | { .modelname = "hp", .config = ALC260_HP }, | 3834 | { .modelname = "hp", .config = ALC260_HP }, |
| 3828 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP }, | 3835 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3010, .config = ALC260_HP }, |
| 3829 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, | 3836 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3011, .config = ALC260_HP }, |
| 3830 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP }, | 3837 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3012, .config = ALC260_HP_3013 }, |
| 3831 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, | 3838 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3013, .config = ALC260_HP_3013 }, |
| 3832 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP }, | 3839 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3014, .config = ALC260_HP }, |
| 3833 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP }, | 3840 | { .pci_subvendor = 0x103c, .pci_subdevice = 0x3015, .config = ALC260_HP }, |
| @@ -3862,7 +3869,7 @@ static struct alc_config_preset alc260_presets[] = { | |||
| 3862 | .mixers = { alc260_base_output_mixer, | 3869 | .mixers = { alc260_base_output_mixer, |
| 3863 | alc260_input_mixer, | 3870 | alc260_input_mixer, |
| 3864 | alc260_capture_alt_mixer }, | 3871 | alc260_capture_alt_mixer }, |
| 3865 | .init_verbs = { alc260_hp_init_verbs }, | 3872 | .init_verbs = { alc260_init_verbs }, |
| 3866 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), | 3873 | .num_dacs = ARRAY_SIZE(alc260_dac_nids), |
| 3867 | .dac_nids = alc260_dac_nids, | 3874 | .dac_nids = alc260_dac_nids, |
| 3868 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), | 3875 | .num_adc_nids = ARRAY_SIZE(alc260_hp_adc_nids), |
| @@ -4094,21 +4101,6 @@ static struct snd_kcontrol_new alc882_base_mixer[] = { | |||
| 4094 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | 4101 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), |
| 4095 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), | 4102 | HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT), |
| 4096 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), | 4103 | HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT), |
| 4097 | HDA_CODEC_VOLUME("Capture Volume", 0x07, 0x0, HDA_INPUT), | ||
| 4098 | HDA_CODEC_MUTE("Capture Switch", 0x07, 0x0, HDA_INPUT), | ||
| 4099 | HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x08, 0x0, HDA_INPUT), | ||
| 4100 | HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x08, 0x0, HDA_INPUT), | ||
| 4101 | HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x09, 0x0, HDA_INPUT), | ||
| 4102 | HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x09, 0x0, HDA_INPUT), | ||
| 4103 | { | ||
| 4104 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 4105 | /* .name = "Capture Source", */ | ||
| 4106 | .name = "Input Source", | ||
| 4107 | .count = 3, | ||
| 4108 | .info = alc882_mux_enum_info, | ||
| 4109 | .get = alc882_mux_enum_get, | ||
| 4110 | .put = alc882_mux_enum_put, | ||
| 4111 | }, | ||
| 4112 | { } /* end */ | 4104 | { } /* end */ |
| 4113 | }; | 4105 | }; |
| 4114 | 4106 | ||
| @@ -4342,8 +4334,6 @@ static struct alc_config_preset alc882_presets[] = { | |||
| 4342 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | 4334 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), |
| 4343 | .dac_nids = alc882_dac_nids, | 4335 | .dac_nids = alc882_dac_nids, |
| 4344 | .dig_out_nid = ALC882_DIGOUT_NID, | 4336 | .dig_out_nid = ALC882_DIGOUT_NID, |
| 4345 | .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), | ||
| 4346 | .adc_nids = alc882_adc_nids, | ||
| 4347 | .dig_in_nid = ALC882_DIGIN_NID, | 4337 | .dig_in_nid = ALC882_DIGIN_NID, |
| 4348 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), | 4338 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), |
| 4349 | .channel_mode = alc882_ch_modes, | 4339 | .channel_mode = alc882_ch_modes, |
| @@ -4355,8 +4345,6 @@ static struct alc_config_preset alc882_presets[] = { | |||
| 4355 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | 4345 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), |
| 4356 | .dac_nids = alc882_dac_nids, | 4346 | .dac_nids = alc882_dac_nids, |
| 4357 | .dig_out_nid = ALC882_DIGOUT_NID, | 4347 | .dig_out_nid = ALC882_DIGOUT_NID, |
| 4358 | .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), | ||
| 4359 | .adc_nids = alc882_adc_nids, | ||
| 4360 | .dig_in_nid = ALC882_DIGIN_NID, | 4348 | .dig_in_nid = ALC882_DIGIN_NID, |
| 4361 | .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), | 4349 | .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), |
| 4362 | .channel_mode = alc882_sixstack_modes, | 4350 | .channel_mode = alc882_sixstack_modes, |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8c440fb98603..36f199442fdc 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #define STAC_REF 0 | 41 | #define STAC_REF 0 |
| 42 | #define STAC_D945GTP3 1 | 42 | #define STAC_D945GTP3 1 |
| 43 | #define STAC_D945GTP5 2 | 43 | #define STAC_D945GTP5 2 |
| 44 | #define STAC_MACMINI 3 | ||
| 44 | 45 | ||
| 45 | struct sigmatel_spec { | 46 | struct sigmatel_spec { |
| 46 | struct snd_kcontrol_new *mixers[4]; | 47 | struct snd_kcontrol_new *mixers[4]; |
| @@ -52,6 +53,7 @@ struct sigmatel_spec { | |||
| 52 | unsigned int mic_switch: 1; | 53 | unsigned int mic_switch: 1; |
| 53 | unsigned int alt_switch: 1; | 54 | unsigned int alt_switch: 1; |
| 54 | unsigned int hp_detect: 1; | 55 | unsigned int hp_detect: 1; |
| 56 | unsigned int gpio_mute: 1; | ||
| 55 | 57 | ||
| 56 | /* playback */ | 58 | /* playback */ |
| 57 | struct hda_multi_out multiout; | 59 | struct hda_multi_out multiout; |
| @@ -293,6 +295,7 @@ static unsigned int *stac922x_brd_tbl[] = { | |||
| 293 | ref922x_pin_configs, | 295 | ref922x_pin_configs, |
| 294 | d945gtp3_pin_configs, | 296 | d945gtp3_pin_configs, |
| 295 | d945gtp5_pin_configs, | 297 | d945gtp5_pin_configs, |
| 298 | NULL, /* STAC_MACMINI */ | ||
| 296 | }; | 299 | }; |
| 297 | 300 | ||
| 298 | static struct hda_board_config stac922x_cfg_tbl[] = { | 301 | static struct hda_board_config stac922x_cfg_tbl[] = { |
| @@ -324,6 +327,9 @@ static struct hda_board_config stac922x_cfg_tbl[] = { | |||
| 324 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, | 327 | { .pci_subvendor = PCI_VENDOR_ID_INTEL, |
| 325 | .pci_subdevice = 0x0417, | 328 | .pci_subdevice = 0x0417, |
| 326 | .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */ | 329 | .config = STAC_D945GTP5 }, /* Intel D975XBK - 5 Stack */ |
| 330 | { .pci_subvendor = 0x8384, | ||
| 331 | .pci_subdevice = 0x7680, | ||
| 332 | .config = STAC_MACMINI }, /* Apple Mac Mini (early 2006) */ | ||
| 327 | {} /* terminator */ | 333 | {} /* terminator */ |
| 328 | }; | 334 | }; |
| 329 | 335 | ||
| @@ -841,6 +847,19 @@ static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const | |||
| 841 | } | 847 | } |
| 842 | } | 848 | } |
| 843 | 849 | ||
| 850 | if (imux->num_items == 1) { | ||
| 851 | /* | ||
| 852 | * Set the current input for the muxes. | ||
| 853 | * The STAC9221 has two input muxes with identical source | ||
| 854 | * NID lists. Hopefully this won't get confused. | ||
| 855 | */ | ||
| 856 | for (i = 0; i < spec->num_muxes; i++) { | ||
| 857 | snd_hda_codec_write(codec, spec->mux_nids[i], 0, | ||
| 858 | AC_VERB_SET_CONNECT_SEL, | ||
| 859 | imux->items[0].index); | ||
| 860 | } | ||
| 861 | } | ||
| 862 | |||
| 844 | return 0; | 863 | return 0; |
| 845 | } | 864 | } |
| 846 | 865 | ||
| @@ -946,6 +965,45 @@ static int stac9200_parse_auto_config(struct hda_codec *codec) | |||
| 946 | return 1; | 965 | return 1; |
| 947 | } | 966 | } |
| 948 | 967 | ||
| 968 | /* | ||
| 969 | * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a | ||
| 970 | * funky external mute control using GPIO pins. | ||
| 971 | */ | ||
| 972 | |||
| 973 | static void stac922x_gpio_mute(struct hda_codec *codec, int pin, int muted) | ||
| 974 | { | ||
| 975 | unsigned int gpiostate, gpiomask, gpiodir; | ||
| 976 | |||
| 977 | gpiostate = snd_hda_codec_read(codec, codec->afg, 0, | ||
| 978 | AC_VERB_GET_GPIO_DATA, 0); | ||
| 979 | |||
| 980 | if (!muted) | ||
| 981 | gpiostate |= (1 << pin); | ||
| 982 | else | ||
| 983 | gpiostate &= ~(1 << pin); | ||
| 984 | |||
| 985 | gpiomask = snd_hda_codec_read(codec, codec->afg, 0, | ||
| 986 | AC_VERB_GET_GPIO_MASK, 0); | ||
| 987 | gpiomask |= (1 << pin); | ||
| 988 | |||
| 989 | gpiodir = snd_hda_codec_read(codec, codec->afg, 0, | ||
| 990 | AC_VERB_GET_GPIO_DIRECTION, 0); | ||
| 991 | gpiodir |= (1 << pin); | ||
| 992 | |||
| 993 | /* AppleHDA seems to do this -- WTF is this verb?? */ | ||
| 994 | snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); | ||
| 995 | |||
| 996 | snd_hda_codec_write(codec, codec->afg, 0, | ||
| 997 | AC_VERB_SET_GPIO_MASK, gpiomask); | ||
| 998 | snd_hda_codec_write(codec, codec->afg, 0, | ||
| 999 | AC_VERB_SET_GPIO_DIRECTION, gpiodir); | ||
| 1000 | |||
| 1001 | msleep(1); | ||
| 1002 | |||
| 1003 | snd_hda_codec_write(codec, codec->afg, 0, | ||
| 1004 | AC_VERB_SET_GPIO_DATA, gpiostate); | ||
| 1005 | } | ||
| 1006 | |||
| 949 | static int stac92xx_init(struct hda_codec *codec) | 1007 | static int stac92xx_init(struct hda_codec *codec) |
| 950 | { | 1008 | { |
| 951 | struct sigmatel_spec *spec = codec->spec; | 1009 | struct sigmatel_spec *spec = codec->spec; |
| @@ -982,6 +1040,11 @@ static int stac92xx_init(struct hda_codec *codec) | |||
| 982 | stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, | 1040 | stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, |
| 983 | AC_PINCTL_IN_EN); | 1041 | AC_PINCTL_IN_EN); |
| 984 | 1042 | ||
| 1043 | if (spec->gpio_mute) { | ||
| 1044 | stac922x_gpio_mute(codec, 0, 0); | ||
| 1045 | stac922x_gpio_mute(codec, 1, 0); | ||
| 1046 | } | ||
| 1047 | |||
| 985 | return 0; | 1048 | return 0; |
| 986 | } | 1049 | } |
| 987 | 1050 | ||
| @@ -1132,7 +1195,7 @@ static int patch_stac922x(struct hda_codec *codec) | |||
| 1132 | spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl); | 1195 | spec->board_config = snd_hda_check_board_config(codec, stac922x_cfg_tbl); |
| 1133 | if (spec->board_config < 0) | 1196 | if (spec->board_config < 0) |
| 1134 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, using BIOS defaults\n"); | 1197 | snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, using BIOS defaults\n"); |
| 1135 | else { | 1198 | else if (stac922x_brd_tbl[spec->board_config] != NULL) { |
| 1136 | spec->num_pins = 10; | 1199 | spec->num_pins = 10; |
| 1137 | spec->pin_nids = stac922x_pin_nids; | 1200 | spec->pin_nids = stac922x_pin_nids; |
| 1138 | spec->pin_configs = stac922x_brd_tbl[spec->board_config]; | 1201 | spec->pin_configs = stac922x_brd_tbl[spec->board_config]; |
| @@ -1154,6 +1217,9 @@ static int patch_stac922x(struct hda_codec *codec) | |||
| 1154 | return err; | 1217 | return err; |
| 1155 | } | 1218 | } |
| 1156 | 1219 | ||
| 1220 | if (spec->board_config == STAC_MACMINI) | ||
| 1221 | spec->gpio_mute = 1; | ||
| 1222 | |||
| 1157 | codec->patch_ops = stac92xx_patch_ops; | 1223 | codec->patch_ops = stac92xx_patch_ops; |
| 1158 | 1224 | ||
| 1159 | return 0; | 1225 | return 0; |
| @@ -1262,13 +1328,13 @@ static int vaio_master_sw_put(struct snd_kcontrol *kcontrol, | |||
| 1262 | int change; | 1328 | int change; |
| 1263 | 1329 | ||
| 1264 | change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, | 1330 | change = snd_hda_codec_amp_update(codec, 0x02, 0, HDA_OUTPUT, 0, |
| 1265 | 0x80, valp[0] & 0x80); | 1331 | 0x80, (valp[0] ? 0 : 0x80)); |
| 1266 | change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, | 1332 | change |= snd_hda_codec_amp_update(codec, 0x02, 1, HDA_OUTPUT, 0, |
| 1267 | 0x80, valp[1] & 0x80); | 1333 | 0x80, (valp[1] ? 0 : 0x80)); |
| 1268 | snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, | 1334 | snd_hda_codec_amp_update(codec, 0x05, 0, HDA_OUTPUT, 0, |
| 1269 | 0x80, valp[0] & 0x80); | 1335 | 0x80, (valp[0] ? 0 : 0x80)); |
| 1270 | snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, | 1336 | snd_hda_codec_amp_update(codec, 0x05, 1, HDA_OUTPUT, 0, |
| 1271 | 0x80, valp[1] & 0x80); | 1337 | 0x80, (valp[1] ? 0 : 0x80)); |
| 1272 | return change; | 1338 | return change; |
| 1273 | } | 1339 | } |
| 1274 | 1340 | ||
| @@ -1370,6 +1436,12 @@ struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
| 1370 | { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, | 1436 | { .id = 0x83847681, .name = "STAC9220D/9223D A2", .patch = patch_stac922x }, |
| 1371 | { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, | 1437 | { .id = 0x83847682, .name = "STAC9221 A2", .patch = patch_stac922x }, |
| 1372 | { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, | 1438 | { .id = 0x83847683, .name = "STAC9221D A2", .patch = patch_stac922x }, |
| 1439 | { .id = 0x83847618, .name = "STAC9227", .patch = patch_stac922x }, | ||
| 1440 | { .id = 0x83847619, .name = "STAC9227", .patch = patch_stac922x }, | ||
| 1441 | { .id = 0x83847616, .name = "STAC9228", .patch = patch_stac922x }, | ||
| 1442 | { .id = 0x83847617, .name = "STAC9228", .patch = patch_stac922x }, | ||
| 1443 | { .id = 0x83847614, .name = "STAC9229", .patch = patch_stac922x }, | ||
| 1444 | { .id = 0x83847615, .name = "STAC9229", .patch = patch_stac922x }, | ||
| 1373 | { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x }, | 1445 | { .id = 0x83847620, .name = "STAC9274", .patch = patch_stac927x }, |
| 1374 | { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x }, | 1446 | { .id = 0x83847621, .name = "STAC9274D", .patch = patch_stac927x }, |
| 1375 | { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x }, | 1447 | { .id = 0x83847622, .name = "STAC9273X", .patch = patch_stac927x }, |
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 336dc489aee1..ca74f5b85f42 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c | |||
| @@ -1281,9 +1281,15 @@ static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable) | |||
| 1281 | 1281 | ||
| 1282 | tmp2 = tmp = snd_ice1712_gpio_read(ice); | 1282 | tmp2 = tmp = snd_ice1712_gpio_read(ice); |
| 1283 | if (enable) | 1283 | if (enable) |
| 1284 | tmp |= AUREON_HP_SEL; | 1284 | if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) |
| 1285 | tmp |= AUREON_HP_SEL; | ||
| 1286 | else | ||
| 1287 | tmp |= PRODIGY_HP_SEL; | ||
| 1285 | else | 1288 | else |
| 1286 | tmp &= ~ AUREON_HP_SEL; | 1289 | if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT) |
| 1290 | tmp &= ~ AUREON_HP_SEL; | ||
| 1291 | else | ||
| 1292 | tmp &= ~ PRODIGY_HP_SEL; | ||
| 1287 | if (tmp != tmp2) { | 1293 | if (tmp != tmp2) { |
| 1288 | snd_ice1712_gpio_write(ice, tmp); | 1294 | snd_ice1712_gpio_write(ice, tmp); |
| 1289 | return 1; | 1295 | return 1; |
| @@ -2079,16 +2085,16 @@ static unsigned char prodigy71_eeprom[] __devinitdata = { | |||
| 2079 | }; | 2085 | }; |
| 2080 | 2086 | ||
| 2081 | static unsigned char prodigy71lt_eeprom[] __devinitdata = { | 2087 | static unsigned char prodigy71lt_eeprom[] __devinitdata = { |
| 2082 | 0x0b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */ | 2088 | 0x4b, /* SYSCINF: clock 512, spdif-in/ADC, 4DACs */ |
| 2083 | 0x80, /* ACLINK: I2S */ | 2089 | 0x80, /* ACLINK: I2S */ |
| 2084 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ | 2090 | 0xfc, /* I2S: vol, 96k, 24bit, 192k */ |
| 2085 | 0xc3, /* SPDUF: out-en, out-int */ | 2091 | 0xc3, /* SPDIF: out-en, out-int, spdif-in */ |
| 2086 | 0x00, /* GPIO_DIR */ | 2092 | 0xff, /* GPIO_DIR */ |
| 2087 | 0x07, /* GPIO_DIR1 */ | 2093 | 0xff, /* GPIO_DIR1 */ |
| 2088 | 0x00, /* GPIO_DIR2 */ | 2094 | 0x5f, /* GPIO_DIR2 */ |
| 2089 | 0xff, /* GPIO_MASK */ | 2095 | 0x00, /* GPIO_MASK */ |
| 2090 | 0xf8, /* GPIO_MASK1 */ | 2096 | 0x00, /* GPIO_MASK1 */ |
| 2091 | 0xff, /* GPIO_MASK2 */ | 2097 | 0x00, /* GPIO_MASK2 */ |
| 2092 | 0x00, /* GPIO_STATE */ | 2098 | 0x00, /* GPIO_STATE */ |
| 2093 | 0x00, /* GPIO_STATE1 */ | 2099 | 0x00, /* GPIO_STATE1 */ |
| 2094 | 0x00, /* GPIO_STATE2 */ | 2100 | 0x00, /* GPIO_STATE2 */ |
diff --git a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h index 98a6752280f2..3b7bea656c57 100644 --- a/sound/pci/ice1712/aureon.h +++ b/sound/pci/ice1712/aureon.h | |||
| @@ -58,5 +58,6 @@ extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[]; | |||
| 58 | #define PRODIGY_WM_CS (1 << 8) | 58 | #define PRODIGY_WM_CS (1 << 8) |
| 59 | #define PRODIGY_SPI_MOSI (1 << 10) | 59 | #define PRODIGY_SPI_MOSI (1 << 10) |
| 60 | #define PRODIGY_SPI_CLK (1 << 9) | 60 | #define PRODIGY_SPI_CLK (1 << 9) |
| 61 | #define PRODIGY_HP_SEL (1 << 5) | ||
| 61 | 62 | ||
| 62 | #endif /* __SOUND_AUREON_H */ | 63 | #endif /* __SOUND_AUREON_H */ |
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 2c529e741384..b135389fec6c 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c | |||
| @@ -1031,6 +1031,9 @@ struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = { | |||
| 1031 | .model = "dmx6fire", | 1031 | .model = "dmx6fire", |
| 1032 | .chip_init = snd_ice1712_ews_init, | 1032 | .chip_init = snd_ice1712_ews_init, |
| 1033 | .build_controls = snd_ice1712_ews_add_controls, | 1033 | .build_controls = snd_ice1712_ews_add_controls, |
| 1034 | .mpu401_1_name = "MIDI-Front DMX6fire", | ||
| 1035 | .mpu401_2_name = "Wavetable DMX6fire", | ||
| 1036 | .mpu401_2_info_flags = MPU401_INFO_OUTPUT, | ||
| 1034 | }, | 1037 | }, |
| 1035 | { } /* terminator */ | 1038 | { } /* terminator */ |
| 1036 | }; | 1039 | }; |
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index c56793b381e2..845907159b74 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c | |||
| @@ -61,7 +61,6 @@ | |||
| 61 | #include <sound/core.h> | 61 | #include <sound/core.h> |
| 62 | #include <sound/cs8427.h> | 62 | #include <sound/cs8427.h> |
| 63 | #include <sound/info.h> | 63 | #include <sound/info.h> |
| 64 | #include <sound/mpu401.h> | ||
| 65 | #include <sound/initval.h> | 64 | #include <sound/initval.h> |
| 66 | 65 | ||
| 67 | #include <sound/asoundef.h> | 66 | #include <sound/asoundef.h> |
| @@ -1596,7 +1595,7 @@ static void __devinit snd_ice1712_proc_init(struct snd_ice1712 * ice) | |||
| 1596 | struct snd_info_entry *entry; | 1595 | struct snd_info_entry *entry; |
| 1597 | 1596 | ||
| 1598 | if (! snd_card_proc_new(ice->card, "ice1712", &entry)) | 1597 | if (! snd_card_proc_new(ice->card, "ice1712", &entry)) |
| 1599 | snd_info_set_text_ops(entry, ice, 1024, snd_ice1712_proc_read); | 1598 | snd_info_set_text_ops(entry, ice, snd_ice1712_proc_read); |
| 1600 | } | 1599 | } |
| 1601 | 1600 | ||
| 1602 | /* | 1601 | /* |
| @@ -2398,13 +2397,14 @@ static int __devinit snd_ice1712_chip_init(struct snd_ice1712 *ice) | |||
| 2398 | udelay(200); | 2397 | udelay(200); |
| 2399 | outb(ICE1712_NATIVE, ICEREG(ice, CONTROL)); | 2398 | outb(ICE1712_NATIVE, ICEREG(ice, CONTROL)); |
| 2400 | udelay(200); | 2399 | udelay(200); |
| 2401 | if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE && !ice->dxr_enable) { | 2400 | if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DMX6FIRE && |
| 2402 | /* Limit active ADCs and DACs to 6; */ | 2401 | !ice->dxr_enable) |
| 2403 | /* Note: DXR extension not supported */ | 2402 | /* Set eeprom value to limit active ADCs and DACs to 6; |
| 2404 | pci_write_config_byte(ice->pci, 0x60, 0x2a); | 2403 | * Also disable AC97 as no hardware in standard 6fire card/box |
| 2405 | } else { | 2404 | * Note: DXR extensions are not currently supported |
| 2406 | pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]); | 2405 | */ |
| 2407 | } | 2406 | ice->eeprom.data[ICE_EEP1_CODEC] = 0x3a; |
| 2407 | pci_write_config_byte(ice->pci, 0x60, ice->eeprom.data[ICE_EEP1_CODEC]); | ||
| 2408 | pci_write_config_byte(ice->pci, 0x61, ice->eeprom.data[ICE_EEP1_ACLINK]); | 2408 | pci_write_config_byte(ice->pci, 0x61, ice->eeprom.data[ICE_EEP1_ACLINK]); |
| 2409 | pci_write_config_byte(ice->pci, 0x62, ice->eeprom.data[ICE_EEP1_I2SID]); | 2409 | pci_write_config_byte(ice->pci, 0x62, ice->eeprom.data[ICE_EEP1_I2SID]); |
| 2410 | pci_write_config_byte(ice->pci, 0x63, ice->eeprom.data[ICE_EEP1_SPDIF]); | 2410 | pci_write_config_byte(ice->pci, 0x63, ice->eeprom.data[ICE_EEP1_SPDIF]); |
| @@ -2737,21 +2737,38 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, | |||
| 2737 | 2737 | ||
| 2738 | if (! c->no_mpu401) { | 2738 | if (! c->no_mpu401) { |
| 2739 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, | 2739 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, |
| 2740 | ICEREG(ice, MPU1_CTRL), 1, | 2740 | ICEREG(ice, MPU1_CTRL), |
| 2741 | (c->mpu401_1_info_flags | | ||
| 2742 | MPU401_INFO_INTEGRATED), | ||
| 2741 | ice->irq, 0, | 2743 | ice->irq, 0, |
| 2742 | &ice->rmidi[0])) < 0) { | 2744 | &ice->rmidi[0])) < 0) { |
| 2743 | snd_card_free(card); | 2745 | snd_card_free(card); |
| 2744 | return err; | 2746 | return err; |
| 2745 | } | 2747 | } |
| 2746 | 2748 | if (c->mpu401_1_name) | |
| 2747 | if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) | 2749 | /* Prefered name available in card_info */ |
| 2750 | snprintf(ice->rmidi[0]->name, | ||
| 2751 | sizeof(ice->rmidi[0]->name), | ||
| 2752 | "%s %d", c->mpu401_1_name, card->number); | ||
| 2753 | |||
| 2754 | if (ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) { | ||
| 2755 | /* 2nd port used */ | ||
| 2748 | if ((err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712, | 2756 | if ((err = snd_mpu401_uart_new(card, 1, MPU401_HW_ICE1712, |
| 2749 | ICEREG(ice, MPU2_CTRL), 1, | 2757 | ICEREG(ice, MPU2_CTRL), |
| 2758 | (c->mpu401_2_info_flags | | ||
| 2759 | MPU401_INFO_INTEGRATED), | ||
| 2750 | ice->irq, 0, | 2760 | ice->irq, 0, |
| 2751 | &ice->rmidi[1])) < 0) { | 2761 | &ice->rmidi[1])) < 0) { |
| 2752 | snd_card_free(card); | 2762 | snd_card_free(card); |
| 2753 | return err; | 2763 | return err; |
| 2754 | } | 2764 | } |
| 2765 | if (c->mpu401_2_name) | ||
| 2766 | /* Prefered name available in card_info */ | ||
| 2767 | snprintf(ice->rmidi[1]->name, | ||
| 2768 | sizeof(ice->rmidi[1]->name), | ||
| 2769 | "%s %d", c->mpu401_2_name, | ||
| 2770 | card->number); | ||
| 2771 | } | ||
| 2755 | } | 2772 | } |
| 2756 | 2773 | ||
| 2757 | snd_ice1712_set_input_clock_source(ice, 0); | 2774 | snd_ice1712_set_input_clock_source(ice, 0); |
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 053f8e56fd68..ce27eac40d4e 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <sound/ak4xxx-adda.h> | 29 | #include <sound/ak4xxx-adda.h> |
| 30 | #include <sound/ak4114.h> | 30 | #include <sound/ak4114.h> |
| 31 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
| 32 | #include <sound/mpu401.h> | ||
| 32 | 33 | ||
| 33 | 34 | ||
| 34 | /* | 35 | /* |
| @@ -495,6 +496,10 @@ struct snd_ice1712_card_info { | |||
| 495 | int (*chip_init)(struct snd_ice1712 *); | 496 | int (*chip_init)(struct snd_ice1712 *); |
| 496 | int (*build_controls)(struct snd_ice1712 *); | 497 | int (*build_controls)(struct snd_ice1712 *); |
| 497 | unsigned int no_mpu401: 1; | 498 | unsigned int no_mpu401: 1; |
| 499 | unsigned int mpu401_1_info_flags; | ||
| 500 | unsigned int mpu401_2_info_flags; | ||
| 501 | const char *mpu401_1_name; | ||
| 502 | const char *mpu401_2_name; | ||
| 498 | unsigned int eeprom_size; | 503 | unsigned int eeprom_size; |
| 499 | unsigned char *eeprom_data; | 504 | unsigned char *eeprom_data; |
| 500 | }; | 505 | }; |
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index b1c007e022d2..34a58c629f47 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
| @@ -1293,7 +1293,7 @@ static void __devinit snd_vt1724_proc_init(struct snd_ice1712 * ice) | |||
| 1293 | struct snd_info_entry *entry; | 1293 | struct snd_info_entry *entry; |
| 1294 | 1294 | ||
| 1295 | if (! snd_card_proc_new(ice->card, "ice1724", &entry)) | 1295 | if (! snd_card_proc_new(ice->card, "ice1724", &entry)) |
| 1296 | snd_info_set_text_ops(entry, ice, 1024, snd_vt1724_proc_read); | 1296 | snd_info_set_text_ops(entry, ice, snd_vt1724_proc_read); |
| 1297 | } | 1297 | } |
| 1298 | 1298 | ||
| 1299 | /* | 1299 | /* |
| @@ -2388,7 +2388,8 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, | |||
| 2388 | if (! c->no_mpu401) { | 2388 | if (! c->no_mpu401) { |
| 2389 | if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { | 2389 | if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { |
| 2390 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, | 2390 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, |
| 2391 | ICEREG1724(ice, MPU_CTRL), 1, | 2391 | ICEREG1724(ice, MPU_CTRL), |
| 2392 | MPU401_INFO_INTEGRATED, | ||
| 2392 | ice->irq, 0, | 2393 | ice->irq, 0, |
| 2393 | &ice->rmidi[0])) < 0) { | 2394 | &ice->rmidi[0])) < 0) { |
| 2394 | snd_card_free(card); | 2395 | snd_card_free(card); |
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index d23fb3fc2133..0efcad9260a5 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c | |||
| @@ -680,9 +680,8 @@ static void wm_proc_init(struct snd_ice1712 *ice) | |||
| 680 | { | 680 | { |
| 681 | struct snd_info_entry *entry; | 681 | struct snd_info_entry *entry; |
| 682 | if (! snd_card_proc_new(ice->card, "wm_codec", &entry)) { | 682 | if (! snd_card_proc_new(ice->card, "wm_codec", &entry)) { |
| 683 | snd_info_set_text_ops(entry, ice, 1024, wm_proc_regs_read); | 683 | snd_info_set_text_ops(entry, ice, wm_proc_regs_read); |
| 684 | entry->mode |= S_IWUSR; | 684 | entry->mode |= S_IWUSR; |
| 685 | entry->c.text.write_size = 1024; | ||
| 686 | entry->c.text.write = wm_proc_regs_write; | 685 | entry->c.text.write = wm_proc_regs_write; |
| 687 | } | 686 | } |
| 688 | } | 687 | } |
| @@ -705,9 +704,8 @@ static void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buff | |||
| 705 | static void cs_proc_init(struct snd_ice1712 *ice) | 704 | static void cs_proc_init(struct snd_ice1712 *ice) |
| 706 | { | 705 | { |
| 707 | struct snd_info_entry *entry; | 706 | struct snd_info_entry *entry; |
| 708 | if (! snd_card_proc_new(ice->card, "cs_codec", &entry)) { | 707 | if (! snd_card_proc_new(ice->card, "cs_codec", &entry)) |
| 709 | snd_info_set_text_ops(entry, ice, 1024, cs_proc_regs_read); | 708 | snd_info_set_text_ops(entry, ice, cs_proc_regs_read); |
| 710 | } | ||
| 711 | } | 709 | } |
| 712 | 710 | ||
| 713 | 711 | ||
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 0df7602568e2..edc14475ef82 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
| @@ -66,7 +66,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," | |||
| 66 | 66 | ||
| 67 | static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ | 67 | static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ |
| 68 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | 68 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ |
| 69 | static int ac97_clock = 0; | 69 | static int ac97_clock; |
| 70 | static char *ac97_quirk; | 70 | static char *ac97_quirk; |
| 71 | static int buggy_semaphore; | 71 | static int buggy_semaphore; |
| 72 | static int buggy_irq = -1; /* auto-check */ | 72 | static int buggy_irq = -1; /* auto-check */ |
| @@ -1807,6 +1807,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { | |||
| 1807 | }, | 1807 | }, |
| 1808 | { | 1808 | { |
| 1809 | .subvendor = 0x1028, | 1809 | .subvendor = 0x1028, |
| 1810 | .subdevice = 0x014e, | ||
| 1811 | .name = "Dell D800", /* STAC9750/51 */ | ||
| 1812 | .type = AC97_TUNE_HP_ONLY | ||
| 1813 | }, | ||
| 1814 | { | ||
| 1815 | .subvendor = 0x1028, | ||
| 1810 | .subdevice = 0x0163, | 1816 | .subdevice = 0x0163, |
| 1811 | .name = "Dell Unknown", /* STAC9750/51 */ | 1817 | .name = "Dell Unknown", /* STAC9750/51 */ |
| 1812 | .type = AC97_TUNE_HP_ONLY | 1818 | .type = AC97_TUNE_HP_ONLY |
| @@ -2645,7 +2651,7 @@ static void __devinit snd_intel8x0_proc_init(struct intel8x0 * chip) | |||
| 2645 | struct snd_info_entry *entry; | 2651 | struct snd_info_entry *entry; |
| 2646 | 2652 | ||
| 2647 | if (! snd_card_proc_new(chip->card, "intel8x0", &entry)) | 2653 | if (! snd_card_proc_new(chip->card, "intel8x0", &entry)) |
| 2648 | snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0_proc_read); | 2654 | snd_info_set_text_ops(entry, chip, snd_intel8x0_proc_read); |
| 2649 | } | 2655 | } |
| 2650 | #else | 2656 | #else |
| 2651 | #define snd_intel8x0_proc_init(x) | 2657 | #define snd_intel8x0_proc_init(x) |
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 720635f0cb81..24703d75b65a 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c | |||
| @@ -59,7 +59,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," | |||
| 59 | 59 | ||
| 60 | static int index = -2; /* Exclude the first card */ | 60 | static int index = -2; /* Exclude the first card */ |
| 61 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | 61 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ |
| 62 | static int ac97_clock = 0; | 62 | static int ac97_clock; |
| 63 | 63 | ||
| 64 | module_param(index, int, 0444); | 64 | module_param(index, int, 0444); |
| 65 | MODULE_PARM_DESC(index, "Index value for Intel i8x0 modemcard."); | 65 | MODULE_PARM_DESC(index, "Index value for Intel i8x0 modemcard."); |
| @@ -1092,7 +1092,7 @@ static void __devinit snd_intel8x0m_proc_init(struct intel8x0m * chip) | |||
| 1092 | struct snd_info_entry *entry; | 1092 | struct snd_info_entry *entry; |
| 1093 | 1093 | ||
| 1094 | if (! snd_card_proc_new(chip->card, "intel8x0m", &entry)) | 1094 | if (! snd_card_proc_new(chip->card, "intel8x0m", &entry)) |
| 1095 | snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0m_proc_read); | 1095 | snd_info_set_text_ops(entry, chip, snd_intel8x0m_proc_read); |
| 1096 | } | 1096 | } |
| 1097 | #else /* !CONFIG_PROC_FS */ | 1097 | #else /* !CONFIG_PROC_FS */ |
| 1098 | #define snd_intel8x0m_proc_init(chip) | 1098 | #define snd_intel8x0m_proc_init(chip) |
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index e39fad1a4200..6e97932de34f 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c | |||
| @@ -2085,7 +2085,7 @@ static void __devinit snd_korg1212_proc_init(struct snd_korg1212 *korg1212) | |||
| 2085 | struct snd_info_entry *entry; | 2085 | struct snd_info_entry *entry; |
| 2086 | 2086 | ||
| 2087 | if (! snd_card_proc_new(korg1212->card, "korg1212", &entry)) | 2087 | if (! snd_card_proc_new(korg1212->card, "korg1212", &entry)) |
| 2088 | snd_info_set_text_ops(entry, korg1212, 1024, snd_korg1212_proc_read); | 2088 | snd_info_set_text_ops(entry, korg1212, snd_korg1212_proc_read); |
| 2089 | } | 2089 | } |
| 2090 | 2090 | ||
| 2091 | static int | 2091 | static int |
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 1928e06b6d82..1c344fbd964d 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
| @@ -2861,7 +2861,8 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 2861 | #if 0 /* TODO: not supported yet */ | 2861 | #if 0 /* TODO: not supported yet */ |
| 2862 | /* TODO enable MIDI IRQ and I/O */ | 2862 | /* TODO enable MIDI IRQ and I/O */ |
| 2863 | err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401, | 2863 | err = snd_mpu401_uart_new(chip->card, 0, MPU401_HW_MPU401, |
| 2864 | chip->iobase + MPU401_DATA_PORT, 1, | 2864 | chip->iobase + MPU401_DATA_PORT, |
| 2865 | MPU401_INFO_INTEGRATED, | ||
| 2865 | chip->irq, 0, &chip->rmidi); | 2866 | chip->irq, 0, &chip->rmidi); |
| 2866 | if (err < 0) | 2867 | if (err < 0) |
| 2867 | printk(KERN_WARNING "maestro3: no MIDI support.\n"); | 2868 | printk(KERN_WARNING "maestro3: no MIDI support.\n"); |
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 09cc0786495a..366c4a7e65c6 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c | |||
| @@ -1244,7 +1244,6 @@ static void __devinit snd_mixart_proc_init(struct snd_mixart *chip) | |||
| 1244 | /* text interface to read perf and temp meters */ | 1244 | /* text interface to read perf and temp meters */ |
| 1245 | if (! snd_card_proc_new(chip->card, "board_info", &entry)) { | 1245 | if (! snd_card_proc_new(chip->card, "board_info", &entry)) { |
| 1246 | entry->private_data = chip; | 1246 | entry->private_data = chip; |
| 1247 | entry->c.text.read_size = 1024; | ||
| 1248 | entry->c.text.read = snd_mixart_proc_read; | 1247 | entry->c.text.read = snd_mixart_proc_read; |
| 1249 | } | 1248 | } |
| 1250 | 1249 | ||
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index dafa2235abaa..8198884b51ee 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c | |||
| @@ -1150,9 +1150,9 @@ static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip) | |||
| 1150 | struct snd_info_entry *entry; | 1150 | struct snd_info_entry *entry; |
| 1151 | 1151 | ||
| 1152 | if (! snd_card_proc_new(chip->card, "info", &entry)) | 1152 | if (! snd_card_proc_new(chip->card, "info", &entry)) |
| 1153 | snd_info_set_text_ops(entry, chip, 1024, pcxhr_proc_info); | 1153 | snd_info_set_text_ops(entry, chip, pcxhr_proc_info); |
| 1154 | if (! snd_card_proc_new(chip->card, "sync", &entry)) | 1154 | if (! snd_card_proc_new(chip->card, "sync", &entry)) |
| 1155 | snd_info_set_text_ops(entry, chip, 1024, pcxhr_proc_sync); | 1155 | snd_info_set_text_ops(entry, chip, pcxhr_proc_sync); |
| 1156 | } | 1156 | } |
| 1157 | /* end of proc interface */ | 1157 | /* end of proc interface */ |
| 1158 | 1158 | ||
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index d8cc985d7241..5618ec9740bd 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c | |||
| @@ -1836,11 +1836,11 @@ static int snd_riptide_free(struct snd_riptide *chip) | |||
| 1836 | UNSET_GRESET(cif->hwport); | 1836 | UNSET_GRESET(cif->hwport); |
| 1837 | kfree(chip->cif); | 1837 | kfree(chip->cif); |
| 1838 | } | 1838 | } |
| 1839 | if (chip->irq >= 0) | ||
| 1840 | free_irq(chip->irq, chip); | ||
| 1839 | if (chip->fw_entry) | 1841 | if (chip->fw_entry) |
| 1840 | release_firmware(chip->fw_entry); | 1842 | release_firmware(chip->fw_entry); |
| 1841 | release_and_free_resource(chip->res_port); | 1843 | release_and_free_resource(chip->res_port); |
| 1842 | if (chip->irq >= 0) | ||
| 1843 | free_irq(chip->irq, chip); | ||
| 1844 | kfree(chip); | 1844 | kfree(chip); |
| 1845 | return 0; | 1845 | return 0; |
| 1846 | } | 1846 | } |
| @@ -1992,7 +1992,7 @@ static void __devinit snd_riptide_proc_init(struct snd_riptide *chip) | |||
| 1992 | struct snd_info_entry *entry; | 1992 | struct snd_info_entry *entry; |
| 1993 | 1993 | ||
| 1994 | if (!snd_card_proc_new(chip->card, "riptide", &entry)) | 1994 | if (!snd_card_proc_new(chip->card, "riptide", &entry)) |
| 1995 | snd_info_set_text_ops(entry, chip, 4096, snd_riptide_proc_read); | 1995 | snd_info_set_text_ops(entry, chip, snd_riptide_proc_read); |
| 1996 | } | 1996 | } |
| 1997 | 1997 | ||
| 1998 | static int __devinit snd_riptide_mixer(struct snd_riptide *chip) | 1998 | static int __devinit snd_riptide_mixer(struct snd_riptide *chip) |
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 55b1d4838d97..2cb9fe98db2f 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c | |||
| @@ -1368,18 +1368,18 @@ static int __devinit snd_rme32_create(struct rme32 * rme32) | |||
| 1368 | return err; | 1368 | return err; |
| 1369 | rme32->port = pci_resource_start(rme32->pci, 0); | 1369 | rme32->port = pci_resource_start(rme32->pci, 0); |
| 1370 | 1370 | ||
| 1371 | if (request_irq(pci->irq, snd_rme32_interrupt, SA_INTERRUPT | SA_SHIRQ, "RME32", (void *) rme32)) { | ||
| 1372 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); | ||
| 1373 | return -EBUSY; | ||
| 1374 | } | ||
| 1375 | rme32->irq = pci->irq; | ||
| 1376 | |||
| 1377 | if ((rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE)) == 0) { | 1371 | if ((rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE)) == 0) { |
| 1378 | snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", | 1372 | snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", |
| 1379 | rme32->port, rme32->port + RME32_IO_SIZE - 1); | 1373 | rme32->port, rme32->port + RME32_IO_SIZE - 1); |
| 1380 | return -ENOMEM; | 1374 | return -ENOMEM; |
| 1381 | } | 1375 | } |
| 1382 | 1376 | ||
| 1377 | if (request_irq(pci->irq, snd_rme32_interrupt, SA_INTERRUPT | SA_SHIRQ, "RME32", (void *) rme32)) { | ||
| 1378 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); | ||
| 1379 | return -EBUSY; | ||
| 1380 | } | ||
| 1381 | rme32->irq = pci->irq; | ||
| 1382 | |||
| 1383 | /* read the card's revision number */ | 1383 | /* read the card's revision number */ |
| 1384 | pci_read_config_byte(pci, 8, &rme32->rev); | 1384 | pci_read_config_byte(pci, 8, &rme32->rev); |
| 1385 | 1385 | ||
| @@ -1578,7 +1578,7 @@ static void __devinit snd_rme32_proc_init(struct rme32 * rme32) | |||
| 1578 | struct snd_info_entry *entry; | 1578 | struct snd_info_entry *entry; |
| 1579 | 1579 | ||
| 1580 | if (! snd_card_proc_new(rme32->card, "rme32", &entry)) | 1580 | if (! snd_card_proc_new(rme32->card, "rme32", &entry)) |
| 1581 | snd_info_set_text_ops(entry, rme32, 1024, snd_rme32_proc_read); | 1581 | snd_info_set_text_ops(entry, rme32, snd_rme32_proc_read); |
| 1582 | } | 1582 | } |
| 1583 | 1583 | ||
| 1584 | /* | 1584 | /* |
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 3c1bc533d511..991cb18c14f3 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
| @@ -1151,6 +1151,25 @@ static struct snd_pcm_hw_constraint_list hw_constraints_period_bytes = { | |||
| 1151 | .mask = 0 | 1151 | .mask = 0 |
| 1152 | }; | 1152 | }; |
| 1153 | 1153 | ||
| 1154 | static void | ||
| 1155 | rme96_set_buffer_size_constraint(struct rme96 *rme96, | ||
| 1156 | struct snd_pcm_runtime *runtime) | ||
| 1157 | { | ||
| 1158 | unsigned int size; | ||
| 1159 | |||
| 1160 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | ||
| 1161 | RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); | ||
| 1162 | if ((size = rme96->playback_periodsize) != 0 || | ||
| 1163 | (size = rme96->capture_periodsize) != 0) | ||
| 1164 | snd_pcm_hw_constraint_minmax(runtime, | ||
| 1165 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
| 1166 | size, size); | ||
| 1167 | else | ||
| 1168 | snd_pcm_hw_constraint_list(runtime, 0, | ||
| 1169 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
| 1170 | &hw_constraints_period_bytes); | ||
| 1171 | } | ||
| 1172 | |||
| 1154 | static int | 1173 | static int |
| 1155 | snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream) | 1174 | snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream) |
| 1156 | { | 1175 | { |
| @@ -1180,8 +1199,7 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream) | |||
| 1180 | runtime->hw.rate_min = rate; | 1199 | runtime->hw.rate_min = rate; |
| 1181 | runtime->hw.rate_max = rate; | 1200 | runtime->hw.rate_max = rate; |
| 1182 | } | 1201 | } |
| 1183 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); | 1202 | rme96_set_buffer_size_constraint(rme96, runtime); |
| 1184 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes); | ||
| 1185 | 1203 | ||
| 1186 | rme96->wcreg_spdif_stream = rme96->wcreg_spdif; | 1204 | rme96->wcreg_spdif_stream = rme96->wcreg_spdif; |
| 1187 | rme96->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | 1205 | rme96->spdif_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; |
| @@ -1219,9 +1237,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream) | |||
| 1219 | rme96->capture_substream = substream; | 1237 | rme96->capture_substream = substream; |
| 1220 | spin_unlock_irq(&rme96->lock); | 1238 | spin_unlock_irq(&rme96->lock); |
| 1221 | 1239 | ||
| 1222 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); | 1240 | rme96_set_buffer_size_constraint(rme96, runtime); |
| 1223 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes); | ||
| 1224 | |||
| 1225 | return 0; | 1241 | return 0; |
| 1226 | } | 1242 | } |
| 1227 | 1243 | ||
| @@ -1254,8 +1270,7 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream) | |||
| 1254 | runtime->hw.rate_min = rate; | 1270 | runtime->hw.rate_min = rate; |
| 1255 | runtime->hw.rate_max = rate; | 1271 | runtime->hw.rate_max = rate; |
| 1256 | } | 1272 | } |
| 1257 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); | 1273 | rme96_set_buffer_size_constraint(rme96, runtime); |
| 1258 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes); | ||
| 1259 | return 0; | 1274 | return 0; |
| 1260 | } | 1275 | } |
| 1261 | 1276 | ||
| @@ -1291,8 +1306,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream) | |||
| 1291 | rme96->capture_substream = substream; | 1306 | rme96->capture_substream = substream; |
| 1292 | spin_unlock_irq(&rme96->lock); | 1307 | spin_unlock_irq(&rme96->lock); |
| 1293 | 1308 | ||
| 1294 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE); | 1309 | rme96_set_buffer_size_constraint(rme96, runtime); |
| 1295 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_period_bytes); | ||
| 1296 | return 0; | 1310 | return 0; |
| 1297 | } | 1311 | } |
| 1298 | 1312 | ||
| @@ -1569,17 +1583,17 @@ snd_rme96_create(struct rme96 *rme96) | |||
| 1569 | return err; | 1583 | return err; |
| 1570 | rme96->port = pci_resource_start(rme96->pci, 0); | 1584 | rme96->port = pci_resource_start(rme96->pci, 0); |
| 1571 | 1585 | ||
| 1586 | if ((rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE)) == 0) { | ||
| 1587 | snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1); | ||
| 1588 | return -ENOMEM; | ||
| 1589 | } | ||
| 1590 | |||
| 1572 | if (request_irq(pci->irq, snd_rme96_interrupt, SA_INTERRUPT|SA_SHIRQ, "RME96", (void *)rme96)) { | 1591 | if (request_irq(pci->irq, snd_rme96_interrupt, SA_INTERRUPT|SA_SHIRQ, "RME96", (void *)rme96)) { |
| 1573 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); | 1592 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); |
| 1574 | return -EBUSY; | 1593 | return -EBUSY; |
| 1575 | } | 1594 | } |
| 1576 | rme96->irq = pci->irq; | 1595 | rme96->irq = pci->irq; |
| 1577 | 1596 | ||
| 1578 | if ((rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE)) == 0) { | ||
| 1579 | snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1); | ||
| 1580 | return -ENOMEM; | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | /* read the card's revision number */ | 1597 | /* read the card's revision number */ |
| 1584 | pci_read_config_byte(pci, 8, &rme96->rev); | 1598 | pci_read_config_byte(pci, 8, &rme96->rev); |
| 1585 | 1599 | ||
| @@ -1805,7 +1819,7 @@ snd_rme96_proc_init(struct rme96 *rme96) | |||
| 1805 | struct snd_info_entry *entry; | 1819 | struct snd_info_entry *entry; |
| 1806 | 1820 | ||
| 1807 | if (! snd_card_proc_new(rme96->card, "rme96", &entry)) | 1821 | if (! snd_card_proc_new(rme96->card, "rme96", &entry)) |
| 1808 | snd_info_set_text_ops(entry, rme96, 1024, snd_rme96_proc_read); | 1822 | snd_info_set_text_ops(entry, rme96, snd_rme96_proc_read); |
| 1809 | } | 1823 | } |
| 1810 | 1824 | ||
| 1811 | /* | 1825 | /* |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 61f82f0d5cc6..eaf3c22449ad 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
| @@ -389,7 +389,7 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP}," | |||
| 389 | 389 | ||
| 390 | /* use hotplug firmeare loader? */ | 390 | /* use hotplug firmeare loader? */ |
| 391 | #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) | 391 | #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) |
| 392 | #ifndef HDSP_USE_HWDEP_LOADER | 392 | #if !defined(HDSP_USE_HWDEP_LOADER) && !defined(CONFIG_SND_HDSP) |
| 393 | #define HDSP_FW_LOADER | 393 | #define HDSP_FW_LOADER |
| 394 | #endif | 394 | #endif |
| 395 | #endif | 395 | #endif |
| @@ -3169,9 +3169,10 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) | |||
| 3169 | char *clock_source; | 3169 | char *clock_source; |
| 3170 | int x; | 3170 | int x; |
| 3171 | 3171 | ||
| 3172 | if (hdsp_check_for_iobox (hdsp)) | 3172 | if (hdsp_check_for_iobox (hdsp)) { |
| 3173 | snd_iprintf(buffer, "No I/O box connected.\nPlease connect one and upload firmware.\n"); | 3173 | snd_iprintf(buffer, "No I/O box connected.\nPlease connect one and upload firmware.\n"); |
| 3174 | return; | 3174 | return; |
| 3175 | } | ||
| 3175 | 3176 | ||
| 3176 | if (hdsp_check_for_firmware(hdsp, 0)) { | 3177 | if (hdsp_check_for_firmware(hdsp, 0)) { |
| 3177 | if (hdsp->state & HDSP_FirmwareCached) { | 3178 | if (hdsp->state & HDSP_FirmwareCached) { |
| @@ -3470,7 +3471,7 @@ static void __devinit snd_hdsp_proc_init(struct hdsp *hdsp) | |||
| 3470 | struct snd_info_entry *entry; | 3471 | struct snd_info_entry *entry; |
| 3471 | 3472 | ||
| 3472 | if (! snd_card_proc_new(hdsp->card, "hdsp", &entry)) | 3473 | if (! snd_card_proc_new(hdsp->card, "hdsp", &entry)) |
| 3473 | snd_info_set_text_ops(entry, hdsp, 1024, snd_hdsp_proc_read); | 3474 | snd_info_set_text_ops(entry, hdsp, snd_hdsp_proc_read); |
| 3474 | } | 3475 | } |
| 3475 | 3476 | ||
| 3476 | static void snd_hdsp_free_buffers(struct hdsp *hdsp) | 3477 | static void snd_hdsp_free_buffers(struct hdsp *hdsp) |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 722b9e6ce54a..bba1615504d3 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c | |||
| @@ -2489,7 +2489,7 @@ static void __devinit snd_hdspm_proc_init(struct hdspm * hdspm) | |||
| 2489 | struct snd_info_entry *entry; | 2489 | struct snd_info_entry *entry; |
| 2490 | 2490 | ||
| 2491 | if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) | 2491 | if (!snd_card_proc_new(hdspm->card, "hdspm", &entry)) |
| 2492 | snd_info_set_text_ops(entry, hdspm, 1024, | 2492 | snd_info_set_text_ops(entry, hdspm, |
| 2493 | snd_hdspm_proc_read); | 2493 | snd_hdspm_proc_read); |
| 2494 | } | 2494 | } |
| 2495 | 2495 | ||
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 75d6406303d3..3b945e8c1b15 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c | |||
| @@ -41,7 +41,7 @@ | |||
| 41 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 41 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
| 42 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 42 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
| 43 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ | 43 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ |
| 44 | static int precise_ptr[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 0 }; /* Enable precise pointer */ | 44 | static int precise_ptr[SNDRV_CARDS]; /* Enable precise pointer */ |
| 45 | 45 | ||
| 46 | module_param_array(index, int, NULL, 0444); | 46 | module_param_array(index, int, NULL, 0444); |
| 47 | MODULE_PARM_DESC(index, "Index value for RME Digi9652 (Hammerfall) soundcard."); | 47 | MODULE_PARM_DESC(index, "Index value for RME Digi9652 (Hammerfall) soundcard."); |
| @@ -1787,7 +1787,7 @@ static void __devinit snd_rme9652_proc_init(struct snd_rme9652 *rme9652) | |||
| 1787 | struct snd_info_entry *entry; | 1787 | struct snd_info_entry *entry; |
| 1788 | 1788 | ||
| 1789 | if (! snd_card_proc_new(rme9652->card, "rme9652", &entry)) | 1789 | if (! snd_card_proc_new(rme9652->card, "rme9652", &entry)) |
| 1790 | snd_info_set_text_ops(entry, rme9652, 1024, snd_rme9652_proc_read); | 1790 | snd_info_set_text_ops(entry, rme9652, snd_rme9652_proc_read); |
| 1791 | } | 1791 | } |
| 1792 | 1792 | ||
| 1793 | static void snd_rme9652_free_buffers(struct snd_rme9652 *rme9652) | 1793 | static void snd_rme9652_free_buffers(struct snd_rme9652 *rme9652) |
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 91f8bf3ae9fa..dcf402948347 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c | |||
| @@ -54,8 +54,8 @@ MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}"); | |||
| 54 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 54 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
| 55 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 55 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
| 56 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ | 56 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ |
| 57 | static int reverb[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 57 | static int reverb[SNDRV_CARDS]; |
| 58 | static int mge[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | 58 | static int mge[SNDRV_CARDS]; |
| 59 | static unsigned int dmaio = 0x7a00; /* DDMA i/o address */ | 59 | static unsigned int dmaio = 0x7a00; /* DDMA i/o address */ |
| 60 | 60 | ||
| 61 | module_param_array(index, int, NULL, 0444); | 61 | module_param_array(index, int, NULL, 0444); |
| @@ -1144,7 +1144,7 @@ static void __devinit snd_sonicvibes_proc_init(struct sonicvibes * sonic) | |||
| 1144 | struct snd_info_entry *entry; | 1144 | struct snd_info_entry *entry; |
| 1145 | 1145 | ||
| 1146 | if (! snd_card_proc_new(sonic->card, "sonicvibes", &entry)) | 1146 | if (! snd_card_proc_new(sonic->card, "sonicvibes", &entry)) |
| 1147 | snd_info_set_text_ops(entry, sonic, 1024, snd_sonicvibes_proc_read); | 1147 | snd_info_set_text_ops(entry, sonic, snd_sonicvibes_proc_read); |
| 1148 | } | 1148 | } |
| 1149 | 1149 | ||
| 1150 | /* | 1150 | /* |
| @@ -1456,7 +1456,7 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci, | |||
| 1456 | return err; | 1456 | return err; |
| 1457 | } | 1457 | } |
| 1458 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES, | 1458 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES, |
| 1459 | sonic->midi_port, 1, | 1459 | sonic->midi_port, MPU401_INFO_INTEGRATED, |
| 1460 | sonic->irq, 0, | 1460 | sonic->irq, 0, |
| 1461 | &midi_uart)) < 0) { | 1461 | &midi_uart)) < 0) { |
| 1462 | snd_card_free(card); | 1462 | snd_card_free(card); |
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 9624a5f2b875..5629b7eba96d 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c | |||
| @@ -148,7 +148,8 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, | |||
| 148 | } | 148 | } |
| 149 | if (trident->device != TRIDENT_DEVICE_ID_SI7018 && | 149 | if (trident->device != TRIDENT_DEVICE_ID_SI7018 && |
| 150 | (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, | 150 | (err = snd_mpu401_uart_new(card, 0, MPU401_HW_TRID4DWAVE, |
| 151 | trident->midi_port, 1, | 151 | trident->midi_port, |
| 152 | MPU401_INFO_INTEGRATED, | ||
| 152 | trident->irq, 0, &trident->rmidi)) < 0) { | 153 | trident->irq, 0, &trident->rmidi)) < 0) { |
| 153 | snd_card_free(card); | 154 | snd_card_free(card); |
| 154 | return err; | 155 | return err; |
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 52178b8ad49d..d99ed7237750 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c | |||
| @@ -306,6 +306,8 @@ void snd_trident_start_voice(struct snd_trident * trident, unsigned int voice) | |||
| 306 | outl(mask, TRID_REG(trident, reg)); | 306 | outl(mask, TRID_REG(trident, reg)); |
| 307 | } | 307 | } |
| 308 | 308 | ||
| 309 | EXPORT_SYMBOL(snd_trident_start_voice); | ||
| 310 | |||
| 309 | /*--------------------------------------------------------------------------- | 311 | /*--------------------------------------------------------------------------- |
| 310 | void snd_trident_stop_voice(struct snd_trident * trident, unsigned int voice) | 312 | void snd_trident_stop_voice(struct snd_trident * trident, unsigned int voice) |
| 311 | 313 | ||
| @@ -328,6 +330,8 @@ void snd_trident_stop_voice(struct snd_trident * trident, unsigned int voice) | |||
| 328 | outl(mask, TRID_REG(trident, reg)); | 330 | outl(mask, TRID_REG(trident, reg)); |
| 329 | } | 331 | } |
| 330 | 332 | ||
| 333 | EXPORT_SYMBOL(snd_trident_stop_voice); | ||
| 334 | |||
| 331 | /*--------------------------------------------------------------------------- | 335 | /*--------------------------------------------------------------------------- |
| 332 | int snd_trident_allocate_pcm_channel(struct snd_trident *trident) | 336 | int snd_trident_allocate_pcm_channel(struct snd_trident *trident) |
| 333 | 337 | ||
| @@ -502,6 +506,8 @@ void snd_trident_write_voice_regs(struct snd_trident * trident, | |||
| 502 | #endif | 506 | #endif |
| 503 | } | 507 | } |
| 504 | 508 | ||
| 509 | EXPORT_SYMBOL(snd_trident_write_voice_regs); | ||
| 510 | |||
| 505 | /*--------------------------------------------------------------------------- | 511 | /*--------------------------------------------------------------------------- |
| 506 | snd_trident_write_cso_reg | 512 | snd_trident_write_cso_reg |
| 507 | 513 | ||
| @@ -3332,7 +3338,7 @@ static void __devinit snd_trident_proc_init(struct snd_trident * trident) | |||
| 3332 | if (trident->device == TRIDENT_DEVICE_ID_SI7018) | 3338 | if (trident->device == TRIDENT_DEVICE_ID_SI7018) |
| 3333 | s = "sis7018"; | 3339 | s = "sis7018"; |
| 3334 | if (! snd_card_proc_new(trident->card, s, &entry)) | 3340 | if (! snd_card_proc_new(trident->card, s, &entry)) |
| 3335 | snd_info_set_text_ops(entry, trident, 1024, snd_trident_proc_read); | 3341 | snd_info_set_text_ops(entry, trident, snd_trident_proc_read); |
| 3336 | } | 3342 | } |
| 3337 | 3343 | ||
| 3338 | static int snd_trident_dev_free(struct snd_device *device) | 3344 | static int snd_trident_dev_free(struct snd_device *device) |
| @@ -3884,6 +3890,8 @@ struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, | |||
| 3884 | return NULL; | 3890 | return NULL; |
| 3885 | } | 3891 | } |
| 3886 | 3892 | ||
| 3893 | EXPORT_SYMBOL(snd_trident_alloc_voice); | ||
| 3894 | |||
| 3887 | void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voice *voice) | 3895 | void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voice *voice) |
| 3888 | { | 3896 | { |
| 3889 | unsigned long flags; | 3897 | unsigned long flags; |
| @@ -3912,6 +3920,8 @@ void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voi | |||
| 3912 | private_free(voice); | 3920 | private_free(voice); |
| 3913 | } | 3921 | } |
| 3914 | 3922 | ||
| 3923 | EXPORT_SYMBOL(snd_trident_free_voice); | ||
| 3924 | |||
| 3915 | static void snd_trident_clear_voices(struct snd_trident * trident, unsigned short v_min, unsigned short v_max) | 3925 | static void snd_trident_clear_voices(struct snd_trident * trident, unsigned short v_min, unsigned short v_max) |
| 3916 | { | 3926 | { |
| 3917 | unsigned int i, val, mask[2] = { 0, 0 }; | 3927 | unsigned int i, val, mask[2] = { 0, 0 }; |
| @@ -3993,13 +4003,3 @@ int snd_trident_resume(struct pci_dev *pci) | |||
| 3993 | return 0; | 4003 | return 0; |
| 3994 | } | 4004 | } |
| 3995 | #endif /* CONFIG_PM */ | 4005 | #endif /* CONFIG_PM */ |
| 3996 | |||
| 3997 | EXPORT_SYMBOL(snd_trident_alloc_voice); | ||
| 3998 | EXPORT_SYMBOL(snd_trident_free_voice); | ||
| 3999 | EXPORT_SYMBOL(snd_trident_start_voice); | ||
| 4000 | EXPORT_SYMBOL(snd_trident_stop_voice); | ||
| 4001 | EXPORT_SYMBOL(snd_trident_write_voice_regs); | ||
| 4002 | /* trident_memory.c symbols */ | ||
| 4003 | EXPORT_SYMBOL(snd_trident_synth_alloc); | ||
| 4004 | EXPORT_SYMBOL(snd_trident_synth_free); | ||
| 4005 | EXPORT_SYMBOL(snd_trident_synth_copy_from_user); | ||
diff --git a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c index 46c6982c9e88..aff3f874131c 100644 --- a/sound/pci/trident/trident_memory.c +++ b/sound/pci/trident/trident_memory.c | |||
| @@ -349,6 +349,7 @@ snd_trident_synth_alloc(struct snd_trident *hw, unsigned int size) | |||
| 349 | return blk; | 349 | return blk; |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | EXPORT_SYMBOL(snd_trident_synth_alloc); | ||
| 352 | 353 | ||
| 353 | /* | 354 | /* |
| 354 | * free a synth sample area | 355 | * free a synth sample area |
| @@ -365,6 +366,7 @@ snd_trident_synth_free(struct snd_trident *hw, struct snd_util_memblk *blk) | |||
| 365 | return 0; | 366 | return 0; |
| 366 | } | 367 | } |
| 367 | 368 | ||
| 369 | EXPORT_SYMBOL(snd_trident_synth_free); | ||
| 368 | 370 | ||
| 369 | /* | 371 | /* |
| 370 | * reset TLB entry and free kernel page | 372 | * reset TLB entry and free kernel page |
| @@ -486,3 +488,4 @@ int snd_trident_synth_copy_from_user(struct snd_trident *trident, | |||
| 486 | return 0; | 488 | return 0; |
| 487 | } | 489 | } |
| 488 | 490 | ||
| 491 | EXPORT_SYMBOL(snd_trident_synth_copy_from_user); | ||
diff --git a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c index cc7af8bc55a0..9b7dee84743b 100644 --- a/sound/pci/trident/trident_synth.c +++ b/sound/pci/trident/trident_synth.c | |||
| @@ -914,7 +914,9 @@ static int snd_trident_synth_create_port(struct snd_trident * trident, int idx) | |||
| 914 | &callbacks, | 914 | &callbacks, |
| 915 | SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, | 915 | SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, |
| 916 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | | 916 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | |
| 917 | SNDRV_SEQ_PORT_TYPE_SYNTH, | 917 | SNDRV_SEQ_PORT_TYPE_SYNTH | |
| 918 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
| 919 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER, | ||
| 918 | 16, 0, | 920 | 16, 0, |
| 919 | name); | 921 | name); |
| 920 | if (p->chset->port < 0) { | 922 | if (p->chset->port < 0) { |
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 39daf62d2bad..2527bbd958c5 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
| @@ -1775,6 +1775,12 @@ static struct ac97_quirk ac97_quirks[] = { | |||
| 1775 | .name = "Targa Traveller 811", | 1775 | .name = "Targa Traveller 811", |
| 1776 | .type = AC97_TUNE_HP_ONLY, | 1776 | .type = AC97_TUNE_HP_ONLY, |
| 1777 | }, | 1777 | }, |
| 1778 | { | ||
| 1779 | .subvendor = 0x161f, | ||
| 1780 | .subdevice = 0x2032, | ||
| 1781 | .name = "m680x", | ||
| 1782 | .type = AC97_TUNE_HP_ONLY, /* http://launchpad.net/bugs/38546 */ | ||
| 1783 | }, | ||
| 1778 | { } /* terminator */ | 1784 | { } /* terminator */ |
| 1779 | }; | 1785 | }; |
| 1780 | 1786 | ||
| @@ -1973,7 +1979,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip) | |||
| 1973 | pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg); | 1979 | pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg); |
| 1974 | if (chip->mpu_res) { | 1980 | if (chip->mpu_res) { |
| 1975 | if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A, | 1981 | if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A, |
| 1976 | mpu_port, 1, | 1982 | mpu_port, MPU401_INFO_INTEGRATED, |
| 1977 | chip->irq, 0, &chip->rmidi) < 0) { | 1983 | chip->irq, 0, &chip->rmidi) < 0) { |
| 1978 | printk(KERN_WARNING "unable to initialize MPU-401" | 1984 | printk(KERN_WARNING "unable to initialize MPU-401" |
| 1979 | " at 0x%lx, skipping\n", mpu_port); | 1985 | " at 0x%lx, skipping\n", mpu_port); |
| @@ -2015,7 +2021,7 @@ static void __devinit snd_via82xx_proc_init(struct via82xx *chip) | |||
| 2015 | struct snd_info_entry *entry; | 2021 | struct snd_info_entry *entry; |
| 2016 | 2022 | ||
| 2017 | if (! snd_card_proc_new(chip->card, "via82xx", &entry)) | 2023 | if (! snd_card_proc_new(chip->card, "via82xx", &entry)) |
| 2018 | snd_info_set_text_ops(entry, chip, 1024, snd_via82xx_proc_read); | 2024 | snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read); |
| 2019 | } | 2025 | } |
| 2020 | 2026 | ||
| 2021 | /* | 2027 | /* |
| @@ -2365,7 +2371,7 @@ static int __devinit check_dxs_list(struct pci_dev *pci, int revision) | |||
| 2365 | { .subvendor = 0x1462, .subdevice = 0x0470, .action = VIA_DXS_SRC }, /* MSI KT880 Delta-FSR */ | 2371 | { .subvendor = 0x1462, .subdevice = 0x0470, .action = VIA_DXS_SRC }, /* MSI KT880 Delta-FSR */ |
| 2366 | { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ | 2372 | { .subvendor = 0x1462, .subdevice = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ |
| 2367 | { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ | 2373 | { .subvendor = 0x1462, .subdevice = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ |
| 2368 | { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_NO_VRA }, /* MSI K8T Neo2-FI */ | 2374 | { .subvendor = 0x1462, .subdevice = 0x7023, .action = VIA_DXS_SRC }, /* MSI K8T Neo2-FI */ |
| 2369 | { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ | 2375 | { .subvendor = 0x1462, .subdevice = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ |
| 2370 | { .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */ | 2376 | { .subvendor = 0x1462, .subdevice = 0x7142, .action = VIA_DXS_ENABLE }, /* MSI K8MM-V */ |
| 2371 | { .subvendor = 0x1462, .subdevice = 0xb012, .action = VIA_DXS_SRC }, /* P4M800/VIA8237R */ | 2377 | { .subvendor = 0x1462, .subdevice = 0xb012, .action = VIA_DXS_SRC }, /* P4M800/VIA8237R */ |
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index ef97e50cd6c2..577a2b03759f 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c | |||
| @@ -929,7 +929,7 @@ static void __devinit snd_via82xx_proc_init(struct via82xx_modem *chip) | |||
| 929 | struct snd_info_entry *entry; | 929 | struct snd_info_entry *entry; |
| 930 | 930 | ||
| 931 | if (! snd_card_proc_new(chip->card, "via82xx", &entry)) | 931 | if (! snd_card_proc_new(chip->card, "via82xx", &entry)) |
| 932 | snd_info_set_text_ops(entry, chip, 1024, snd_via82xx_proc_read); | 932 | snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read); |
| 933 | } | 933 | } |
| 934 | 934 | ||
| 935 | /* | 935 | /* |
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 65ebf5f1933a..26aa775b7b69 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c | |||
| @@ -308,7 +308,8 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, | |||
| 308 | } | 308 | } |
| 309 | if (chip->mpu_res) { | 309 | if (chip->mpu_res) { |
| 310 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, | 310 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, |
| 311 | mpu_port[dev], 1, | 311 | mpu_port[dev], |
| 312 | MPU401_INFO_INTEGRATED, | ||
| 312 | pci->irq, 0, &chip->rawmidi)) < 0) { | 313 | pci->irq, 0, &chip->rawmidi)) < 0) { |
| 313 | printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]); | 314 | printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]); |
| 314 | legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */ | 315 | legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */ |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 8ac5ab50b5c7..f894752523bb 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
| @@ -1919,7 +1919,7 @@ static int __devinit snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfp | |||
| 1919 | struct snd_info_entry *entry; | 1919 | struct snd_info_entry *entry; |
| 1920 | 1920 | ||
| 1921 | if (! snd_card_proc_new(card, "ymfpci", &entry)) | 1921 | if (! snd_card_proc_new(card, "ymfpci", &entry)) |
| 1922 | snd_info_set_text_ops(entry, chip, 1024, snd_ymfpci_proc_read); | 1922 | snd_info_set_text_ops(entry, chip, snd_ymfpci_proc_read); |
| 1923 | return 0; | 1923 | return 0; |
| 1924 | } | 1924 | } |
| 1925 | 1925 | ||
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c index bd0d70ff3019..1dfe29b863d3 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c | |||
| @@ -144,7 +144,7 @@ static void pdacf_proc_init(struct snd_pdacf *chip) | |||
| 144 | struct snd_info_entry *entry; | 144 | struct snd_info_entry *entry; |
| 145 | 145 | ||
| 146 | if (! snd_card_proc_new(chip->card, "pdaudiocf", &entry)) | 146 | if (! snd_card_proc_new(chip->card, "pdaudiocf", &entry)) |
| 147 | snd_info_set_text_ops(entry, chip, 1024, pdacf_proc_read); | 147 | snd_info_set_text_ops(entry, chip, pdacf_proc_read); |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | struct snd_pdacf *snd_pdacf_create(struct snd_card *card) | 150 | struct snd_pdacf *snd_pdacf_create(struct snd_card *card) |
diff --git a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c index 7f82f619f9f4..1ee0918c3b9f 100644 --- a/sound/pcmcia/vx/vxp_ops.c +++ b/sound/pcmcia/vx/vxp_ops.c | |||
| @@ -202,7 +202,7 @@ static int vxp_load_xilinx_binary(struct vx_core *_chip, const struct firmware * | |||
| 202 | c |= (int)vx_inb(chip, RXM) << 8; | 202 | c |= (int)vx_inb(chip, RXM) << 8; |
| 203 | c |= vx_inb(chip, RXL); | 203 | c |= vx_inb(chip, RXL); |
| 204 | 204 | ||
| 205 | snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%x\n", c, fw->size); | 205 | snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%Zx\n", c, fw->size); |
| 206 | 206 | ||
| 207 | vx_outb(chip, ICR, ICR_HF0); | 207 | vx_outb(chip, ICR, ICR_HF0); |
| 208 | 208 | ||
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 7e0cda2b6ef9..cafe6640cc1a 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c | |||
| @@ -261,7 +261,7 @@ static int vxpocket_config(struct pcmcia_device *link) | |||
| 261 | 261 | ||
| 262 | link->dev_node = &vxp->node; | 262 | link->dev_node = &vxp->node; |
| 263 | kfree(parse); | 263 | kfree(parse); |
| 264 | return 9; | 264 | return 0; |
| 265 | 265 | ||
| 266 | cs_failed: | 266 | cs_failed: |
| 267 | cs_error(link, last_fn, last_ret); | 267 | cs_error(link, last_fn, last_ret); |
diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile index d6ba9959097b..4d95c652c8ca 100644 --- a/sound/ppc/Makefile +++ b/sound/ppc/Makefile | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> | 3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> |
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o toonie.o keywest.o beep.o | 6 | snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o |
| 7 | 7 | ||
| 8 | # Toplevel Module Dependency | 8 | # Toplevel Module Dependency |
| 9 | obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o | 9 | obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o |
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index f0794ef9d1ac..b678814975c9 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c | |||
| @@ -867,8 +867,6 @@ static int __init snd_pmac_detect(struct snd_pmac *chip) | |||
| 867 | unsigned int *prop, l; | 867 | unsigned int *prop, l; |
| 868 | struct macio_chip* macio; | 868 | struct macio_chip* macio; |
| 869 | 869 | ||
| 870 | u32 layout_id = 0; | ||
| 871 | |||
| 872 | if (!machine_is(powermac)) | 870 | if (!machine_is(powermac)) |
| 873 | return -ENODEV; | 871 | return -ENODEV; |
| 874 | 872 | ||
| @@ -929,8 +927,14 @@ static int __init snd_pmac_detect(struct snd_pmac *chip) | |||
| 929 | if (prop && *prop < 16) | 927 | if (prop && *prop < 16) |
| 930 | chip->subframe = *prop; | 928 | chip->subframe = *prop; |
| 931 | prop = (unsigned int *) get_property(sound, "layout-id", NULL); | 929 | prop = (unsigned int *) get_property(sound, "layout-id", NULL); |
| 932 | if (prop) | 930 | if (prop) { |
| 933 | layout_id = *prop; | 931 | /* partly deprecate snd-powermac, for those machines |
| 932 | * that have a layout-id property for now */ | ||
| 933 | printk(KERN_INFO "snd-powermac no longer handles any " | ||
| 934 | "machines with a layout-id property " | ||
| 935 | "in the device-tree, use snd-aoa.\n"); | ||
| 936 | return -ENODEV; | ||
| 937 | } | ||
| 934 | /* This should be verified on older screamers */ | 938 | /* This should be verified on older screamers */ |
| 935 | if (device_is_compatible(sound, "screamer")) { | 939 | if (device_is_compatible(sound, "screamer")) { |
| 936 | chip->model = PMAC_SCREAMER; | 940 | chip->model = PMAC_SCREAMER; |
| @@ -963,38 +967,6 @@ static int __init snd_pmac_detect(struct snd_pmac *chip) | |||
| 963 | chip->freq_table = tumbler_freqs; | 967 | chip->freq_table = tumbler_freqs; |
| 964 | chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ | 968 | chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */ |
| 965 | } | 969 | } |
| 966 | if (device_is_compatible(sound, "AOAKeylargo") || | ||
| 967 | device_is_compatible(sound, "AOAbase") || | ||
| 968 | device_is_compatible(sound, "AOAK2")) { | ||
| 969 | /* For now, only support very basic TAS3004 based machines with | ||
| 970 | * single frequency until proper i2s control is implemented | ||
| 971 | */ | ||
| 972 | switch(layout_id) { | ||
| 973 | case 0x24: | ||
| 974 | case 0x29: | ||
| 975 | case 0x33: | ||
| 976 | case 0x46: | ||
| 977 | case 0x48: | ||
| 978 | case 0x50: | ||
| 979 | case 0x5c: | ||
| 980 | chip->num_freqs = ARRAY_SIZE(tumbler_freqs); | ||
| 981 | chip->model = PMAC_SNAPPER; | ||
| 982 | chip->can_byte_swap = 0; /* FIXME: check this */ | ||
| 983 | chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */ | ||
| 984 | break; | ||
| 985 | case 0x3a: | ||
| 986 | chip->num_freqs = ARRAY_SIZE(tumbler_freqs); | ||
| 987 | chip->model = PMAC_TOONIE; | ||
| 988 | chip->can_byte_swap = 0; /* FIXME: check this */ | ||
| 989 | chip->control_mask = MASK_IEPC | 0x11;/* disable IEE */ | ||
| 990 | break; | ||
| 991 | default: | ||
| 992 | printk(KERN_ERR "snd: Unknown layout ID 0x%x\n", | ||
| 993 | layout_id); | ||
| 994 | return -ENODEV; | ||
| 995 | |||
| 996 | } | ||
| 997 | } | ||
| 998 | prop = (unsigned int *)get_property(sound, "device-id", NULL); | 970 | prop = (unsigned int *)get_property(sound, "device-id", NULL); |
| 999 | if (prop) | 971 | if (prop) |
| 1000 | chip->device_id = *prop; | 972 | chip->device_id = *prop; |
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h index 3a9bd4dbb9a6..8394e66ceb00 100644 --- a/sound/ppc/pmac.h +++ b/sound/ppc/pmac.h | |||
| @@ -85,7 +85,7 @@ struct pmac_stream { | |||
| 85 | 85 | ||
| 86 | enum snd_pmac_model { | 86 | enum snd_pmac_model { |
| 87 | PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER, | 87 | PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER, |
| 88 | PMAC_SNAPPER, PMAC_TOONIE | 88 | PMAC_SNAPPER |
| 89 | }; | 89 | }; |
| 90 | 90 | ||
| 91 | struct snd_pmac { | 91 | struct snd_pmac { |
| @@ -188,7 +188,6 @@ int snd_pmac_burgundy_init(struct snd_pmac *chip); | |||
| 188 | int snd_pmac_daca_init(struct snd_pmac *chip); | 188 | int snd_pmac_daca_init(struct snd_pmac *chip); |
| 189 | int snd_pmac_tumbler_init(struct snd_pmac *chip); | 189 | int snd_pmac_tumbler_init(struct snd_pmac *chip); |
| 190 | int snd_pmac_tumbler_post_init(void); | 190 | int snd_pmac_tumbler_post_init(void); |
| 191 | int snd_pmac_toonie_init(struct snd_pmac *chip); | ||
| 192 | 191 | ||
| 193 | /* i2c functions */ | 192 | /* i2c functions */ |
| 194 | struct pmac_keywest { | 193 | struct pmac_keywest { |
diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c index f4902a219e50..fa9a44ab487e 100644 --- a/sound/ppc/powermac.c +++ b/sound/ppc/powermac.c | |||
| @@ -94,13 +94,6 @@ static int __init snd_pmac_probe(struct platform_device *devptr) | |||
| 94 | if ( snd_pmac_tumbler_init(chip) < 0 || snd_pmac_tumbler_post_init() < 0) | 94 | if ( snd_pmac_tumbler_init(chip) < 0 || snd_pmac_tumbler_post_init() < 0) |
| 95 | goto __error; | 95 | goto __error; |
| 96 | break; | 96 | break; |
| 97 | case PMAC_TOONIE: | ||
| 98 | strcpy(card->driver, "PMac Toonie"); | ||
| 99 | strcpy(card->shortname, "PowerMac Toonie"); | ||
| 100 | strcpy(card->longname, card->shortname); | ||
| 101 | if ((err = snd_pmac_toonie_init(chip)) < 0) | ||
| 102 | goto __error; | ||
| 103 | break; | ||
| 104 | case PMAC_AWACS: | 97 | case PMAC_AWACS: |
| 105 | case PMAC_SCREAMER: | 98 | case PMAC_SCREAMER: |
| 106 | name_ext = chip->model == PMAC_SCREAMER ? "Screamer" : "AWACS"; | 99 | name_ext = chip->model == PMAC_SCREAMER ? "Screamer" : "AWACS"; |
| @@ -188,11 +181,15 @@ static int __init alsa_card_pmac_init(void) | |||
| 188 | if ((err = platform_driver_register(&snd_pmac_driver)) < 0) | 181 | if ((err = platform_driver_register(&snd_pmac_driver)) < 0) |
| 189 | return err; | 182 | return err; |
| 190 | device = platform_device_register_simple(SND_PMAC_DRIVER, -1, NULL, 0); | 183 | device = platform_device_register_simple(SND_PMAC_DRIVER, -1, NULL, 0); |
| 191 | if (IS_ERR(device)) { | 184 | if (!IS_ERR(device)) { |
| 192 | platform_driver_unregister(&snd_pmac_driver); | 185 | if (platform_get_drvdata(device)) |
| 193 | return PTR_ERR(device); | 186 | return 0; |
| 194 | } | 187 | platform_device_unregister(device); |
| 195 | return 0; | 188 | err = -ENODEV; |
| 189 | } else | ||
| 190 | err = PTR_ERR(device); | ||
| 191 | platform_driver_unregister(&snd_pmac_driver); | ||
| 192 | return err; | ||
| 196 | 193 | ||
| 197 | } | 194 | } |
| 198 | 195 | ||
diff --git a/sound/ppc/toonie.c b/sound/ppc/toonie.c index 1ac7c8552f50..e69de29bb2d1 100644 --- a/sound/ppc/toonie.c +++ b/sound/ppc/toonie.c | |||
| @@ -1,378 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Mac Mini "toonie" mixer control | ||
| 3 | * | ||
| 4 | * Copyright (c) 2005 by Benjamin Herrenschmidt <benh@kernel.crashing.org> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <sound/driver.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/delay.h> | ||
| 24 | #include <linux/i2c.h> | ||
| 25 | #include <linux/kmod.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | #include <linux/interrupt.h> | ||
| 28 | #include <sound/core.h> | ||
| 29 | #include <asm/io.h> | ||
| 30 | #include <asm/irq.h> | ||
| 31 | #include <asm/machdep.h> | ||
| 32 | #include <asm/pmac_feature.h> | ||
| 33 | #include "pmac.h" | ||
| 34 | |||
| 35 | #undef DEBUG | ||
| 36 | |||
| 37 | #ifdef DEBUG | ||
| 38 | #define DBG(fmt...) printk(fmt) | ||
| 39 | #else | ||
| 40 | #define DBG(fmt...) | ||
| 41 | #endif | ||
| 42 | |||
| 43 | struct pmac_gpio { | ||
| 44 | unsigned int addr; | ||
| 45 | u8 active_val; | ||
| 46 | u8 inactive_val; | ||
| 47 | u8 active_state; | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct pmac_toonie | ||
| 51 | { | ||
| 52 | struct pmac_gpio hp_detect_gpio; | ||
| 53 | struct pmac_gpio hp_mute_gpio; | ||
| 54 | struct pmac_gpio amp_mute_gpio; | ||
| 55 | int hp_detect_irq; | ||
| 56 | int auto_mute_notify; | ||
| 57 | struct work_struct detect_work; | ||
| 58 | }; | ||
| 59 | |||
| 60 | |||
| 61 | /* | ||
| 62 | * gpio access | ||
| 63 | */ | ||
| 64 | #define do_gpio_write(gp, val) \ | ||
| 65 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, (gp)->addr, val) | ||
| 66 | #define do_gpio_read(gp) \ | ||
| 67 | pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, (gp)->addr, 0) | ||
| 68 | #define tumbler_gpio_free(gp) /* NOP */ | ||
| 69 | |||
| 70 | static void write_audio_gpio(struct pmac_gpio *gp, int active) | ||
| 71 | { | ||
| 72 | if (! gp->addr) | ||
| 73 | return; | ||
| 74 | active = active ? gp->active_val : gp->inactive_val; | ||
| 75 | do_gpio_write(gp, active); | ||
| 76 | DBG("(I) gpio %x write %d\n", gp->addr, active); | ||
| 77 | } | ||
| 78 | |||
| 79 | static int check_audio_gpio(struct pmac_gpio *gp) | ||
| 80 | { | ||
| 81 | int ret; | ||
| 82 | |||
| 83 | if (! gp->addr) | ||
| 84 | return 0; | ||
| 85 | |||
| 86 | ret = do_gpio_read(gp); | ||
| 87 | |||
| 88 | return (ret & 0xd) == (gp->active_val & 0xd); | ||
| 89 | } | ||
| 90 | |||
| 91 | static int read_audio_gpio(struct pmac_gpio *gp) | ||
| 92 | { | ||
| 93 | int ret; | ||
| 94 | if (! gp->addr) | ||
| 95 | return 0; | ||
| 96 | ret = ((do_gpio_read(gp) & 0x02) !=0); | ||
| 97 | return ret == gp->active_state; | ||
| 98 | } | ||
| 99 | |||
| 100 | |||
| 101 | enum { TOONIE_MUTE_HP, TOONIE_MUTE_AMP }; | ||
| 102 | |||
| 103 | static int toonie_get_mute_switch(struct snd_kcontrol *kcontrol, | ||
| 104 | struct snd_ctl_elem_value *ucontrol) | ||
| 105 | { | ||
| 106 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | ||
| 107 | struct pmac_toonie *mix = chip->mixer_data; | ||
| 108 | struct pmac_gpio *gp; | ||
| 109 | |||
| 110 | if (mix == NULL) | ||
| 111 | return -ENODEV; | ||
| 112 | switch(kcontrol->private_value) { | ||
| 113 | case TOONIE_MUTE_HP: | ||
| 114 | gp = &mix->hp_mute_gpio; | ||
| 115 | break; | ||
| 116 | case TOONIE_MUTE_AMP: | ||
| 117 | gp = &mix->amp_mute_gpio; | ||
| 118 | break; | ||
| 119 | default: | ||
| 120 | return -EINVAL; | ||
| 121 | } | ||
| 122 | ucontrol->value.integer.value[0] = !check_audio_gpio(gp); | ||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | static int toonie_put_mute_switch(struct snd_kcontrol *kcontrol, | ||
| 127 | struct snd_ctl_elem_value *ucontrol) | ||
| 128 | { | ||
| 129 | struct snd_pmac *chip = snd_kcontrol_chip(kcontrol); | ||
| 130 | struct pmac_toonie *mix = chip->mixer_data; | ||
| 131 | struct pmac_gpio *gp; | ||
| 132 | int val; | ||
| 133 | |||
| 134 | if (chip->update_automute && chip->auto_mute) | ||
| 135 | return 0; /* don't touch in the auto-mute mode */ | ||
| 136 | |||
| 137 | if (mix == NULL) | ||
| 138 | return -ENODEV; | ||
| 139 | |||
| 140 | switch(kcontrol->private_value) { | ||
| 141 | case TOONIE_MUTE_HP: | ||
| 142 | gp = &mix->hp_mute_gpio; | ||
| 143 | break; | ||
| 144 | case TOONIE_MUTE_AMP: | ||
| 145 | gp = &mix->amp_mute_gpio; | ||
| 146 | break; | ||
| 147 | default: | ||
| 148 | return -EINVAL; | ||
| 149 | } | ||
| 150 | val = ! check_audio_gpio(gp); | ||
| 151 | if (val != ucontrol->value.integer.value[0]) { | ||
| 152 | write_audio_gpio(gp, ! ucontrol->value.integer.value[0]); | ||
| 153 | return 1; | ||
| 154 | } | ||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | static struct snd_kcontrol_new toonie_hp_sw __initdata = { | ||
| 159 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 160 | .name = "Headphone Playback Switch", | ||
| 161 | .info = snd_pmac_boolean_mono_info, | ||
| 162 | .get = toonie_get_mute_switch, | ||
| 163 | .put = toonie_put_mute_switch, | ||
| 164 | .private_value = TOONIE_MUTE_HP, | ||
| 165 | }; | ||
| 166 | static struct snd_kcontrol_new toonie_speaker_sw __initdata = { | ||
| 167 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 168 | .name = "PC Speaker Playback Switch", | ||
| 169 | .info = snd_pmac_boolean_mono_info, | ||
| 170 | .get = toonie_get_mute_switch, | ||
| 171 | .put = toonie_put_mute_switch, | ||
| 172 | .private_value = TOONIE_MUTE_AMP, | ||
| 173 | }; | ||
| 174 | |||
| 175 | /* | ||
| 176 | * auto-mute stuffs | ||
| 177 | */ | ||
| 178 | static int toonie_detect_headphone(struct snd_pmac *chip) | ||
| 179 | { | ||
| 180 | struct pmac_toonie *mix = chip->mixer_data; | ||
| 181 | int detect = 0; | ||
| 182 | |||
| 183 | if (mix->hp_detect_gpio.addr) | ||
| 184 | detect |= read_audio_gpio(&mix->hp_detect_gpio); | ||
| 185 | return detect; | ||
| 186 | } | ||
| 187 | |||
| 188 | static void toonie_check_mute(struct snd_pmac *chip, struct pmac_gpio *gp, int val, | ||
| 189 | int do_notify, struct snd_kcontrol *sw) | ||
| 190 | { | ||
| 191 | if (check_audio_gpio(gp) != val) { | ||
| 192 | write_audio_gpio(gp, val); | ||
| 193 | if (do_notify) | ||
| 194 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
| 195 | &sw->id); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | static void toonie_detect_handler(void *self) | ||
| 200 | { | ||
| 201 | struct snd_pmac *chip = (struct snd_pmac *) self; | ||
| 202 | struct pmac_toonie *mix; | ||
| 203 | int headphone; | ||
| 204 | |||
| 205 | if (!chip) | ||
| 206 | return; | ||
| 207 | |||
| 208 | mix = chip->mixer_data; | ||
| 209 | snd_assert(mix, return); | ||
| 210 | |||
| 211 | headphone = toonie_detect_headphone(chip); | ||
| 212 | |||
| 213 | DBG("headphone: %d, lineout: %d\n", headphone, lineout); | ||
| 214 | |||
| 215 | if (headphone) { | ||
| 216 | /* unmute headphone/lineout & mute speaker */ | ||
| 217 | toonie_check_mute(chip, &mix->hp_mute_gpio, 0, | ||
| 218 | mix->auto_mute_notify, chip->master_sw_ctl); | ||
| 219 | toonie_check_mute(chip, &mix->amp_mute_gpio, 1, | ||
| 220 | mix->auto_mute_notify, chip->speaker_sw_ctl); | ||
| 221 | } else { | ||
| 222 | /* unmute speaker, mute others */ | ||
| 223 | toonie_check_mute(chip, &mix->amp_mute_gpio, 0, | ||
| 224 | mix->auto_mute_notify, chip->speaker_sw_ctl); | ||
| 225 | toonie_check_mute(chip, &mix->hp_mute_gpio, 1, | ||
| 226 | mix->auto_mute_notify, chip->master_sw_ctl); | ||
| 227 | } | ||
| 228 | if (mix->auto_mute_notify) { | ||
| 229 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
| 230 | &chip->hp_detect_ctl->id); | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | static void toonie_update_automute(struct snd_pmac *chip, int do_notify) | ||
| 235 | { | ||
| 236 | if (chip->auto_mute) { | ||
| 237 | struct pmac_toonie *mix; | ||
| 238 | mix = chip->mixer_data; | ||
| 239 | snd_assert(mix, return); | ||
| 240 | mix->auto_mute_notify = do_notify; | ||
| 241 | schedule_work(&mix->detect_work); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | /* interrupt - headphone plug changed */ | ||
| 246 | static irqreturn_t toonie_hp_intr(int irq, void *devid, struct pt_regs *regs) | ||
| 247 | { | ||
| 248 | struct snd_pmac *chip = devid; | ||
| 249 | |||
| 250 | if (chip->update_automute && chip->initialized) { | ||
| 251 | chip->update_automute(chip, 1); | ||
| 252 | return IRQ_HANDLED; | ||
| 253 | } | ||
| 254 | return IRQ_NONE; | ||
| 255 | } | ||
| 256 | |||
| 257 | /* look for audio gpio device */ | ||
| 258 | static int find_audio_gpio(const char *name, const char *platform, | ||
| 259 | struct pmac_gpio *gp) | ||
| 260 | { | ||
| 261 | struct device_node *np; | ||
| 262 | u32 *base, addr; | ||
| 263 | |||
| 264 | if (! (np = find_devices("gpio"))) | ||
| 265 | return -ENODEV; | ||
| 266 | |||
| 267 | for (np = np->child; np; np = np->sibling) { | ||
| 268 | char *property = get_property(np, "audio-gpio", NULL); | ||
| 269 | if (property && strcmp(property, name) == 0) | ||
| 270 | break; | ||
| 271 | if (device_is_compatible(np, name)) | ||
| 272 | break; | ||
| 273 | } | ||
| 274 | if (np == NULL) | ||
| 275 | return -ENODEV; | ||
| 276 | |||
| 277 | base = (u32 *)get_property(np, "AAPL,address", NULL); | ||
| 278 | if (! base) { | ||
| 279 | base = (u32 *)get_property(np, "reg", NULL); | ||
| 280 | if (!base) { | ||
| 281 | DBG("(E) cannot find address for device %s !\n", name); | ||
| 282 | return -ENODEV; | ||
| 283 | } | ||
| 284 | addr = *base; | ||
| 285 | if (addr < 0x50) | ||
| 286 | addr += 0x50; | ||
| 287 | } else | ||
| 288 | addr = *base; | ||
| 289 | |||
| 290 | gp->addr = addr & 0x0000ffff; | ||
| 291 | |||
| 292 | /* Try to find the active state, default to 0 ! */ | ||
| 293 | base = (u32 *)get_property(np, "audio-gpio-active-state", NULL); | ||
| 294 | if (base) { | ||
| 295 | gp->active_state = *base; | ||
| 296 | gp->active_val = (*base) ? 0x5 : 0x4; | ||
| 297 | gp->inactive_val = (*base) ? 0x4 : 0x5; | ||
| 298 | } else { | ||
| 299 | u32 *prop = NULL; | ||
| 300 | gp->active_state = 0; | ||
| 301 | gp->active_val = 0x4; | ||
| 302 | gp->inactive_val = 0x5; | ||
| 303 | /* Here are some crude hacks to extract the GPIO polarity and | ||
| 304 | * open collector informations out of the do-platform script | ||
| 305 | * as we don't yet have an interpreter for these things | ||
| 306 | */ | ||
| 307 | if (platform) | ||
| 308 | prop = (u32 *)get_property(np, platform, NULL); | ||
| 309 | if (prop) { | ||
| 310 | if (prop[3] == 0x9 && prop[4] == 0x9) { | ||
| 311 | gp->active_val = 0xd; | ||
| 312 | gp->inactive_val = 0xc; | ||
| 313 | } | ||
| 314 | if (prop[3] == 0x1 && prop[4] == 0x1) { | ||
| 315 | gp->active_val = 0x5; | ||
| 316 | gp->inactive_val = 0x4; | ||
| 317 | } | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | DBG("(I) GPIO device %s found, offset: %x, active state: %d !\n", | ||
| 322 | name, gp->addr, gp->active_state); | ||
| 323 | |||
| 324 | return (np->n_intrs > 0) ? np->intrs[0].line : 0; | ||
| 325 | } | ||
| 326 | |||
| 327 | static void toonie_cleanup(struct snd_pmac *chip) | ||
| 328 | { | ||
| 329 | struct pmac_toonie *mix = chip->mixer_data; | ||
| 330 | if (! mix) | ||
| 331 | return; | ||
| 332 | if (mix->hp_detect_irq >= 0) | ||
| 333 | free_irq(mix->hp_detect_irq, chip); | ||
| 334 | kfree(mix); | ||
| 335 | chip->mixer_data = NULL; | ||
| 336 | } | ||
| 337 | |||
| 338 | int __init snd_pmac_toonie_init(struct snd_pmac *chip) | ||
| 339 | { | ||
| 340 | struct pmac_toonie *mix; | ||
| 341 | |||
| 342 | mix = kmalloc(sizeof(*mix), GFP_KERNEL); | ||
| 343 | if (! mix) | ||
| 344 | return -ENOMEM; | ||
| 345 | |||
| 346 | chip->mixer_data = mix; | ||
| 347 | chip->mixer_free = toonie_cleanup; | ||
| 348 | |||
| 349 | find_audio_gpio("headphone-mute", NULL, &mix->hp_mute_gpio); | ||
| 350 | find_audio_gpio("amp-mute", NULL, &mix->amp_mute_gpio); | ||
| 351 | mix->hp_detect_irq = find_audio_gpio("headphone-detect", | ||
| 352 | NULL, &mix->hp_detect_gpio); | ||
| 353 | |||
| 354 | strcpy(chip->card->mixername, "PowerMac Toonie"); | ||
| 355 | |||
| 356 | chip->master_sw_ctl = snd_ctl_new1(&toonie_hp_sw, chip); | ||
| 357 | snd_ctl_add(chip->card, chip->master_sw_ctl); | ||
| 358 | |||
| 359 | chip->speaker_sw_ctl = snd_ctl_new1(&toonie_speaker_sw, chip); | ||
| 360 | snd_ctl_add(chip->card, chip->speaker_sw_ctl); | ||
| 361 | |||
| 362 | INIT_WORK(&mix->detect_work, toonie_detect_handler, (void *)chip); | ||
| 363 | |||
| 364 | if (mix->hp_detect_irq >= 0) { | ||
| 365 | snd_pmac_add_automute(chip); | ||
| 366 | |||
| 367 | chip->detect_headphone = toonie_detect_headphone; | ||
| 368 | chip->update_automute = toonie_update_automute; | ||
| 369 | toonie_update_automute(chip, 0); | ||
| 370 | |||
| 371 | if (request_irq(mix->hp_detect_irq, toonie_hp_intr, 0, | ||
| 372 | "Sound Headphone Detection", chip) < 0) | ||
| 373 | mix->hp_detect_irq = -1; | ||
| 374 | } | ||
| 375 | |||
| 376 | return 0; | ||
| 377 | } | ||
| 378 | |||
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index e622d08215c9..5eecdd09a79d 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c | |||
| @@ -92,7 +92,7 @@ MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard."); | |||
| 92 | #define D_USR (1<<4) | 92 | #define D_USR (1<<4) |
| 93 | #define D_DESC (1<<5) | 93 | #define D_DESC (1<<5) |
| 94 | 94 | ||
| 95 | static int dbri_debug = 0; | 95 | static int dbri_debug; |
| 96 | module_param(dbri_debug, int, 0644); | 96 | module_param(dbri_debug, int, 0644); |
| 97 | MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard."); | 97 | MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard."); |
| 98 | 98 | ||
| @@ -593,7 +593,7 @@ struct snd_dbri { | |||
| 593 | /* Return a pointer to dbri_streaminfo */ | 593 | /* Return a pointer to dbri_streaminfo */ |
| 594 | #define DBRI_STREAM(dbri, substream) &dbri->stream_info[DBRI_STREAMNO(substream)] | 594 | #define DBRI_STREAM(dbri, substream) &dbri->stream_info[DBRI_STREAMNO(substream)] |
| 595 | 595 | ||
| 596 | static struct snd_dbri *dbri_list = NULL; /* All DBRI devices */ | 596 | static struct snd_dbri *dbri_list; /* All DBRI devices */ |
| 597 | 597 | ||
| 598 | /* | 598 | /* |
| 599 | * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr. | 599 | * Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr. |
| @@ -2521,11 +2521,11 @@ void snd_dbri_proc(struct snd_dbri * dbri) | |||
| 2521 | struct snd_info_entry *entry; | 2521 | struct snd_info_entry *entry; |
| 2522 | 2522 | ||
| 2523 | if (! snd_card_proc_new(dbri->card, "regs", &entry)) | 2523 | if (! snd_card_proc_new(dbri->card, "regs", &entry)) |
| 2524 | snd_info_set_text_ops(entry, dbri, 1024, dbri_regs_read); | 2524 | snd_info_set_text_ops(entry, dbri, dbri_regs_read); |
| 2525 | 2525 | ||
| 2526 | #ifdef DBRI_DEBUG | 2526 | #ifdef DBRI_DEBUG |
| 2527 | if (! snd_card_proc_new(dbri->card, "debug", &entry)) { | 2527 | if (! snd_card_proc_new(dbri->card, "debug", &entry)) { |
| 2528 | snd_info_set_text_ops(entry, dbri, 4096, dbri_debug_read); | 2528 | snd_info_set_text_ops(entry, dbri, dbri_debug_read); |
| 2529 | entry->mode = S_IFREG | S_IRUGO; /* Readable only. */ | 2529 | entry->mode = S_IFREG | S_IRUGO; /* Readable only. */ |
| 2530 | } | 2530 | } |
| 2531 | #endif | 2531 | #endif |
diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index fc733bbf4487..573e3701c14f 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c | |||
| @@ -63,6 +63,7 @@ int snd_emux_new(struct snd_emux **remu) | |||
| 63 | return 0; | 63 | return 0; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | EXPORT_SYMBOL(snd_emux_new); | ||
| 66 | 67 | ||
| 67 | /* | 68 | /* |
| 68 | */ | 69 | */ |
| @@ -136,6 +137,7 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch | |||
| 136 | return 0; | 137 | return 0; |
| 137 | } | 138 | } |
| 138 | 139 | ||
| 140 | EXPORT_SYMBOL(snd_emux_register); | ||
| 139 | 141 | ||
| 140 | /* | 142 | /* |
| 141 | */ | 143 | */ |
| @@ -171,18 +173,8 @@ int snd_emux_free(struct snd_emux *emu) | |||
| 171 | return 0; | 173 | return 0; |
| 172 | } | 174 | } |
| 173 | 175 | ||
| 174 | |||
| 175 | EXPORT_SYMBOL(snd_emux_new); | ||
| 176 | EXPORT_SYMBOL(snd_emux_register); | ||
| 177 | EXPORT_SYMBOL(snd_emux_free); | 176 | EXPORT_SYMBOL(snd_emux_free); |
| 178 | 177 | ||
| 179 | EXPORT_SYMBOL(snd_emux_terminate_all); | ||
| 180 | EXPORT_SYMBOL(snd_emux_lock_voice); | ||
| 181 | EXPORT_SYMBOL(snd_emux_unlock_voice); | ||
| 182 | |||
| 183 | /* soundfont.c */ | ||
| 184 | EXPORT_SYMBOL(snd_sf_linear_to_log); | ||
| 185 | |||
| 186 | 178 | ||
| 187 | /* | 179 | /* |
| 188 | * INIT part | 180 | * INIT part |
diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c index 1ba68ce30279..58b9601f3ad0 100644 --- a/sound/synth/emux/emux_proc.c +++ b/sound/synth/emux/emux_proc.c | |||
| @@ -119,7 +119,6 @@ void snd_emux_proc_init(struct snd_emux *emu, struct snd_card *card, int device) | |||
| 119 | 119 | ||
| 120 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 120 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
| 121 | entry->private_data = emu; | 121 | entry->private_data = emu; |
| 122 | entry->c.text.read_size = 1024; | ||
| 123 | entry->c.text.read = snd_emux_proc_info_read; | 122 | entry->c.text.read = snd_emux_proc_info_read; |
| 124 | if (snd_info_register(entry) < 0) | 123 | if (snd_info_register(entry) < 0) |
| 125 | snd_info_free_entry(entry); | 124 | snd_info_free_entry(entry); |
diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c index 8f00f07701c4..d176cc01742d 100644 --- a/sound/synth/emux/emux_seq.c +++ b/sound/synth/emux/emux_seq.c | |||
| @@ -55,7 +55,8 @@ static struct snd_midi_op emux_ops = { | |||
| 55 | SNDRV_SEQ_PORT_TYPE_MIDI_GM |\ | 55 | SNDRV_SEQ_PORT_TYPE_MIDI_GM |\ |
| 56 | SNDRV_SEQ_PORT_TYPE_MIDI_GS |\ | 56 | SNDRV_SEQ_PORT_TYPE_MIDI_GS |\ |
| 57 | SNDRV_SEQ_PORT_TYPE_MIDI_XG |\ | 57 | SNDRV_SEQ_PORT_TYPE_MIDI_XG |\ |
| 58 | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE) | 58 | SNDRV_SEQ_PORT_TYPE_HARDWARE |\ |
| 59 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) | ||
| 59 | 60 | ||
| 60 | /* | 61 | /* |
| 61 | * Initialise the EMUX Synth by creating a client and registering | 62 | * Initialise the EMUX Synth by creating a client and registering |
diff --git a/sound/synth/emux/emux_synth.c b/sound/synth/emux/emux_synth.c index 24705d15ebd8..3733118d39bb 100644 --- a/sound/synth/emux/emux_synth.c +++ b/sound/synth/emux/emux_synth.c | |||
| @@ -434,6 +434,7 @@ snd_emux_terminate_all(struct snd_emux *emu) | |||
| 434 | spin_unlock_irqrestore(&emu->voice_lock, flags); | 434 | spin_unlock_irqrestore(&emu->voice_lock, flags); |
| 435 | } | 435 | } |
| 436 | 436 | ||
| 437 | EXPORT_SYMBOL(snd_emux_terminate_all); | ||
| 437 | 438 | ||
| 438 | /* | 439 | /* |
| 439 | * Terminate all voices associated with the given port | 440 | * Terminate all voices associated with the given port |
| @@ -951,6 +952,8 @@ void snd_emux_lock_voice(struct snd_emux *emu, int voice) | |||
| 951 | spin_unlock_irqrestore(&emu->voice_lock, flags); | 952 | spin_unlock_irqrestore(&emu->voice_lock, flags); |
| 952 | } | 953 | } |
| 953 | 954 | ||
| 955 | EXPORT_SYMBOL(snd_emux_lock_voice); | ||
| 956 | |||
| 954 | /* | 957 | /* |
| 955 | */ | 958 | */ |
| 956 | void snd_emux_unlock_voice(struct snd_emux *emu, int voice) | 959 | void snd_emux_unlock_voice(struct snd_emux *emu, int voice) |
| @@ -965,3 +968,5 @@ void snd_emux_unlock_voice(struct snd_emux *emu, int voice) | |||
| 965 | voice, emu->voices[voice].state); | 968 | voice, emu->voices[voice].state); |
| 966 | spin_unlock_irqrestore(&emu->voice_lock, flags); | 969 | spin_unlock_irqrestore(&emu->voice_lock, flags); |
| 967 | } | 970 | } |
| 971 | |||
| 972 | EXPORT_SYMBOL(snd_emux_unlock_voice); | ||
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index 32c27162dfb6..455e535933ec 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c | |||
| @@ -195,7 +195,7 @@ snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data, | |||
| 195 | break; | 195 | break; |
| 196 | case SNDRV_SFNT_REMOVE_INFO: | 196 | case SNDRV_SFNT_REMOVE_INFO: |
| 197 | /* patch must be opened */ | 197 | /* patch must be opened */ |
| 198 | if (sflist->currsf) { | 198 | if (!sflist->currsf) { |
| 199 | snd_printk("soundfont: remove_info: patch not opened\n"); | 199 | snd_printk("soundfont: remove_info: patch not opened\n"); |
| 200 | rc = -EINVAL; | 200 | rc = -EINVAL; |
| 201 | } else { | 201 | } else { |
| @@ -810,6 +810,9 @@ snd_sf_linear_to_log(unsigned int amount, int offset, int ratio) | |||
| 810 | return v; | 810 | return v; |
| 811 | } | 811 | } |
| 812 | 812 | ||
| 813 | EXPORT_SYMBOL(snd_sf_linear_to_log); | ||
| 814 | |||
| 815 | |||
| 813 | #define OFFSET_MSEC 653117 /* base = 1000 */ | 816 | #define OFFSET_MSEC 653117 /* base = 1000 */ |
| 814 | #define OFFSET_ABSCENT 851781 /* base = 8176 */ | 817 | #define OFFSET_ABSCENT 851781 /* base = 8176 */ |
| 815 | #define OFFSET_SAMPLERATE 1011119 /* base = 44100 */ | 818 | #define OFFSET_SAMPLERATE 1011119 /* base = 44100 */ |
| @@ -1485,4 +1488,3 @@ snd_soundfont_remove_unlocked(struct snd_sf_list *sflist) | |||
| 1485 | unlock_preset(sflist); | 1488 | unlock_preset(sflist); |
| 1486 | return 0; | 1489 | return 0; |
| 1487 | } | 1490 | } |
| 1488 | |||
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 4e614ac39f21..627de9525a32 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
| @@ -2138,7 +2138,7 @@ static void proc_pcm_format_add(struct snd_usb_stream *stream) | |||
| 2138 | 2138 | ||
| 2139 | sprintf(name, "stream%d", stream->pcm_index); | 2139 | sprintf(name, "stream%d", stream->pcm_index); |
| 2140 | if (! snd_card_proc_new(card, name, &entry)) | 2140 | if (! snd_card_proc_new(card, name, &entry)) |
| 2141 | snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read); | 2141 | snd_info_set_text_ops(entry, stream, proc_pcm_format_read); |
| 2142 | } | 2142 | } |
| 2143 | 2143 | ||
| 2144 | #else | 2144 | #else |
| @@ -2627,9 +2627,10 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 2627 | if (!csep && altsd->bNumEndpoints >= 2) | 2627 | if (!csep && altsd->bNumEndpoints >= 2) |
| 2628 | csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); | 2628 | csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); |
| 2629 | if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) { | 2629 | if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) { |
| 2630 | snd_printk(KERN_ERR "%d:%u:%d : no or invalid class specific endpoint descriptor\n", | 2630 | snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" |
| 2631 | " class specific endpoint descriptor\n", | ||
| 2631 | dev->devnum, iface_no, altno); | 2632 | dev->devnum, iface_no, altno); |
| 2632 | continue; | 2633 | csep = NULL; |
| 2633 | } | 2634 | } |
| 2634 | 2635 | ||
| 2635 | fp = kmalloc(sizeof(*fp), GFP_KERNEL); | 2636 | fp = kmalloc(sizeof(*fp), GFP_KERNEL); |
| @@ -2648,7 +2649,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 2648 | if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) | 2649 | if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) |
| 2649 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) | 2650 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) |
| 2650 | * (fp->maxpacksize & 0x7ff); | 2651 | * (fp->maxpacksize & 0x7ff); |
| 2651 | fp->attributes = csep[3]; | 2652 | fp->attributes = csep ? csep[3] : 0; |
| 2652 | 2653 | ||
| 2653 | /* some quirks for attributes here */ | 2654 | /* some quirks for attributes here */ |
| 2654 | 2655 | ||
| @@ -2980,7 +2981,7 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip, | |||
| 2980 | return -ENXIO; | 2981 | return -ENXIO; |
| 2981 | alts = &iface->altsetting[1]; | 2982 | alts = &iface->altsetting[1]; |
| 2982 | altsd = get_iface_desc(alts); | 2983 | altsd = get_iface_desc(alts); |
| 2983 | if (alts->extralen != 11 || alts->extra[1] != CS_AUDIO_INTERFACE || | 2984 | if (alts->extralen != 11 || alts->extra[1] != USB_DT_CS_INTERFACE || |
| 2984 | altsd->bNumEndpoints != 1) | 2985 | altsd->bNumEndpoints != 1) |
| 2985 | return -ENXIO; | 2986 | return -ENXIO; |
| 2986 | 2987 | ||
| @@ -3197,9 +3198,9 @@ static void snd_usb_audio_create_proc(struct snd_usb_audio *chip) | |||
| 3197 | { | 3198 | { |
| 3198 | struct snd_info_entry *entry; | 3199 | struct snd_info_entry *entry; |
| 3199 | if (! snd_card_proc_new(chip->card, "usbbus", &entry)) | 3200 | if (! snd_card_proc_new(chip->card, "usbbus", &entry)) |
| 3200 | snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbbus_read); | 3201 | snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read); |
| 3201 | if (! snd_card_proc_new(chip->card, "usbid", &entry)) | 3202 | if (! snd_card_proc_new(chip->card, "usbid", &entry)) |
| 3202 | snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbid_read); | 3203 | snd_info_set_text_ops(entry, chip, proc_audio_usbid_read); |
| 3203 | } | 3204 | } |
| 3204 | 3205 | ||
| 3205 | /* | 3206 | /* |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 88733524d0fb..0f4b2b8541d6 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
| @@ -30,13 +30,6 @@ | |||
| 30 | #define USB_SUBCLASS_MIDI_STREAMING 0x03 | 30 | #define USB_SUBCLASS_MIDI_STREAMING 0x03 |
| 31 | #define USB_SUBCLASS_VENDOR_SPEC 0xff | 31 | #define USB_SUBCLASS_VENDOR_SPEC 0xff |
| 32 | 32 | ||
| 33 | #define CS_AUDIO_UNDEFINED 0x20 | ||
| 34 | #define CS_AUDIO_DEVICE 0x21 | ||
| 35 | #define CS_AUDIO_CONFIGURATION 0x22 | ||
| 36 | #define CS_AUDIO_STRING 0x23 | ||
| 37 | #define CS_AUDIO_INTERFACE 0x24 | ||
| 38 | #define CS_AUDIO_ENDPOINT 0x25 | ||
| 39 | |||
| 40 | #define HEADER 0x01 | 33 | #define HEADER 0x01 |
| 41 | #define INPUT_TERMINAL 0x02 | 34 | #define INPUT_TERMINAL 0x02 |
| 42 | #define OUTPUT_TERMINAL 0x03 | 35 | #define OUTPUT_TERMINAL 0x03 |
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 2b9d940c8064..5105b6b05748 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | #include <linux/usb.h> | 48 | #include <linux/usb.h> |
| 49 | #include <sound/core.h> | 49 | #include <sound/core.h> |
| 50 | #include <sound/rawmidi.h> | 50 | #include <sound/rawmidi.h> |
| 51 | #include <sound/asequencer.h> | ||
| 51 | #include "usbaudio.h" | 52 | #include "usbaudio.h" |
| 52 | 53 | ||
| 53 | 54 | ||
| @@ -1010,97 +1011,157 @@ static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_m | |||
| 1010 | * "(product) MIDI (n)" schema because they aren't external MIDI ports, | 1011 | * "(product) MIDI (n)" schema because they aren't external MIDI ports, |
| 1011 | * such as internal control or synthesizer ports. | 1012 | * such as internal control or synthesizer ports. |
| 1012 | */ | 1013 | */ |
| 1013 | static struct { | 1014 | static struct port_info { |
| 1014 | u32 id; | 1015 | u32 id; |
| 1015 | int port; | 1016 | short int port; |
| 1016 | const char *name_format; | 1017 | short int voices; |
| 1017 | } snd_usbmidi_port_names[] = { | 1018 | const char *name; |
| 1019 | unsigned int seq_flags; | ||
| 1020 | } snd_usbmidi_port_info[] = { | ||
| 1021 | #define PORT_INFO(vendor, product, num, name_, voices_, flags) \ | ||
| 1022 | { .id = USB_ID(vendor, product), \ | ||
| 1023 | .port = num, .voices = voices_, \ | ||
| 1024 | .name = name_, .seq_flags = flags } | ||
| 1025 | #define EXTERNAL_PORT(vendor, product, num, name) \ | ||
| 1026 | PORT_INFO(vendor, product, num, name, 0, \ | ||
| 1027 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ | ||
| 1028 | SNDRV_SEQ_PORT_TYPE_HARDWARE | \ | ||
| 1029 | SNDRV_SEQ_PORT_TYPE_PORT) | ||
| 1030 | #define CONTROL_PORT(vendor, product, num, name) \ | ||
| 1031 | PORT_INFO(vendor, product, num, name, 0, \ | ||
| 1032 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ | ||
| 1033 | SNDRV_SEQ_PORT_TYPE_HARDWARE) | ||
| 1034 | #define ROLAND_SYNTH_PORT(vendor, product, num, name, voices) \ | ||
| 1035 | PORT_INFO(vendor, product, num, name, voices, \ | ||
| 1036 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ | ||
| 1037 | SNDRV_SEQ_PORT_TYPE_MIDI_GM | \ | ||
| 1038 | SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \ | ||
| 1039 | SNDRV_SEQ_PORT_TYPE_MIDI_GS | \ | ||
| 1040 | SNDRV_SEQ_PORT_TYPE_MIDI_XG | \ | ||
| 1041 | SNDRV_SEQ_PORT_TYPE_HARDWARE | \ | ||
| 1042 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) | ||
| 1043 | #define SOUNDCANVAS_PORT(vendor, product, num, name, voices) \ | ||
| 1044 | PORT_INFO(vendor, product, num, name, voices, \ | ||
| 1045 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ | ||
| 1046 | SNDRV_SEQ_PORT_TYPE_MIDI_GM | \ | ||
| 1047 | SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \ | ||
| 1048 | SNDRV_SEQ_PORT_TYPE_MIDI_GS | \ | ||
| 1049 | SNDRV_SEQ_PORT_TYPE_MIDI_XG | \ | ||
| 1050 | SNDRV_SEQ_PORT_TYPE_MIDI_MT32 | \ | ||
| 1051 | SNDRV_SEQ_PORT_TYPE_HARDWARE | \ | ||
| 1052 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) | ||
| 1018 | /* Roland UA-100 */ | 1053 | /* Roland UA-100 */ |
| 1019 | { USB_ID(0x0582, 0x0000), 2, "%s Control" }, | 1054 | CONTROL_PORT(0x0582, 0x0000, 2, "%s Control"), |
| 1020 | /* Roland SC-8850 */ | 1055 | /* Roland SC-8850 */ |
| 1021 | { USB_ID(0x0582, 0x0003), 0, "%s Part A" }, | 1056 | SOUNDCANVAS_PORT(0x0582, 0x0003, 0, "%s Part A", 128), |
| 1022 | { USB_ID(0x0582, 0x0003), 1, "%s Part B" }, | 1057 | SOUNDCANVAS_PORT(0x0582, 0x0003, 1, "%s Part B", 128), |
| 1023 | { USB_ID(0x0582, 0x0003), 2, "%s Part C" }, | 1058 | SOUNDCANVAS_PORT(0x0582, 0x0003, 2, "%s Part C", 128), |
| 1024 | { USB_ID(0x0582, 0x0003), 3, "%s Part D" }, | 1059 | SOUNDCANVAS_PORT(0x0582, 0x0003, 3, "%s Part D", 128), |
| 1025 | { USB_ID(0x0582, 0x0003), 4, "%s MIDI 1" }, | 1060 | EXTERNAL_PORT(0x0582, 0x0003, 4, "%s MIDI 1"), |
| 1026 | { USB_ID(0x0582, 0x0003), 5, "%s MIDI 2" }, | 1061 | EXTERNAL_PORT(0x0582, 0x0003, 5, "%s MIDI 2"), |
| 1027 | /* Roland U-8 */ | 1062 | /* Roland U-8 */ |
| 1028 | { USB_ID(0x0582, 0x0004), 0, "%s MIDI" }, | 1063 | EXTERNAL_PORT(0x0582, 0x0004, 0, "%s MIDI"), |
| 1029 | { USB_ID(0x0582, 0x0004), 1, "%s Control" }, | 1064 | CONTROL_PORT(0x0582, 0x0004, 1, "%s Control"), |
| 1030 | /* Roland SC-8820 */ | 1065 | /* Roland SC-8820 */ |
| 1031 | { USB_ID(0x0582, 0x0007), 0, "%s Part A" }, | 1066 | SOUNDCANVAS_PORT(0x0582, 0x0007, 0, "%s Part A", 64), |
| 1032 | { USB_ID(0x0582, 0x0007), 1, "%s Part B" }, | 1067 | SOUNDCANVAS_PORT(0x0582, 0x0007, 1, "%s Part B", 64), |
| 1033 | { USB_ID(0x0582, 0x0007), 2, "%s MIDI" }, | 1068 | EXTERNAL_PORT(0x0582, 0x0007, 2, "%s MIDI"), |
| 1034 | /* Roland SK-500 */ | 1069 | /* Roland SK-500 */ |
| 1035 | { USB_ID(0x0582, 0x000b), 0, "%s Part A" }, | 1070 | SOUNDCANVAS_PORT(0x0582, 0x000b, 0, "%s Part A", 64), |
| 1036 | { USB_ID(0x0582, 0x000b), 1, "%s Part B" }, | 1071 | SOUNDCANVAS_PORT(0x0582, 0x000b, 1, "%s Part B", 64), |
| 1037 | { USB_ID(0x0582, 0x000b), 2, "%s MIDI" }, | 1072 | EXTERNAL_PORT(0x0582, 0x000b, 2, "%s MIDI"), |
| 1038 | /* Roland SC-D70 */ | 1073 | /* Roland SC-D70 */ |
| 1039 | { USB_ID(0x0582, 0x000c), 0, "%s Part A" }, | 1074 | SOUNDCANVAS_PORT(0x0582, 0x000c, 0, "%s Part A", 64), |
| 1040 | { USB_ID(0x0582, 0x000c), 1, "%s Part B" }, | 1075 | SOUNDCANVAS_PORT(0x0582, 0x000c, 1, "%s Part B", 64), |
| 1041 | { USB_ID(0x0582, 0x000c), 2, "%s MIDI" }, | 1076 | EXTERNAL_PORT(0x0582, 0x000c, 2, "%s MIDI"), |
| 1042 | /* Edirol UM-880 */ | 1077 | /* Edirol UM-880 */ |
| 1043 | { USB_ID(0x0582, 0x0014), 8, "%s Control" }, | 1078 | CONTROL_PORT(0x0582, 0x0014, 8, "%s Control"), |
| 1044 | /* Edirol SD-90 */ | 1079 | /* Edirol SD-90 */ |
| 1045 | { USB_ID(0x0582, 0x0016), 0, "%s Part A" }, | 1080 | ROLAND_SYNTH_PORT(0x0582, 0x0016, 0, "%s Part A", 128), |
| 1046 | { USB_ID(0x0582, 0x0016), 1, "%s Part B" }, | 1081 | ROLAND_SYNTH_PORT(0x0582, 0x0016, 1, "%s Part B", 128), |
| 1047 | { USB_ID(0x0582, 0x0016), 2, "%s MIDI 1" }, | 1082 | EXTERNAL_PORT(0x0582, 0x0016, 2, "%s MIDI 1"), |
| 1048 | { USB_ID(0x0582, 0x0016), 3, "%s MIDI 2" }, | 1083 | EXTERNAL_PORT(0x0582, 0x0016, 3, "%s MIDI 2"), |
| 1049 | /* Edirol UM-550 */ | 1084 | /* Edirol UM-550 */ |
| 1050 | { USB_ID(0x0582, 0x0023), 5, "%s Control" }, | 1085 | CONTROL_PORT(0x0582, 0x0023, 5, "%s Control"), |
| 1051 | /* Edirol SD-20 */ | 1086 | /* Edirol SD-20 */ |
| 1052 | { USB_ID(0x0582, 0x0027), 0, "%s Part A" }, | 1087 | ROLAND_SYNTH_PORT(0x0582, 0x0027, 0, "%s Part A", 64), |
| 1053 | { USB_ID(0x0582, 0x0027), 1, "%s Part B" }, | 1088 | ROLAND_SYNTH_PORT(0x0582, 0x0027, 1, "%s Part B", 64), |
| 1054 | { USB_ID(0x0582, 0x0027), 2, "%s MIDI" }, | 1089 | EXTERNAL_PORT(0x0582, 0x0027, 2, "%s MIDI"), |
| 1055 | /* Edirol SD-80 */ | 1090 | /* Edirol SD-80 */ |
| 1056 | { USB_ID(0x0582, 0x0029), 0, "%s Part A" }, | 1091 | ROLAND_SYNTH_PORT(0x0582, 0x0029, 0, "%s Part A", 128), |
| 1057 | { USB_ID(0x0582, 0x0029), 1, "%s Part B" }, | 1092 | ROLAND_SYNTH_PORT(0x0582, 0x0029, 1, "%s Part B", 128), |
| 1058 | { USB_ID(0x0582, 0x0029), 2, "%s MIDI 1" }, | 1093 | EXTERNAL_PORT(0x0582, 0x0029, 2, "%s MIDI 1"), |
| 1059 | { USB_ID(0x0582, 0x0029), 3, "%s MIDI 2" }, | 1094 | EXTERNAL_PORT(0x0582, 0x0029, 3, "%s MIDI 2"), |
| 1060 | /* Edirol UA-700 */ | 1095 | /* Edirol UA-700 */ |
| 1061 | { USB_ID(0x0582, 0x002b), 0, "%s MIDI" }, | 1096 | EXTERNAL_PORT(0x0582, 0x002b, 0, "%s MIDI"), |
| 1062 | { USB_ID(0x0582, 0x002b), 1, "%s Control" }, | 1097 | CONTROL_PORT(0x0582, 0x002b, 1, "%s Control"), |
| 1063 | /* Roland VariOS */ | 1098 | /* Roland VariOS */ |
| 1064 | { USB_ID(0x0582, 0x002f), 0, "%s MIDI" }, | 1099 | EXTERNAL_PORT(0x0582, 0x002f, 0, "%s MIDI"), |
| 1065 | { USB_ID(0x0582, 0x002f), 1, "%s External MIDI" }, | 1100 | EXTERNAL_PORT(0x0582, 0x002f, 1, "%s External MIDI"), |
| 1066 | { USB_ID(0x0582, 0x002f), 2, "%s Sync" }, | 1101 | EXTERNAL_PORT(0x0582, 0x002f, 2, "%s Sync"), |
| 1067 | /* Edirol PCR */ | 1102 | /* Edirol PCR */ |
| 1068 | { USB_ID(0x0582, 0x0033), 0, "%s MIDI" }, | 1103 | EXTERNAL_PORT(0x0582, 0x0033, 0, "%s MIDI"), |
| 1069 | { USB_ID(0x0582, 0x0033), 1, "%s 1" }, | 1104 | EXTERNAL_PORT(0x0582, 0x0033, 1, "%s 1"), |
| 1070 | { USB_ID(0x0582, 0x0033), 2, "%s 2" }, | 1105 | EXTERNAL_PORT(0x0582, 0x0033, 2, "%s 2"), |
| 1071 | /* BOSS GS-10 */ | 1106 | /* BOSS GS-10 */ |
| 1072 | { USB_ID(0x0582, 0x003b), 0, "%s MIDI" }, | 1107 | EXTERNAL_PORT(0x0582, 0x003b, 0, "%s MIDI"), |
| 1073 | { USB_ID(0x0582, 0x003b), 1, "%s Control" }, | 1108 | CONTROL_PORT(0x0582, 0x003b, 1, "%s Control"), |
| 1074 | /* Edirol UA-1000 */ | 1109 | /* Edirol UA-1000 */ |
| 1075 | { USB_ID(0x0582, 0x0044), 0, "%s MIDI" }, | 1110 | EXTERNAL_PORT(0x0582, 0x0044, 0, "%s MIDI"), |
| 1076 | { USB_ID(0x0582, 0x0044), 1, "%s Control" }, | 1111 | CONTROL_PORT(0x0582, 0x0044, 1, "%s Control"), |
| 1077 | /* Edirol UR-80 */ | 1112 | /* Edirol UR-80 */ |
| 1078 | { USB_ID(0x0582, 0x0048), 0, "%s MIDI" }, | 1113 | EXTERNAL_PORT(0x0582, 0x0048, 0, "%s MIDI"), |
| 1079 | { USB_ID(0x0582, 0x0048), 1, "%s 1" }, | 1114 | EXTERNAL_PORT(0x0582, 0x0048, 1, "%s 1"), |
| 1080 | { USB_ID(0x0582, 0x0048), 2, "%s 2" }, | 1115 | EXTERNAL_PORT(0x0582, 0x0048, 2, "%s 2"), |
| 1081 | /* Edirol PCR-A */ | 1116 | /* Edirol PCR-A */ |
| 1082 | { USB_ID(0x0582, 0x004d), 0, "%s MIDI" }, | 1117 | EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"), |
| 1083 | { USB_ID(0x0582, 0x004d), 1, "%s 1" }, | 1118 | EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"), |
| 1084 | { USB_ID(0x0582, 0x004d), 2, "%s 2" }, | 1119 | EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"), |
| 1085 | /* Edirol UM-3EX */ | 1120 | /* Edirol UM-3EX */ |
| 1086 | { USB_ID(0x0582, 0x009a), 3, "%s Control" }, | 1121 | CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"), |
| 1087 | /* M-Audio MidiSport 8x8 */ | 1122 | /* M-Audio MidiSport 8x8 */ |
| 1088 | { USB_ID(0x0763, 0x1031), 8, "%s Control" }, | 1123 | CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"), |
| 1089 | { USB_ID(0x0763, 0x1033), 8, "%s Control" }, | 1124 | CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"), |
| 1090 | /* MOTU Fastlane */ | 1125 | /* MOTU Fastlane */ |
| 1091 | { USB_ID(0x07fd, 0x0001), 0, "%s MIDI A" }, | 1126 | EXTERNAL_PORT(0x07fd, 0x0001, 0, "%s MIDI A"), |
| 1092 | { USB_ID(0x07fd, 0x0001), 1, "%s MIDI B" }, | 1127 | EXTERNAL_PORT(0x07fd, 0x0001, 1, "%s MIDI B"), |
| 1093 | /* Emagic Unitor8/AMT8/MT4 */ | 1128 | /* Emagic Unitor8/AMT8/MT4 */ |
| 1094 | { USB_ID(0x086a, 0x0001), 8, "%s Broadcast" }, | 1129 | EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"), |
| 1095 | { USB_ID(0x086a, 0x0002), 8, "%s Broadcast" }, | 1130 | EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"), |
| 1096 | { USB_ID(0x086a, 0x0003), 4, "%s Broadcast" }, | 1131 | EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"), |
| 1097 | }; | 1132 | }; |
| 1098 | 1133 | ||
| 1134 | static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) | ||
| 1135 | { | ||
| 1136 | int i; | ||
| 1137 | |||
| 1138 | for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) { | ||
| 1139 | if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id && | ||
| 1140 | snd_usbmidi_port_info[i].port == number) | ||
| 1141 | return &snd_usbmidi_port_info[i]; | ||
| 1142 | } | ||
| 1143 | return NULL; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number, | ||
| 1147 | struct snd_seq_port_info *seq_port_info) | ||
| 1148 | { | ||
| 1149 | struct snd_usb_midi *umidi = rmidi->private_data; | ||
| 1150 | struct port_info *port_info; | ||
| 1151 | |||
| 1152 | /* TODO: read port flags from descriptors */ | ||
| 1153 | port_info = find_port_info(umidi, number); | ||
| 1154 | if (port_info) { | ||
| 1155 | seq_port_info->type = port_info->seq_flags; | ||
| 1156 | seq_port_info->midi_voices = port_info->voices; | ||
| 1157 | } | ||
| 1158 | } | ||
| 1159 | |||
| 1099 | static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, | 1160 | static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, |
| 1100 | int stream, int number, | 1161 | int stream, int number, |
| 1101 | struct snd_rawmidi_substream ** rsubstream) | 1162 | struct snd_rawmidi_substream ** rsubstream) |
| 1102 | { | 1163 | { |
| 1103 | int i; | 1164 | struct port_info *port_info; |
| 1104 | const char *name_format; | 1165 | const char *name_format; |
| 1105 | 1166 | ||
| 1106 | struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number); | 1167 | struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number); |
| @@ -1110,14 +1171,8 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, | |||
| 1110 | } | 1171 | } |
| 1111 | 1172 | ||
| 1112 | /* TODO: read port name from jack descriptor */ | 1173 | /* TODO: read port name from jack descriptor */ |
| 1113 | name_format = "%s MIDI %d"; | 1174 | port_info = find_port_info(umidi, number); |
| 1114 | for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) { | 1175 | name_format = port_info ? port_info->name : "%s MIDI %d"; |
| 1115 | if (snd_usbmidi_port_names[i].id == umidi->chip->usb_id && | ||
| 1116 | snd_usbmidi_port_names[i].port == number) { | ||
| 1117 | name_format = snd_usbmidi_port_names[i].name_format; | ||
| 1118 | break; | ||
| 1119 | } | ||
| 1120 | } | ||
| 1121 | snprintf(substream->name, sizeof(substream->name), | 1176 | snprintf(substream->name, sizeof(substream->name), |
| 1122 | name_format, umidi->chip->card->shortname, number + 1); | 1177 | name_format, umidi->chip->card->shortname, number + 1); |
| 1123 | 1178 | ||
| @@ -1358,7 +1413,7 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi, | |||
| 1358 | for (cs_desc = hostif->extra; | 1413 | for (cs_desc = hostif->extra; |
| 1359 | cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2; | 1414 | cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2; |
| 1360 | cs_desc += cs_desc[0]) { | 1415 | cs_desc += cs_desc[0]) { |
| 1361 | if (cs_desc[1] == CS_AUDIO_INTERFACE) { | 1416 | if (cs_desc[1] == USB_DT_CS_INTERFACE) { |
| 1362 | if (cs_desc[2] == MIDI_IN_JACK) | 1417 | if (cs_desc[2] == MIDI_IN_JACK) |
| 1363 | endpoint->in_cables = (endpoint->in_cables << 1) | 1; | 1418 | endpoint->in_cables = (endpoint->in_cables << 1) | 1; |
| 1364 | else if (cs_desc[2] == MIDI_OUT_JACK) | 1419 | else if (cs_desc[2] == MIDI_OUT_JACK) |
| @@ -1457,6 +1512,10 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi, | |||
| 1457 | return 0; | 1512 | return 0; |
| 1458 | } | 1513 | } |
| 1459 | 1514 | ||
| 1515 | static struct snd_rawmidi_global_ops snd_usbmidi_ops = { | ||
| 1516 | .get_port_info = snd_usbmidi_get_port_info, | ||
| 1517 | }; | ||
| 1518 | |||
| 1460 | static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, | 1519 | static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, |
| 1461 | int out_ports, int in_ports) | 1520 | int out_ports, int in_ports) |
| 1462 | { | 1521 | { |
| @@ -1472,6 +1531,7 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, | |||
| 1472 | rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | | 1531 | rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | |
| 1473 | SNDRV_RAWMIDI_INFO_INPUT | | 1532 | SNDRV_RAWMIDI_INFO_INPUT | |
| 1474 | SNDRV_RAWMIDI_INFO_DUPLEX; | 1533 | SNDRV_RAWMIDI_INFO_DUPLEX; |
| 1534 | rmidi->ops = &snd_usbmidi_ops; | ||
| 1475 | rmidi->private_data = umidi; | 1535 | rmidi->private_data = umidi; |
| 1476 | rmidi->private_free = snd_usbmidi_rawmidi_free; | 1536 | rmidi->private_free = snd_usbmidi_rawmidi_free; |
| 1477 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output_ops); | 1537 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output_ops); |
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index ce86283ee0fa..491e975a0c87 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
| @@ -46,6 +46,27 @@ | |||
| 46 | /* ignore error from controls - for debugging */ | 46 | /* ignore error from controls - for debugging */ |
| 47 | /* #define IGNORE_CTL_ERROR */ | 47 | /* #define IGNORE_CTL_ERROR */ |
| 48 | 48 | ||
| 49 | /* | ||
| 50 | * Sound Blaster remote control configuration | ||
| 51 | * | ||
| 52 | * format of remote control data: | ||
| 53 | * Extigy: xx 00 | ||
| 54 | * Audigy 2 NX: 06 80 xx 00 00 00 | ||
| 55 | * Live! 24-bit: 06 80 xx yy 22 83 | ||
| 56 | */ | ||
| 57 | static const struct rc_config { | ||
| 58 | u32 usb_id; | ||
| 59 | u8 offset; | ||
| 60 | u8 length; | ||
| 61 | u8 packet_length; | ||
| 62 | u8 mute_mixer_id; | ||
| 63 | u32 mute_code; | ||
| 64 | } rc_configs[] = { | ||
| 65 | { USB_ID(0x041e, 0x3000), 0, 1, 2, 18, 0x0013 }, /* Extigy */ | ||
| 66 | { USB_ID(0x041e, 0x3020), 2, 1, 6, 18, 0x0013 }, /* Audigy 2 NX */ | ||
| 67 | { USB_ID(0x041e, 0x3040), 2, 2, 6, 2, 0x6e91 }, /* Live! 24-bit */ | ||
| 68 | }; | ||
| 69 | |||
| 49 | struct usb_mixer_interface { | 70 | struct usb_mixer_interface { |
| 50 | struct snd_usb_audio *chip; | 71 | struct snd_usb_audio *chip; |
| 51 | unsigned int ctrlif; | 72 | unsigned int ctrlif; |
| @@ -55,11 +76,7 @@ struct usb_mixer_interface { | |||
| 55 | struct usb_mixer_elem_info **id_elems; /* array[256], indexed by unit id */ | 76 | struct usb_mixer_elem_info **id_elems; /* array[256], indexed by unit id */ |
| 56 | 77 | ||
| 57 | /* Sound Blaster remote control stuff */ | 78 | /* Sound Blaster remote control stuff */ |
| 58 | enum { | 79 | const struct rc_config *rc_cfg; |
| 59 | RC_NONE, | ||
| 60 | RC_EXTIGY, | ||
| 61 | RC_AUDIGY2NX, | ||
| 62 | } rc_type; | ||
| 63 | unsigned long rc_hwdep_open; | 80 | unsigned long rc_hwdep_open; |
| 64 | u32 rc_code; | 81 | u32 rc_code; |
| 65 | wait_queue_head_t rc_waitq; | 82 | wait_queue_head_t rc_waitq; |
| @@ -1647,7 +1664,7 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, | |||
| 1647 | static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, | 1664 | static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, |
| 1648 | int unitid) | 1665 | int unitid) |
| 1649 | { | 1666 | { |
| 1650 | if (mixer->rc_type == RC_NONE) | 1667 | if (!mixer->rc_cfg) |
| 1651 | return; | 1668 | return; |
| 1652 | /* unit ids specific to Extigy/Audigy 2 NX: */ | 1669 | /* unit ids specific to Extigy/Audigy 2 NX: */ |
| 1653 | switch (unitid) { | 1670 | switch (unitid) { |
| @@ -1732,20 +1749,19 @@ static void snd_usb_soundblaster_remote_complete(struct urb *urb, | |||
| 1732 | struct pt_regs *regs) | 1749 | struct pt_regs *regs) |
| 1733 | { | 1750 | { |
| 1734 | struct usb_mixer_interface *mixer = urb->context; | 1751 | struct usb_mixer_interface *mixer = urb->context; |
| 1735 | /* | 1752 | const struct rc_config *rc = mixer->rc_cfg; |
| 1736 | * format of remote control data: | ||
| 1737 | * Extigy: xx 00 | ||
| 1738 | * Audigy 2 NX: 06 80 xx 00 00 00 | ||
| 1739 | */ | ||
| 1740 | int offset = mixer->rc_type == RC_EXTIGY ? 0 : 2; | ||
| 1741 | u32 code; | 1753 | u32 code; |
| 1742 | 1754 | ||
| 1743 | if (urb->status < 0 || urb->actual_length <= offset) | 1755 | if (urb->status < 0 || urb->actual_length < rc->packet_length) |
| 1744 | return; | 1756 | return; |
| 1745 | code = mixer->rc_buffer[offset]; | 1757 | |
| 1758 | code = mixer->rc_buffer[rc->offset]; | ||
| 1759 | if (rc->length == 2) | ||
| 1760 | code |= mixer->rc_buffer[rc->offset + 1] << 8; | ||
| 1761 | |||
| 1746 | /* the Mute button actually changes the mixer control */ | 1762 | /* the Mute button actually changes the mixer control */ |
| 1747 | if (code == 13) | 1763 | if (code == rc->mute_code) |
| 1748 | snd_usb_mixer_notify_id(mixer, 18); | 1764 | snd_usb_mixer_notify_id(mixer, rc->mute_mixer_id); |
| 1749 | mixer->rc_code = code; | 1765 | mixer->rc_code = code; |
| 1750 | wmb(); | 1766 | wmb(); |
| 1751 | wake_up(&mixer->rc_waitq); | 1767 | wake_up(&mixer->rc_waitq); |
| @@ -1801,21 +1817,17 @@ static unsigned int snd_usb_sbrc_hwdep_poll(struct snd_hwdep *hw, struct file *f | |||
| 1801 | static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) | 1817 | static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) |
| 1802 | { | 1818 | { |
| 1803 | struct snd_hwdep *hwdep; | 1819 | struct snd_hwdep *hwdep; |
| 1804 | int err, len; | 1820 | int err, len, i; |
| 1805 | 1821 | ||
| 1806 | switch (mixer->chip->usb_id) { | 1822 | for (i = 0; i < ARRAY_SIZE(rc_configs); ++i) |
| 1807 | case USB_ID(0x041e, 0x3000): | 1823 | if (rc_configs[i].usb_id == mixer->chip->usb_id) |
| 1808 | mixer->rc_type = RC_EXTIGY; | 1824 | break; |
| 1809 | len = 2; | 1825 | if (i >= ARRAY_SIZE(rc_configs)) |
| 1810 | break; | ||
| 1811 | case USB_ID(0x041e, 0x3020): | ||
| 1812 | mixer->rc_type = RC_AUDIGY2NX; | ||
| 1813 | len = 6; | ||
| 1814 | break; | ||
| 1815 | default: | ||
| 1816 | return 0; | 1826 | return 0; |
| 1817 | } | 1827 | mixer->rc_cfg = &rc_configs[i]; |
| 1818 | 1828 | ||
| 1829 | len = mixer->rc_cfg->packet_length; | ||
| 1830 | |||
| 1819 | init_waitqueue_head(&mixer->rc_waitq); | 1831 | init_waitqueue_head(&mixer->rc_waitq); |
| 1820 | err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); | 1832 | err = snd_hwdep_new(mixer->chip->card, "SB remote control", 0, &hwdep); |
| 1821 | if (err < 0) | 1833 | if (err < 0) |
| @@ -1998,7 +2010,7 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif) | |||
| 1998 | if ((err = snd_audigy2nx_controls_create(mixer)) < 0) | 2010 | if ((err = snd_audigy2nx_controls_create(mixer)) < 0) |
| 1999 | goto _error; | 2011 | goto _error; |
| 2000 | if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) | 2012 | if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) |
| 2001 | snd_info_set_text_ops(entry, mixer, 1024, | 2013 | snd_info_set_text_ops(entry, mixer, |
| 2002 | snd_audigy2nx_proc_read); | 2014 | snd_audigy2nx_proc_read); |
| 2003 | } | 2015 | } |
| 2004 | 2016 | ||
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index fe67a92e2a1a..88b72b52590f 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c | |||
| @@ -632,7 +632,7 @@ static int usX2Y_pcms_lock_check(struct snd_card *card) | |||
| 632 | for (s = 0; s < 2; ++s) { | 632 | for (s = 0; s < 2; ++s) { |
| 633 | struct snd_pcm_substream *substream; | 633 | struct snd_pcm_substream *substream; |
| 634 | substream = pcm->streams[s].substream; | 634 | substream = pcm->streams[s].substream; |
| 635 | if (substream && substream->ffile != NULL) | 635 | if (SUBSTREAM_BUSY(substream)) |
| 636 | err = -EBUSY; | 636 | err = -EBUSY; |
| 637 | } | 637 | } |
| 638 | } | 638 | } |
