diff options
354 files changed, 14416 insertions, 5662 deletions
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/pci.txt b/Documentation/pci.txt index 66bbbf1d1ef6..3242e5c1ee9c 100644 --- a/Documentation/pci.txt +++ b/Documentation/pci.txt | |||
| @@ -213,9 +213,17 @@ have been remapped by the kernel. | |||
| 213 | 213 | ||
| 214 | See Documentation/IO-mapping.txt for how to access device memory. | 214 | See Documentation/IO-mapping.txt for how to access device memory. |
| 215 | 215 | ||
| 216 | You still need to call request_region() for I/O regions and | 216 | The device driver needs to call pci_request_region() to make sure |
| 217 | request_mem_region() for memory regions to make sure nobody else is using the | 217 | no other device is already using the same resource. The driver is expected |
| 218 | same device. | 218 | to determine MMIO and IO Port resource availability _before_ calling |
| 219 | pci_enable_device(). Conversely, drivers should call pci_release_region() | ||
| 220 | _after_ calling pci_disable_device(). The idea is to prevent two devices | ||
| 221 | colliding on the same address range. | ||
| 222 | |||
| 223 | Generic flavors of pci_request_region() are request_mem_region() | ||
| 224 | (for MMIO ranges) and request_region() (for IO Port ranges). | ||
| 225 | Use these for address resources that are not described by "normal" PCI | ||
| 226 | interfaces (e.g. BAR). | ||
| 219 | 227 | ||
| 220 | All interrupt handlers should be registered with SA_SHIRQ and use the devid | 228 | All interrupt handlers should be registered with SA_SHIRQ and use the devid |
| 221 | to map IRQs to devices (remember that all PCI interrupts are shared). | 229 | to map IRQs to devices (remember that all PCI interrupts are shared). |
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/w1/masters/ds2490 b/Documentation/w1/masters/ds2490 new file mode 100644 index 000000000000..44a4918bd7f2 --- /dev/null +++ b/Documentation/w1/masters/ds2490 | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | Kernel driver ds2490 | ||
| 2 | ==================== | ||
| 3 | |||
| 4 | Supported chips: | ||
| 5 | * Maxim DS2490 based | ||
| 6 | |||
| 7 | Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru> | ||
| 8 | |||
| 9 | |||
| 10 | Description | ||
| 11 | ----------- | ||
| 12 | |||
| 13 | The Maixm/Dallas Semiconductor DS2490 is a chip | ||
| 14 | which allows to build USB <-> W1 bridges. | ||
| 15 | |||
| 16 | DS9490(R) is a USB <-> W1 bus master device | ||
| 17 | which has 0x81 family ID integrated chip and DS2490 | ||
| 18 | low-level operational chip. | ||
diff --git a/Documentation/w1/w1.generic b/Documentation/w1/w1.generic index f937fbe1cacb..4c6509dd4789 100644 --- a/Documentation/w1/w1.generic +++ b/Documentation/w1/w1.generic | |||
| @@ -27,8 +27,19 @@ When a w1 master driver registers with the w1 subsystem, the following occurs: | |||
| 27 | 27 | ||
| 28 | When a device is found on the bus, w1 core checks if driver for it's family is | 28 | When a device is found on the bus, w1 core checks if driver for it's family is |
| 29 | loaded. If so, the family driver is attached to the slave. | 29 | loaded. If so, the family driver is attached to the slave. |
| 30 | If there is no driver for the family, a simple sysfs entry is created | 30 | If there is no driver for the family, default one is assigned, which allows to perform |
| 31 | for the slave device. | 31 | almost any kind of operations. Each logical operation is a transaction |
| 32 | in nature, which can contain several (two or one) low-level operations. | ||
| 33 | Let's see how one can read EEPROM context: | ||
| 34 | 1. one must write control buffer, i.e. buffer containing command byte | ||
| 35 | and two byte address. At this step bus is reset and appropriate device | ||
| 36 | is selected using either W1_SKIP_ROM or W1_MATCH_ROM command. | ||
| 37 | Then provided control buffer is being written to the wire. | ||
| 38 | 2. reading. This will issue reading eeprom response. | ||
| 39 | |||
| 40 | It is possible that between 1. and 2. w1 master thread will reset bus for searching | ||
| 41 | and slave device will be even removed, but in this case 0xff will | ||
| 42 | be read, since no device was selected. | ||
| 32 | 43 | ||
| 33 | 44 | ||
| 34 | W1 device families | 45 | W1 device families |
| @@ -89,4 +100,5 @@ driver - (standard) symlink to the w1 driver | |||
| 89 | name - the device name, usually the same as the directory name | 100 | name - the device name, usually the same as the directory name |
| 90 | w1_slave - (optional) a binary file whose meaning depends on the | 101 | w1_slave - (optional) a binary file whose meaning depends on the |
| 91 | family driver | 102 | family driver |
| 92 | 103 | rw - (optional) created for slave devices which do not have | |
| 104 | appropriate family driver. Allows to read/write binary data. | ||
diff --git a/Documentation/w1/w1.netlink b/Documentation/w1/w1.netlink new file mode 100644 index 000000000000..3640c7c87d45 --- /dev/null +++ b/Documentation/w1/w1.netlink | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | Userspace communication protocol over connector [1]. | ||
| 2 | |||
| 3 | |||
| 4 | Message types. | ||
| 5 | ============= | ||
| 6 | |||
| 7 | There are three types of messages between w1 core and userspace: | ||
| 8 | 1. Events. They are generated each time new master or slave device found | ||
| 9 | either due to automatic or requested search. | ||
| 10 | 2. Userspace commands. Includes read/write and search/alarm search comamnds. | ||
| 11 | 3. Replies to userspace commands. | ||
| 12 | |||
| 13 | |||
| 14 | Protocol. | ||
| 15 | ======== | ||
| 16 | |||
| 17 | [struct cn_msg] - connector header. It's length field is equal to size of the attached data. | ||
| 18 | [struct w1_netlink_msg] - w1 netlink header. | ||
| 19 | __u8 type - message type. | ||
| 20 | W1_SLAVE_ADD/W1_SLAVE_REMOVE - slave add/remove events. | ||
| 21 | W1_MASTER_ADD/W1_MASTER_REMOVE - master add/remove events. | ||
| 22 | W1_MASTER_CMD - userspace command for bus master device (search/alarm search). | ||
| 23 | W1_SLAVE_CMD - userspace command for slave device (read/write/ search/alarm search | ||
| 24 | for bus master device where given slave device found). | ||
| 25 | __u8 res - reserved | ||
| 26 | __u16 len - size of attached to this header data. | ||
| 27 | union { | ||
| 28 | __u8 id; - slave unique device id | ||
| 29 | struct w1_mst { | ||
| 30 | __u32 id; - master's id. | ||
| 31 | __u32 res; - reserved | ||
| 32 | } mst; | ||
| 33 | } id; | ||
| 34 | |||
| 35 | [strucrt w1_netlink_cmd] - command for gived master or slave device. | ||
| 36 | __u8 cmd - command opcode. | ||
| 37 | W1_CMD_READ - read command. | ||
| 38 | W1_CMD_WRITE - write command. | ||
| 39 | W1_CMD_SEARCH - search command. | ||
| 40 | W1_CMD_ALARM_SEARCH - alarm search command. | ||
| 41 | __u8 res - reserved | ||
| 42 | __u16 len - length of data for this command. | ||
| 43 | For read command data must be allocated like for write command. | ||
| 44 | __u8 data[0] - data for this command. | ||
| 45 | |||
| 46 | |||
| 47 | Each connector message can include one or more w1_netlink_msg with zero of more attached w1_netlink_cmd messages. | ||
| 48 | |||
| 49 | For event messages there are no w1_netlink_cmd embedded structures, only connector header | ||
| 50 | and w1_netlink_msg strucutre with "len" field being zero and filled type (one of event types) | ||
| 51 | and id - either 8 bytes of slave unique id in host order, or master's id, which is assigned | ||
| 52 | to bus master device when it is added to w1 core. | ||
| 53 | |||
| 54 | Currently replies to userspace commands are only generated for read command request. | ||
| 55 | One reply is generated exactly for one w1_netlink_cmd read request. | ||
| 56 | Replies are not combined when sent - i.e. typical reply messages looks like the following: | ||
| 57 | [cn_msg][w1_netlink_msg][w1_netlink_cmd] | ||
| 58 | cn_msg.len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; | ||
| 59 | w1_netlink_msg.len = sizeof(struct w1_netlink_cmd) + cmd->len; | ||
| 60 | w1_netlink_cmd.len = cmd->len; | ||
| 61 | |||
| 62 | |||
| 63 | Operation steps in w1 core when new command is received. | ||
| 64 | ======================================================= | ||
| 65 | |||
| 66 | When new message (w1_netlink_msg) is received w1 core detects if it is master of slave request, | ||
| 67 | according to w1_netlink_msg.type field. | ||
| 68 | Then master or slave device is searched for. | ||
| 69 | When found, master device (requested or those one on where slave device is found) is locked. | ||
| 70 | If slave command is requested, then reset/select procedure is started to select given device. | ||
| 71 | |||
| 72 | Then all requested in w1_netlink_msg operations are performed one by one. | ||
| 73 | If command requires reply (like read command) it is sent on command completion. | ||
| 74 | |||
| 75 | When all commands (w1_netlink_cmd) are processed muster device is unlocked | ||
| 76 | and next w1_netlink_msg header processing started. | ||
| 77 | |||
| 78 | |||
| 79 | Connector [1] specific documentation. | ||
| 80 | ==================================== | ||
| 81 | |||
| 82 | Each connector message includes two u32 fields as "address". | ||
| 83 | w1 uses CN_W1_IDX and CN_W1_VAL defined in include/linux/connector.h header. | ||
| 84 | Each message also includes sequence and acknowledge numbers. | ||
| 85 | Sequence number for event messages is appropriate bus master sequence number increased with | ||
| 86 | each event message sent "through" this master. | ||
| 87 | Sequence number for userspace requests is set by userspace application. | ||
| 88 | Sequence number for reply is the same as was in request, and | ||
| 89 | acknowledge number is set to seq+1. | ||
| 90 | |||
| 91 | |||
| 92 | Additional documantion, source code examples. | ||
| 93 | ============================================ | ||
| 94 | |||
| 95 | 1. Documentation/connector | ||
| 96 | 2. http://tservice.net.ru/~s0mbre/archive/w1 | ||
| 97 | This archive includes userspace application w1d.c which | ||
| 98 | uses read/write/search commands for all master/slave devices found on the bus. | ||
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 40e5aba3ad3d..fbe93084244c 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c | |||
| @@ -202,6 +202,8 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) | |||
| 202 | if (mcfg->config[i].base_reserved) { | 202 | if (mcfg->config[i].base_reserved) { |
| 203 | printk(KERN_ERR PREFIX | 203 | printk(KERN_ERR PREFIX |
| 204 | "MMCONFIG not in low 4GB of memory\n"); | 204 | "MMCONFIG not in low 4GB of memory\n"); |
| 205 | kfree(pci_mmcfg_config); | ||
| 206 | pci_mmcfg_config_num = 0; | ||
| 205 | return -ENODEV; | 207 | return -ENODEV; |
| 206 | } | 208 | } |
| 207 | } | 209 | } |
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c index dbece776c5b2..c624b61e1104 100644 --- a/arch/i386/pci/common.c +++ b/arch/i386/pci/common.c | |||
| @@ -288,6 +288,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) | |||
| 288 | 288 | ||
| 289 | void pcibios_disable_device (struct pci_dev *dev) | 289 | void pcibios_disable_device (struct pci_dev *dev) |
| 290 | { | 290 | { |
| 291 | pcibios_disable_resources(dev); | ||
| 291 | if (pcibios_disable_irq) | 292 | if (pcibios_disable_irq) |
| 292 | pcibios_disable_irq(dev); | 293 | pcibios_disable_irq(dev); |
| 293 | } | 294 | } |
diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c index ed2c8c899bd3..7852827a599b 100644 --- a/arch/i386/pci/i386.c +++ b/arch/i386/pci/i386.c | |||
| @@ -242,6 +242,15 @@ int pcibios_enable_resources(struct pci_dev *dev, int mask) | |||
| 242 | return 0; | 242 | return 0; |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | void pcibios_disable_resources(struct pci_dev *dev) | ||
| 246 | { | ||
| 247 | u16 cmd; | ||
| 248 | |||
| 249 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
| 250 | cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); | ||
| 251 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
| 252 | } | ||
| 253 | |||
| 245 | /* | 254 | /* |
| 246 | * If we set up a device for bus mastering, we need to check the latency | 255 | * If we set up a device for bus mastering, we need to check the latency |
| 247 | * timer as certain crappy BIOSes forget to set it properly. | 256 | * timer as certain crappy BIOSes forget to set it properly. |
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index 6b1ea0c9a570..e545b0992c48 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c | |||
| @@ -15,7 +15,9 @@ | |||
| 15 | #include <asm/e820.h> | 15 | #include <asm/e820.h> |
| 16 | #include "pci.h" | 16 | #include "pci.h" |
| 17 | 17 | ||
| 18 | #define MMCONFIG_APER_SIZE (256*1024*1024) | 18 | /* aperture is up to 256MB but BIOS may reserve less */ |
| 19 | #define MMCONFIG_APER_MIN (2 * 1024*1024) | ||
| 20 | #define MMCONFIG_APER_MAX (256 * 1024*1024) | ||
| 19 | 21 | ||
| 20 | /* Assume systems with more busses have correct MCFG */ | 22 | /* Assume systems with more busses have correct MCFG */ |
| 21 | #define MAX_CHECK_BUS 16 | 23 | #define MAX_CHECK_BUS 16 |
| @@ -197,9 +199,10 @@ void __init pci_mmcfg_init(void) | |||
| 197 | return; | 199 | return; |
| 198 | 200 | ||
| 199 | if (!e820_all_mapped(pci_mmcfg_config[0].base_address, | 201 | if (!e820_all_mapped(pci_mmcfg_config[0].base_address, |
| 200 | pci_mmcfg_config[0].base_address + MMCONFIG_APER_SIZE, | 202 | pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN, |
| 201 | E820_RESERVED)) { | 203 | E820_RESERVED)) { |
| 202 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area is not E820-reserved\n"); | 204 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n", |
| 205 | pci_mmcfg_config[0].base_address); | ||
| 203 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | 206 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); |
| 204 | return; | 207 | return; |
| 205 | } | 208 | } |
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h index 12035e29108b..12bf3d8dda29 100644 --- a/arch/i386/pci/pci.h +++ b/arch/i386/pci/pci.h | |||
| @@ -35,6 +35,7 @@ extern unsigned int pcibios_max_latency; | |||
| 35 | 35 | ||
| 36 | void pcibios_resource_survey(void); | 36 | void pcibios_resource_survey(void); |
| 37 | int pcibios_enable_resources(struct pci_dev *, int); | 37 | int pcibios_enable_resources(struct pci_dev *, int); |
| 38 | void pcibios_disable_resources(struct pci_dev *); | ||
| 38 | 39 | ||
| 39 | /* pci-pc.c */ | 40 | /* pci-pc.c */ |
| 40 | 41 | ||
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 6c4d59fd0364..ef9a2b49307a 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c | |||
| @@ -46,6 +46,10 @@ | |||
| 46 | 46 | ||
| 47 | #define IRQ_DEBUG 0 | 47 | #define IRQ_DEBUG 0 |
| 48 | 48 | ||
| 49 | /* These can be overridden in platform_irq_init */ | ||
| 50 | int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR; | ||
| 51 | int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR; | ||
| 52 | |||
| 49 | /* default base addr of IPI table */ | 53 | /* default base addr of IPI table */ |
| 50 | void __iomem *ipi_base_addr = ((void __iomem *) | 54 | void __iomem *ipi_base_addr = ((void __iomem *) |
| 51 | (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR)); | 55 | (__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR)); |
| @@ -60,7 +64,7 @@ __u8 isa_irq_to_vector_map[16] = { | |||
| 60 | }; | 64 | }; |
| 61 | EXPORT_SYMBOL(isa_irq_to_vector_map); | 65 | EXPORT_SYMBOL(isa_irq_to_vector_map); |
| 62 | 66 | ||
| 63 | static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)]; | 67 | static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)]; |
| 64 | 68 | ||
| 65 | int | 69 | int |
| 66 | assign_irq_vector (int irq) | 70 | assign_irq_vector (int irq) |
| @@ -89,6 +93,19 @@ free_irq_vector (int vector) | |||
| 89 | printk(KERN_WARNING "%s: double free!\n", __FUNCTION__); | 93 | printk(KERN_WARNING "%s: double free!\n", __FUNCTION__); |
| 90 | } | 94 | } |
| 91 | 95 | ||
| 96 | int | ||
| 97 | reserve_irq_vector (int vector) | ||
| 98 | { | ||
| 99 | int pos; | ||
| 100 | |||
| 101 | if (vector < IA64_FIRST_DEVICE_VECTOR || | ||
| 102 | vector > IA64_LAST_DEVICE_VECTOR) | ||
| 103 | return -EINVAL; | ||
| 104 | |||
| 105 | pos = vector - IA64_FIRST_DEVICE_VECTOR; | ||
| 106 | return test_and_set_bit(pos, ia64_vector_mask); | ||
| 107 | } | ||
| 108 | |||
| 92 | #ifdef CONFIG_SMP | 109 | #ifdef CONFIG_SMP |
| 93 | # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE) | 110 | # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE) |
| 94 | #else | 111 | #else |
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 5101ac462643..dc09a6a28a37 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c | |||
| @@ -58,7 +58,7 @@ static int max_pcibus_number = 255; /* Default highest pci bus number */ | |||
| 58 | */ | 58 | */ |
| 59 | 59 | ||
| 60 | static dma_addr_t | 60 | static dma_addr_t |
| 61 | sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size) | 61 | sn_default_pci_map(struct pci_dev *pdev, unsigned long paddr, size_t size, int type) |
| 62 | { | 62 | { |
| 63 | return 0; | 63 | return 0; |
| 64 | } | 64 | } |
| @@ -457,13 +457,6 @@ void sn_pci_fixup_slot(struct pci_dev *dev) | |||
| 457 | pcidev_info->pdi_sn_irq_info = NULL; | 457 | pcidev_info->pdi_sn_irq_info = NULL; |
| 458 | kfree(sn_irq_info); | 458 | kfree(sn_irq_info); |
| 459 | } | 459 | } |
| 460 | |||
| 461 | /* | ||
| 462 | * MSI currently not supported on altix. Remove this when | ||
| 463 | * the MSI abstraction patches are integrated into the kernel | ||
| 464 | * (sometime after 2.6.16 releases) | ||
| 465 | */ | ||
| 466 | dev->no_msi = 1; | ||
| 467 | } | 460 | } |
| 468 | 461 | ||
| 469 | /* | 462 | /* |
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c index c265e02f5036..dc8e2b696713 100644 --- a/arch/ia64/sn/kernel/irq.c +++ b/arch/ia64/sn/kernel/irq.c | |||
| @@ -26,11 +26,11 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info); | |||
| 26 | 26 | ||
| 27 | int sn_force_interrupt_flag = 1; | 27 | int sn_force_interrupt_flag = 1; |
| 28 | extern int sn_ioif_inited; | 28 | extern int sn_ioif_inited; |
| 29 | static struct list_head **sn_irq_lh; | 29 | struct list_head **sn_irq_lh; |
| 30 | static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */ | 30 | static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */ |
| 31 | 31 | ||
| 32 | static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, | 32 | u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, |
| 33 | u64 sn_irq_info, | 33 | struct sn_irq_info *sn_irq_info, |
| 34 | int req_irq, nasid_t req_nasid, | 34 | int req_irq, nasid_t req_nasid, |
| 35 | int req_slice) | 35 | int req_slice) |
| 36 | { | 36 | { |
| @@ -40,12 +40,13 @@ static inline u64 sn_intr_alloc(nasid_t local_nasid, int local_widget, | |||
| 40 | 40 | ||
| 41 | SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT, | 41 | SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_INTERRUPT, |
| 42 | (u64) SAL_INTR_ALLOC, (u64) local_nasid, | 42 | (u64) SAL_INTR_ALLOC, (u64) local_nasid, |
| 43 | (u64) local_widget, (u64) sn_irq_info, (u64) req_irq, | 43 | (u64) local_widget, __pa(sn_irq_info), (u64) req_irq, |
| 44 | (u64) req_nasid, (u64) req_slice); | 44 | (u64) req_nasid, (u64) req_slice); |
| 45 | |||
| 45 | return ret_stuff.status; | 46 | return ret_stuff.status; |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | static inline void sn_intr_free(nasid_t local_nasid, int local_widget, | 49 | void sn_intr_free(nasid_t local_nasid, int local_widget, |
| 49 | struct sn_irq_info *sn_irq_info) | 50 | struct sn_irq_info *sn_irq_info) |
| 50 | { | 51 | { |
| 51 | struct ia64_sal_retval ret_stuff; | 52 | struct ia64_sal_retval ret_stuff; |
| @@ -112,73 +113,91 @@ static void sn_end_irq(unsigned int irq) | |||
| 112 | 113 | ||
| 113 | static void sn_irq_info_free(struct rcu_head *head); | 114 | static void sn_irq_info_free(struct rcu_head *head); |
| 114 | 115 | ||
| 115 | static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) | 116 | struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *sn_irq_info, |
| 117 | nasid_t nasid, int slice) | ||
| 116 | { | 118 | { |
| 117 | struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; | 119 | int vector; |
| 118 | int cpuid, cpuphys; | 120 | int cpuphys; |
| 121 | int64_t bridge; | ||
| 122 | int local_widget, status; | ||
| 123 | nasid_t local_nasid; | ||
| 124 | struct sn_irq_info *new_irq_info; | ||
| 125 | struct sn_pcibus_provider *pci_provider; | ||
| 119 | 126 | ||
| 120 | cpuid = first_cpu(mask); | 127 | new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); |
| 121 | cpuphys = cpu_physical_id(cpuid); | 128 | if (new_irq_info == NULL) |
| 129 | return NULL; | ||
| 122 | 130 | ||
| 123 | list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe, | 131 | memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info)); |
| 124 | sn_irq_lh[irq], list) { | 132 | |
| 125 | u64 bridge; | 133 | bridge = (u64) new_irq_info->irq_bridge; |
| 126 | int local_widget, status; | 134 | if (!bridge) { |
| 127 | nasid_t local_nasid; | 135 | kfree(new_irq_info); |
| 128 | struct sn_irq_info *new_irq_info; | 136 | return NULL; /* irq is not a device interrupt */ |
| 129 | struct sn_pcibus_provider *pci_provider; | 137 | } |
| 130 | |||
| 131 | new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC); | ||
| 132 | if (new_irq_info == NULL) | ||
| 133 | break; | ||
| 134 | memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info)); | ||
| 135 | |||
| 136 | bridge = (u64) new_irq_info->irq_bridge; | ||
| 137 | if (!bridge) { | ||
| 138 | kfree(new_irq_info); | ||
| 139 | break; /* irq is not a device interrupt */ | ||
| 140 | } | ||
| 141 | 138 | ||
| 142 | local_nasid = NASID_GET(bridge); | 139 | local_nasid = NASID_GET(bridge); |
| 143 | 140 | ||
| 144 | if (local_nasid & 1) | 141 | if (local_nasid & 1) |
| 145 | local_widget = TIO_SWIN_WIDGETNUM(bridge); | 142 | local_widget = TIO_SWIN_WIDGETNUM(bridge); |
| 146 | else | 143 | else |
| 147 | local_widget = SWIN_WIDGETNUM(bridge); | 144 | local_widget = SWIN_WIDGETNUM(bridge); |
| 148 | 145 | ||
| 149 | /* Free the old PROM new_irq_info structure */ | 146 | vector = sn_irq_info->irq_irq; |
| 150 | sn_intr_free(local_nasid, local_widget, new_irq_info); | 147 | /* Free the old PROM new_irq_info structure */ |
| 151 | /* Update kernels new_irq_info with new target info */ | 148 | sn_intr_free(local_nasid, local_widget, new_irq_info); |
| 152 | unregister_intr_pda(new_irq_info); | 149 | /* Update kernels new_irq_info with new target info */ |
| 150 | unregister_intr_pda(new_irq_info); | ||
| 153 | 151 | ||
| 154 | /* allocate a new PROM new_irq_info struct */ | 152 | /* allocate a new PROM new_irq_info struct */ |
| 155 | status = sn_intr_alloc(local_nasid, local_widget, | 153 | status = sn_intr_alloc(local_nasid, local_widget, |
| 156 | __pa(new_irq_info), irq, | 154 | new_irq_info, vector, |
| 157 | cpuid_to_nasid(cpuid), | 155 | nasid, slice); |
| 158 | cpuid_to_slice(cpuid)); | ||
| 159 | 156 | ||
| 160 | /* SAL call failed */ | 157 | /* SAL call failed */ |
| 161 | if (status) { | 158 | if (status) { |
| 162 | kfree(new_irq_info); | 159 | kfree(new_irq_info); |
| 163 | break; | 160 | return NULL; |
| 164 | } | 161 | } |
| 165 | 162 | ||
| 166 | new_irq_info->irq_cpuid = cpuid; | 163 | cpuphys = nasid_slice_to_cpuid(nasid, slice); |
| 167 | register_intr_pda(new_irq_info); | 164 | new_irq_info->irq_cpuid = cpuphys; |
| 165 | register_intr_pda(new_irq_info); | ||
| 168 | 166 | ||
| 169 | pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; | 167 | pci_provider = sn_pci_provider[new_irq_info->irq_bridge_type]; |
| 170 | if (pci_provider && pci_provider->target_interrupt) | ||
| 171 | (pci_provider->target_interrupt)(new_irq_info); | ||
| 172 | 168 | ||
| 173 | spin_lock(&sn_irq_info_lock); | 169 | /* |
| 174 | list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); | 170 | * If this represents a line interrupt, target it. If it's |
| 175 | spin_unlock(&sn_irq_info_lock); | 171 | * an msi (irq_int_bit < 0), it's already targeted. |
| 176 | call_rcu(&sn_irq_info->rcu, sn_irq_info_free); | 172 | */ |
| 173 | if (new_irq_info->irq_int_bit >= 0 && | ||
| 174 | pci_provider && pci_provider->target_interrupt) | ||
| 175 | (pci_provider->target_interrupt)(new_irq_info); | ||
| 176 | |||
| 177 | spin_lock(&sn_irq_info_lock); | ||
| 178 | list_replace_rcu(&sn_irq_info->list, &new_irq_info->list); | ||
| 179 | spin_unlock(&sn_irq_info_lock); | ||
| 180 | call_rcu(&sn_irq_info->rcu, sn_irq_info_free); | ||
| 177 | 181 | ||
| 178 | #ifdef CONFIG_SMP | 182 | #ifdef CONFIG_SMP |
| 179 | set_irq_affinity_info((irq & 0xff), cpuphys, 0); | 183 | set_irq_affinity_info((vector & 0xff), cpuphys, 0); |
| 180 | #endif | 184 | #endif |
| 181 | } | 185 | |
| 186 | return new_irq_info; | ||
| 187 | } | ||
| 188 | |||
| 189 | static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask) | ||
| 190 | { | ||
| 191 | struct sn_irq_info *sn_irq_info, *sn_irq_info_safe; | ||
| 192 | nasid_t nasid; | ||
| 193 | int slice; | ||
| 194 | |||
| 195 | nasid = cpuid_to_nasid(first_cpu(mask)); | ||
| 196 | slice = cpuid_to_slice(first_cpu(mask)); | ||
| 197 | |||
| 198 | list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe, | ||
| 199 | sn_irq_lh[irq], list) | ||
| 200 | (void)sn_retarget_vector(sn_irq_info, nasid, slice); | ||
| 182 | } | 201 | } |
| 183 | 202 | ||
| 184 | struct hw_interrupt_type irq_type_sn = { | 203 | struct hw_interrupt_type irq_type_sn = { |
| @@ -202,6 +221,9 @@ void sn_irq_init(void) | |||
| 202 | int i; | 221 | int i; |
| 203 | irq_desc_t *base_desc = irq_desc; | 222 | irq_desc_t *base_desc = irq_desc; |
| 204 | 223 | ||
| 224 | ia64_first_device_vector = IA64_SN2_FIRST_DEVICE_VECTOR; | ||
| 225 | ia64_last_device_vector = IA64_SN2_LAST_DEVICE_VECTOR; | ||
| 226 | |||
| 205 | for (i = 0; i < NR_IRQS; i++) { | 227 | for (i = 0; i < NR_IRQS; i++) { |
| 206 | if (base_desc[i].handler == &no_irq_type) { | 228 | if (base_desc[i].handler == &no_irq_type) { |
| 207 | base_desc[i].handler = &irq_type_sn; | 229 | base_desc[i].handler = &irq_type_sn; |
| @@ -285,6 +307,7 @@ void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info) | |||
| 285 | /* link it into the sn_irq[irq] list */ | 307 | /* link it into the sn_irq[irq] list */ |
| 286 | spin_lock(&sn_irq_info_lock); | 308 | spin_lock(&sn_irq_info_lock); |
| 287 | list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]); | 309 | list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]); |
| 310 | reserve_irq_vector(sn_irq_info->irq_irq); | ||
| 288 | spin_unlock(&sn_irq_info_lock); | 311 | spin_unlock(&sn_irq_info_lock); |
| 289 | 312 | ||
| 290 | register_intr_pda(sn_irq_info); | 313 | register_intr_pda(sn_irq_info); |
| @@ -310,8 +333,11 @@ void sn_irq_unfixup(struct pci_dev *pci_dev) | |||
| 310 | spin_lock(&sn_irq_info_lock); | 333 | spin_lock(&sn_irq_info_lock); |
| 311 | list_del_rcu(&sn_irq_info->list); | 334 | list_del_rcu(&sn_irq_info->list); |
| 312 | spin_unlock(&sn_irq_info_lock); | 335 | spin_unlock(&sn_irq_info_lock); |
| 336 | if (list_empty(sn_irq_lh[sn_irq_info->irq_irq])) | ||
| 337 | free_irq_vector(sn_irq_info->irq_irq); | ||
| 313 | call_rcu(&sn_irq_info->rcu, sn_irq_info_free); | 338 | call_rcu(&sn_irq_info->rcu, sn_irq_info_free); |
| 314 | pci_dev_put(pci_dev); | 339 | pci_dev_put(pci_dev); |
| 340 | |||
| 315 | } | 341 | } |
| 316 | 342 | ||
| 317 | static inline void | 343 | static inline void |
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index b4b84c269210..7a291a271511 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <asm/dma.h> | 13 | #include <asm/dma.h> |
| 14 | #include <asm/sn/pcibr_provider.h> | 14 | #include <asm/sn/intr.h> |
| 15 | #include <asm/sn/pcibus_provider_defs.h> | 15 | #include <asm/sn/pcibus_provider_defs.h> |
| 16 | #include <asm/sn/pcidev.h> | 16 | #include <asm/sn/pcidev.h> |
| 17 | #include <asm/sn/sn_sal.h> | 17 | #include <asm/sn/sn_sal.h> |
| @@ -113,7 +113,8 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size, | |||
| 113 | * resources. | 113 | * resources. |
| 114 | */ | 114 | */ |
| 115 | 115 | ||
| 116 | *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size); | 116 | *dma_handle = provider->dma_map_consistent(pdev, phys_addr, size, |
| 117 | SN_DMA_ADDR_PHYS); | ||
| 117 | if (!*dma_handle) { | 118 | if (!*dma_handle) { |
| 118 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); | 119 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); |
| 119 | free_pages((unsigned long)cpuaddr, get_order(size)); | 120 | free_pages((unsigned long)cpuaddr, get_order(size)); |
| @@ -176,7 +177,7 @@ dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size, | |||
| 176 | BUG_ON(dev->bus != &pci_bus_type); | 177 | BUG_ON(dev->bus != &pci_bus_type); |
| 177 | 178 | ||
| 178 | phys_addr = __pa(cpu_addr); | 179 | phys_addr = __pa(cpu_addr); |
| 179 | dma_addr = provider->dma_map(pdev, phys_addr, size); | 180 | dma_addr = provider->dma_map(pdev, phys_addr, size, SN_DMA_ADDR_PHYS); |
| 180 | if (!dma_addr) { | 181 | if (!dma_addr) { |
| 181 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); | 182 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); |
| 182 | return 0; | 183 | return 0; |
| @@ -260,7 +261,8 @@ int sn_dma_map_sg(struct device *dev, struct scatterlist *sg, int nhwentries, | |||
| 260 | for (i = 0; i < nhwentries; i++, sg++) { | 261 | for (i = 0; i < nhwentries; i++, sg++) { |
| 261 | phys_addr = SG_ENT_PHYS_ADDRESS(sg); | 262 | phys_addr = SG_ENT_PHYS_ADDRESS(sg); |
| 262 | sg->dma_address = provider->dma_map(pdev, | 263 | sg->dma_address = provider->dma_map(pdev, |
| 263 | phys_addr, sg->length); | 264 | phys_addr, sg->length, |
| 265 | SN_DMA_ADDR_PHYS); | ||
| 264 | 266 | ||
| 265 | if (!sg->dma_address) { | 267 | if (!sg->dma_address) { |
| 266 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); | 268 | printk(KERN_ERR "%s: out of ATEs\n", __FUNCTION__); |
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c index 9f86bb6519aa..a86c7b945962 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c | |||
| @@ -41,7 +41,7 @@ extern int sn_ioif_inited; | |||
| 41 | 41 | ||
| 42 | static dma_addr_t | 42 | static dma_addr_t |
| 43 | pcibr_dmamap_ate32(struct pcidev_info *info, | 43 | pcibr_dmamap_ate32(struct pcidev_info *info, |
| 44 | u64 paddr, size_t req_size, u64 flags) | 44 | u64 paddr, size_t req_size, u64 flags, int dma_flags) |
| 45 | { | 45 | { |
| 46 | 46 | ||
| 47 | struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info; | 47 | struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info; |
| @@ -81,9 +81,12 @@ pcibr_dmamap_ate32(struct pcidev_info *info, | |||
| 81 | if (IS_PCIX(pcibus_info)) | 81 | if (IS_PCIX(pcibus_info)) |
| 82 | ate_flags &= ~(PCI32_ATE_PREF); | 82 | ate_flags &= ~(PCI32_ATE_PREF); |
| 83 | 83 | ||
| 84 | xio_addr = | 84 | if (SN_DMA_ADDRTYPE(dma_flags == SN_DMA_ADDR_PHYS)) |
| 85 | IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : | 85 | xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : |
| 86 | PHYS_TO_TIODMA(paddr); | 86 | PHYS_TO_TIODMA(paddr); |
| 87 | else | ||
| 88 | xio_addr = paddr; | ||
| 89 | |||
| 87 | offset = IOPGOFF(xio_addr); | 90 | offset = IOPGOFF(xio_addr); |
| 88 | ate = ate_flags | (xio_addr - offset); | 91 | ate = ate_flags | (xio_addr - offset); |
| 89 | 92 | ||
| @@ -91,6 +94,13 @@ pcibr_dmamap_ate32(struct pcidev_info *info, | |||
| 91 | if (IS_PIC_SOFT(pcibus_info)) { | 94 | if (IS_PIC_SOFT(pcibus_info)) { |
| 92 | ate |= (pcibus_info->pbi_hub_xid << PIC_ATE_TARGETID_SHFT); | 95 | ate |= (pcibus_info->pbi_hub_xid << PIC_ATE_TARGETID_SHFT); |
| 93 | } | 96 | } |
| 97 | |||
| 98 | /* | ||
| 99 | * If we're mapping for MSI, set the MSI bit in the ATE | ||
| 100 | */ | ||
| 101 | if (dma_flags & SN_DMA_MSI) | ||
| 102 | ate |= PCI32_ATE_MSI; | ||
| 103 | |||
| 94 | ate_write(pcibus_info, ate_index, ate_count, ate); | 104 | ate_write(pcibus_info, ate_index, ate_count, ate); |
| 95 | 105 | ||
| 96 | /* | 106 | /* |
| @@ -105,20 +115,27 @@ pcibr_dmamap_ate32(struct pcidev_info *info, | |||
| 105 | if (pcibus_info->pbi_devreg[internal_device] & PCIBR_DEV_SWAP_DIR) | 115 | if (pcibus_info->pbi_devreg[internal_device] & PCIBR_DEV_SWAP_DIR) |
| 106 | ATE_SWAP_ON(pci_addr); | 116 | ATE_SWAP_ON(pci_addr); |
| 107 | 117 | ||
| 118 | |||
| 108 | return pci_addr; | 119 | return pci_addr; |
| 109 | } | 120 | } |
| 110 | 121 | ||
| 111 | static dma_addr_t | 122 | static dma_addr_t |
| 112 | pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr, | 123 | pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr, |
| 113 | u64 dma_attributes) | 124 | u64 dma_attributes, int dma_flags) |
| 114 | { | 125 | { |
| 115 | struct pcibus_info *pcibus_info = (struct pcibus_info *) | 126 | struct pcibus_info *pcibus_info = (struct pcibus_info *) |
| 116 | ((info->pdi_host_pcidev_info)->pdi_pcibus_info); | 127 | ((info->pdi_host_pcidev_info)->pdi_pcibus_info); |
| 117 | u64 pci_addr; | 128 | u64 pci_addr; |
| 118 | 129 | ||
| 119 | /* Translate to Crosstalk View of Physical Address */ | 130 | /* Translate to Crosstalk View of Physical Address */ |
| 120 | pci_addr = (IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : | 131 | if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS) |
| 121 | PHYS_TO_TIODMA(paddr)) | dma_attributes; | 132 | pci_addr = IS_PIC_SOFT(pcibus_info) ? |
| 133 | PHYS_TO_DMA(paddr) : | ||
| 134 | PHYS_TO_TIODMA(paddr) | dma_attributes; | ||
| 135 | else | ||
| 136 | pci_addr = IS_PIC_SOFT(pcibus_info) ? | ||
| 137 | paddr : | ||
| 138 | paddr | dma_attributes; | ||
| 122 | 139 | ||
| 123 | /* Handle Bus mode */ | 140 | /* Handle Bus mode */ |
| 124 | if (IS_PCIX(pcibus_info)) | 141 | if (IS_PCIX(pcibus_info)) |
| @@ -130,7 +147,9 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr, | |||
| 130 | ((u64) pcibus_info-> | 147 | ((u64) pcibus_info-> |
| 131 | pbi_hub_xid << PIC_PCI64_ATTR_TARG_SHFT); | 148 | pbi_hub_xid << PIC_PCI64_ATTR_TARG_SHFT); |
| 132 | } else | 149 | } else |
| 133 | pci_addr |= TIOCP_PCI64_CMDTYPE_MEM; | 150 | pci_addr |= (dma_flags & SN_DMA_MSI) ? |
| 151 | TIOCP_PCI64_CMDTYPE_MSI : | ||
| 152 | TIOCP_PCI64_CMDTYPE_MEM; | ||
| 134 | 153 | ||
| 135 | /* If PCI mode, func zero uses VCHAN0, every other func uses VCHAN1 */ | 154 | /* If PCI mode, func zero uses VCHAN0, every other func uses VCHAN1 */ |
| 136 | if (!IS_PCIX(pcibus_info) && PCI_FUNC(info->pdi_linux_pcidev->devfn)) | 155 | if (!IS_PCIX(pcibus_info) && PCI_FUNC(info->pdi_linux_pcidev->devfn)) |
| @@ -141,7 +160,7 @@ pcibr_dmatrans_direct64(struct pcidev_info * info, u64 paddr, | |||
| 141 | 160 | ||
| 142 | static dma_addr_t | 161 | static dma_addr_t |
| 143 | pcibr_dmatrans_direct32(struct pcidev_info * info, | 162 | pcibr_dmatrans_direct32(struct pcidev_info * info, |
| 144 | u64 paddr, size_t req_size, u64 flags) | 163 | u64 paddr, size_t req_size, u64 flags, int dma_flags) |
| 145 | { | 164 | { |
| 146 | struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info; | 165 | struct pcidev_info *pcidev_info = info->pdi_host_pcidev_info; |
| 147 | struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info-> | 166 | struct pcibus_info *pcibus_info = (struct pcibus_info *)pcidev_info-> |
| @@ -156,8 +175,14 @@ pcibr_dmatrans_direct32(struct pcidev_info * info, | |||
| 156 | return 0; | 175 | return 0; |
| 157 | } | 176 | } |
| 158 | 177 | ||
| 159 | xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : | 178 | if (dma_flags & SN_DMA_MSI) |
| 160 | PHYS_TO_TIODMA(paddr); | 179 | return 0; |
| 180 | |||
| 181 | if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS) | ||
| 182 | xio_addr = IS_PIC_SOFT(pcibus_info) ? PHYS_TO_DMA(paddr) : | ||
| 183 | PHYS_TO_TIODMA(paddr); | ||
| 184 | else | ||
| 185 | xio_addr = paddr; | ||
| 161 | 186 | ||
| 162 | xio_base = pcibus_info->pbi_dir_xbase; | 187 | xio_base = pcibus_info->pbi_dir_xbase; |
| 163 | offset = xio_addr - xio_base; | 188 | offset = xio_addr - xio_base; |
| @@ -327,7 +352,7 @@ void sn_dma_flush(u64 addr) | |||
| 327 | */ | 352 | */ |
| 328 | 353 | ||
| 329 | dma_addr_t | 354 | dma_addr_t |
| 330 | pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) | 355 | pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size, int dma_flags) |
| 331 | { | 356 | { |
| 332 | dma_addr_t dma_handle; | 357 | dma_addr_t dma_handle; |
| 333 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); | 358 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); |
| @@ -344,11 +369,11 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) | |||
| 344 | */ | 369 | */ |
| 345 | 370 | ||
| 346 | dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, | 371 | dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, |
| 347 | PCI64_ATTR_PREF); | 372 | PCI64_ATTR_PREF, dma_flags); |
| 348 | } else { | 373 | } else { |
| 349 | /* Handle 32-63 bit cards via direct mapping */ | 374 | /* Handle 32-63 bit cards via direct mapping */ |
| 350 | dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr, | 375 | dma_handle = pcibr_dmatrans_direct32(pcidev_info, phys_addr, |
| 351 | size, 0); | 376 | size, 0, dma_flags); |
| 352 | if (!dma_handle) { | 377 | if (!dma_handle) { |
| 353 | /* | 378 | /* |
| 354 | * It is a 32 bit card and we cannot do direct mapping, | 379 | * It is a 32 bit card and we cannot do direct mapping, |
| @@ -356,7 +381,8 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) | |||
| 356 | */ | 381 | */ |
| 357 | 382 | ||
| 358 | dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr, | 383 | dma_handle = pcibr_dmamap_ate32(pcidev_info, phys_addr, |
| 359 | size, PCI32_ATE_PREF); | 384 | size, PCI32_ATE_PREF, |
| 385 | dma_flags); | ||
| 360 | } | 386 | } |
| 361 | } | 387 | } |
| 362 | 388 | ||
| @@ -365,18 +391,18 @@ pcibr_dma_map(struct pci_dev * hwdev, unsigned long phys_addr, size_t size) | |||
| 365 | 391 | ||
| 366 | dma_addr_t | 392 | dma_addr_t |
| 367 | pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr, | 393 | pcibr_dma_map_consistent(struct pci_dev * hwdev, unsigned long phys_addr, |
| 368 | size_t size) | 394 | size_t size, int dma_flags) |
| 369 | { | 395 | { |
| 370 | dma_addr_t dma_handle; | 396 | dma_addr_t dma_handle; |
| 371 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); | 397 | struct pcidev_info *pcidev_info = SN_PCIDEV_INFO(hwdev); |
| 372 | 398 | ||
| 373 | if (hwdev->dev.coherent_dma_mask == ~0UL) { | 399 | if (hwdev->dev.coherent_dma_mask == ~0UL) { |
| 374 | dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, | 400 | dma_handle = pcibr_dmatrans_direct64(pcidev_info, phys_addr, |
| 375 | PCI64_ATTR_BAR); | 401 | PCI64_ATTR_BAR, dma_flags); |
| 376 | } else { | 402 | } else { |
| 377 | dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info, | 403 | dma_handle = (dma_addr_t) pcibr_dmamap_ate32(pcidev_info, |
| 378 | phys_addr, size, | 404 | phys_addr, size, |
| 379 | PCI32_ATE_BAR); | 405 | PCI32_ATE_BAR, dma_flags); |
| 380 | } | 406 | } |
| 381 | 407 | ||
| 382 | return dma_handle; | 408 | return dma_handle; |
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c index be0176912968..20de72791b97 100644 --- a/arch/ia64/sn/pci/tioca_provider.c +++ b/arch/ia64/sn/pci/tioca_provider.c | |||
| @@ -515,11 +515,17 @@ tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) | |||
| 515 | * use the GART mapped mode. | 515 | * use the GART mapped mode. |
| 516 | */ | 516 | */ |
| 517 | static u64 | 517 | static u64 |
| 518 | tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count) | 518 | tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags) |
| 519 | { | 519 | { |
| 520 | u64 mapaddr; | 520 | u64 mapaddr; |
| 521 | 521 | ||
| 522 | /* | 522 | /* |
| 523 | * Not supported for now ... | ||
| 524 | */ | ||
| 525 | if (dma_flags & SN_DMA_MSI) | ||
| 526 | return 0; | ||
| 527 | |||
| 528 | /* | ||
| 523 | * If card is 64 or 48 bit addresable, use a direct mapping. 32 | 529 | * If card is 64 or 48 bit addresable, use a direct mapping. 32 |
| 524 | * bit direct is so restrictive w.r.t. where the memory resides that | 530 | * bit direct is so restrictive w.r.t. where the memory resides that |
| 525 | * we don't use it even though CA has some support. | 531 | * we don't use it even though CA has some support. |
diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c index 833295624e5d..4cac7bdc7c7f 100644 --- a/arch/ia64/sn/pci/tioce_provider.c +++ b/arch/ia64/sn/pci/tioce_provider.c | |||
| @@ -170,7 +170,8 @@ tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr) | |||
| 170 | (ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1) | 170 | (ATE_PAGE((start)+(len)-1, pagesize) - ATE_PAGE(start, pagesize) + 1) |
| 171 | 171 | ||
| 172 | #define ATE_VALID(ate) ((ate) & (1UL << 63)) | 172 | #define ATE_VALID(ate) ((ate) & (1UL << 63)) |
| 173 | #define ATE_MAKE(addr, ps) (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63)) | 173 | #define ATE_MAKE(addr, ps, msi) \ |
| 174 | (((addr) & ~ATE_PAGEMASK(ps)) | (1UL << 63) | ((msi)?(1UL << 62):0)) | ||
| 174 | 175 | ||
| 175 | /* | 176 | /* |
| 176 | * Flavors of ate-based mapping supported by tioce_alloc_map() | 177 | * Flavors of ate-based mapping supported by tioce_alloc_map() |
| @@ -196,15 +197,17 @@ tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr) | |||
| 196 | * | 197 | * |
| 197 | * 63 - must be 1 to indicate d64 mode to CE hardware | 198 | * 63 - must be 1 to indicate d64 mode to CE hardware |
| 198 | * 62 - barrier bit ... controlled with tioce_dma_barrier() | 199 | * 62 - barrier bit ... controlled with tioce_dma_barrier() |
| 199 | * 61 - 0 since this is not an MSI transaction | 200 | * 61 - msi bit ... specified through dma_flags |
| 200 | * 60:54 - reserved, MBZ | 201 | * 60:54 - reserved, MBZ |
| 201 | */ | 202 | */ |
| 202 | static u64 | 203 | static u64 |
| 203 | tioce_dma_d64(unsigned long ct_addr) | 204 | tioce_dma_d64(unsigned long ct_addr, int dma_flags) |
| 204 | { | 205 | { |
| 205 | u64 bus_addr; | 206 | u64 bus_addr; |
| 206 | 207 | ||
| 207 | bus_addr = ct_addr | (1UL << 63); | 208 | bus_addr = ct_addr | (1UL << 63); |
| 209 | if (dma_flags & SN_DMA_MSI) | ||
| 210 | bus_addr |= (1UL << 61); | ||
| 208 | 211 | ||
| 209 | return bus_addr; | 212 | return bus_addr; |
| 210 | } | 213 | } |
| @@ -261,7 +264,7 @@ pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base, | |||
| 261 | */ | 264 | */ |
| 262 | static u64 | 265 | static u64 |
| 263 | tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, | 266 | tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, |
| 264 | u64 ct_addr, int len) | 267 | u64 ct_addr, int len, int dma_flags) |
| 265 | { | 268 | { |
| 266 | int i; | 269 | int i; |
| 267 | int j; | 270 | int j; |
| @@ -270,6 +273,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, | |||
| 270 | int entries; | 273 | int entries; |
| 271 | int nates; | 274 | int nates; |
| 272 | u64 pagesize; | 275 | u64 pagesize; |
| 276 | int msi_capable, msi_wanted; | ||
| 273 | u64 *ate_shadow; | 277 | u64 *ate_shadow; |
| 274 | u64 *ate_reg; | 278 | u64 *ate_reg; |
| 275 | u64 addr; | 279 | u64 addr; |
| @@ -291,6 +295,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, | |||
| 291 | ate_reg = ce_mmr->ce_ure_ate3240; | 295 | ate_reg = ce_mmr->ce_ure_ate3240; |
| 292 | pagesize = ce_kern->ce_ate3240_pagesize; | 296 | pagesize = ce_kern->ce_ate3240_pagesize; |
| 293 | bus_base = TIOCE_M32_MIN; | 297 | bus_base = TIOCE_M32_MIN; |
| 298 | msi_capable = 1; | ||
| 294 | break; | 299 | break; |
| 295 | case TIOCE_ATE_M40: | 300 | case TIOCE_ATE_M40: |
| 296 | first = 0; | 301 | first = 0; |
| @@ -299,6 +304,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, | |||
| 299 | ate_reg = ce_mmr->ce_ure_ate40; | 304 | ate_reg = ce_mmr->ce_ure_ate40; |
| 300 | pagesize = MB(64); | 305 | pagesize = MB(64); |
| 301 | bus_base = TIOCE_M40_MIN; | 306 | bus_base = TIOCE_M40_MIN; |
| 307 | msi_capable = 0; | ||
| 302 | break; | 308 | break; |
| 303 | case TIOCE_ATE_M40S: | 309 | case TIOCE_ATE_M40S: |
| 304 | /* | 310 | /* |
| @@ -311,11 +317,16 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, | |||
| 311 | ate_reg = ce_mmr->ce_ure_ate3240; | 317 | ate_reg = ce_mmr->ce_ure_ate3240; |
| 312 | pagesize = GB(16); | 318 | pagesize = GB(16); |
| 313 | bus_base = TIOCE_M40S_MIN; | 319 | bus_base = TIOCE_M40S_MIN; |
| 320 | msi_capable = 0; | ||
| 314 | break; | 321 | break; |
| 315 | default: | 322 | default: |
| 316 | return 0; | 323 | return 0; |
| 317 | } | 324 | } |
| 318 | 325 | ||
| 326 | msi_wanted = dma_flags & SN_DMA_MSI; | ||
| 327 | if (msi_wanted && !msi_capable) | ||
| 328 | return 0; | ||
| 329 | |||
| 319 | nates = ATE_NPAGES(ct_addr, len, pagesize); | 330 | nates = ATE_NPAGES(ct_addr, len, pagesize); |
| 320 | if (nates > entries) | 331 | if (nates > entries) |
| 321 | return 0; | 332 | return 0; |
| @@ -344,7 +355,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, | |||
| 344 | for (j = 0; j < nates; j++) { | 355 | for (j = 0; j < nates; j++) { |
| 345 | u64 ate; | 356 | u64 ate; |
| 346 | 357 | ||
| 347 | ate = ATE_MAKE(addr, pagesize); | 358 | ate = ATE_MAKE(addr, pagesize, msi_wanted); |
| 348 | ate_shadow[i + j] = ate; | 359 | ate_shadow[i + j] = ate; |
| 349 | tioce_mmr_storei(ce_kern, &ate_reg[i + j], ate); | 360 | tioce_mmr_storei(ce_kern, &ate_reg[i + j], ate); |
| 350 | addr += pagesize; | 361 | addr += pagesize; |
| @@ -371,7 +382,7 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port, | |||
| 371 | * Map @paddr into 32-bit bus space of the CE associated with @pcidev_info. | 382 | * Map @paddr into 32-bit bus space of the CE associated with @pcidev_info. |
| 372 | */ | 383 | */ |
| 373 | static u64 | 384 | static u64 |
| 374 | tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr) | 385 | tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr, int dma_flags) |
| 375 | { | 386 | { |
| 376 | int dma_ok; | 387 | int dma_ok; |
| 377 | int port; | 388 | int port; |
| @@ -381,6 +392,9 @@ tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr) | |||
| 381 | u64 ct_lower; | 392 | u64 ct_lower; |
| 382 | dma_addr_t bus_addr; | 393 | dma_addr_t bus_addr; |
| 383 | 394 | ||
| 395 | if (dma_flags & SN_DMA_MSI) | ||
| 396 | return 0; | ||
| 397 | |||
| 384 | ct_upper = ct_addr & ~0x3fffffffUL; | 398 | ct_upper = ct_addr & ~0x3fffffffUL; |
| 385 | ct_lower = ct_addr & 0x3fffffffUL; | 399 | ct_lower = ct_addr & 0x3fffffffUL; |
| 386 | 400 | ||
| @@ -507,7 +521,7 @@ tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir) | |||
| 507 | */ | 521 | */ |
| 508 | static u64 | 522 | static u64 |
| 509 | tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, | 523 | tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, |
| 510 | int barrier) | 524 | int barrier, int dma_flags) |
| 511 | { | 525 | { |
| 512 | unsigned long flags; | 526 | unsigned long flags; |
| 513 | u64 ct_addr; | 527 | u64 ct_addr; |
| @@ -523,15 +537,18 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, | |||
| 523 | if (dma_mask < 0x7fffffffUL) | 537 | if (dma_mask < 0x7fffffffUL) |
| 524 | return 0; | 538 | return 0; |
| 525 | 539 | ||
| 526 | ct_addr = PHYS_TO_TIODMA(paddr); | 540 | if (SN_DMA_ADDRTYPE(dma_flags) == SN_DMA_ADDR_PHYS) |
| 541 | ct_addr = PHYS_TO_TIODMA(paddr); | ||
| 542 | else | ||
| 543 | ct_addr = paddr; | ||
| 527 | 544 | ||
| 528 | /* | 545 | /* |
| 529 | * If the device can generate 64 bit addresses, create a D64 map. | 546 | * If the device can generate 64 bit addresses, create a D64 map. |
| 530 | * Since this should never fail, bypass the rest of the checks. | ||
| 531 | */ | 547 | */ |
| 532 | if (dma_mask == ~0UL) { | 548 | if (dma_mask == ~0UL) { |
| 533 | mapaddr = tioce_dma_d64(ct_addr); | 549 | mapaddr = tioce_dma_d64(ct_addr, dma_flags); |
| 534 | goto dma_map_done; | 550 | if (mapaddr) |
| 551 | goto dma_map_done; | ||
| 535 | } | 552 | } |
| 536 | 553 | ||
| 537 | pcidev_to_tioce(pdev, NULL, &ce_kern, &port); | 554 | pcidev_to_tioce(pdev, NULL, &ce_kern, &port); |
| @@ -574,18 +591,22 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, | |||
| 574 | 591 | ||
| 575 | if (byte_count > MB(64)) { | 592 | if (byte_count > MB(64)) { |
| 576 | mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S, | 593 | mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40S, |
| 577 | port, ct_addr, byte_count); | 594 | port, ct_addr, byte_count, |
| 595 | dma_flags); | ||
| 578 | if (!mapaddr) | 596 | if (!mapaddr) |
| 579 | mapaddr = | 597 | mapaddr = |
| 580 | tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1, | 598 | tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1, |
| 581 | ct_addr, byte_count); | 599 | ct_addr, byte_count, |
| 600 | dma_flags); | ||
| 582 | } else { | 601 | } else { |
| 583 | mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1, | 602 | mapaddr = tioce_alloc_map(ce_kern, TIOCE_ATE_M40, -1, |
| 584 | ct_addr, byte_count); | 603 | ct_addr, byte_count, |
| 604 | dma_flags); | ||
| 585 | if (!mapaddr) | 605 | if (!mapaddr) |
| 586 | mapaddr = | 606 | mapaddr = |
| 587 | tioce_alloc_map(ce_kern, TIOCE_ATE_M40S, | 607 | tioce_alloc_map(ce_kern, TIOCE_ATE_M40S, |
| 588 | port, ct_addr, byte_count); | 608 | port, ct_addr, byte_count, |
| 609 | dma_flags); | ||
| 589 | } | 610 | } |
| 590 | } | 611 | } |
| 591 | 612 | ||
| @@ -593,7 +614,7 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, | |||
| 593 | * 32-bit direct is the next mode to try | 614 | * 32-bit direct is the next mode to try |
| 594 | */ | 615 | */ |
| 595 | if (!mapaddr && dma_mask >= 0xffffffffUL) | 616 | if (!mapaddr && dma_mask >= 0xffffffffUL) |
| 596 | mapaddr = tioce_dma_d32(pdev, ct_addr); | 617 | mapaddr = tioce_dma_d32(pdev, ct_addr, dma_flags); |
| 597 | 618 | ||
| 598 | /* | 619 | /* |
| 599 | * Last resort, try 32-bit ATE-based map. | 620 | * Last resort, try 32-bit ATE-based map. |
| @@ -601,7 +622,7 @@ tioce_do_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, | |||
| 601 | if (!mapaddr) | 622 | if (!mapaddr) |
| 602 | mapaddr = | 623 | mapaddr = |
| 603 | tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr, | 624 | tioce_alloc_map(ce_kern, TIOCE_ATE_M32, -1, ct_addr, |
| 604 | byte_count); | 625 | byte_count, dma_flags); |
| 605 | 626 | ||
| 606 | spin_unlock_irqrestore(&ce_kern->ce_lock, flags); | 627 | spin_unlock_irqrestore(&ce_kern->ce_lock, flags); |
| 607 | 628 | ||
| @@ -622,9 +643,9 @@ dma_map_done: | |||
| 622 | * in the address. | 643 | * in the address. |
| 623 | */ | 644 | */ |
| 624 | static u64 | 645 | static u64 |
| 625 | tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count) | 646 | tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags) |
| 626 | { | 647 | { |
| 627 | return tioce_do_dma_map(pdev, paddr, byte_count, 0); | 648 | return tioce_do_dma_map(pdev, paddr, byte_count, 0, dma_flags); |
| 628 | } | 649 | } |
| 629 | 650 | ||
| 630 | /** | 651 | /** |
| @@ -636,9 +657,9 @@ tioce_dma(struct pci_dev *pdev, u64 paddr, size_t byte_count) | |||
| 636 | * Simply call tioce_do_dma_map() to create a map with the barrier bit set | 657 | * Simply call tioce_do_dma_map() to create a map with the barrier bit set |
| 637 | * in the address. | 658 | * in the address. |
| 638 | */ static u64 | 659 | */ static u64 |
| 639 | tioce_dma_consistent(struct pci_dev *pdev, u64 paddr, size_t byte_count) | 660 | tioce_dma_consistent(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags) |
| 640 | { | 661 | { |
| 641 | return tioce_do_dma_map(pdev, paddr, byte_count, 1); | 662 | return tioce_do_dma_map(pdev, paddr, byte_count, 1, dma_flags); |
| 642 | } | 663 | } |
| 643 | 664 | ||
| 644 | /** | 665 | /** |
| @@ -696,7 +717,7 @@ tioce_reserve_m32(struct tioce_kernel *ce_kern, u64 base, u64 limit) | |||
| 696 | while (ate_index <= last_ate) { | 717 | while (ate_index <= last_ate) { |
| 697 | u64 ate; | 718 | u64 ate; |
| 698 | 719 | ||
| 699 | ate = ATE_MAKE(0xdeadbeef, ps); | 720 | ate = ATE_MAKE(0xdeadbeef, ps, 0); |
| 700 | ce_kern->ce_ate3240_shadow[ate_index] = ate; | 721 | ce_kern->ce_ate3240_shadow[ate_index] = ate; |
| 701 | tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_ate3240[ate_index], | 722 | tioce_mmr_storei(ce_kern, &ce_mmr->ce_ure_ate3240[ate_index], |
| 702 | ate); | 723 | ate); |
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/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/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index c9e0aeeca3d8..4368dc3f3c30 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c | |||
| @@ -379,13 +379,12 @@ mpc85xx_cds_pcibios_fixup(void) | |||
| 379 | PCI_DEVICE_ID_VIA_82C586_2, NULL))) { | 379 | PCI_DEVICE_ID_VIA_82C586_2, NULL))) { |
| 380 | dev->irq = 10; | 380 | dev->irq = 10; |
| 381 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10); | 381 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10); |
| 382 | pci_dev_put(dev); | ||
| 383 | } | ||
| 384 | 382 | ||
| 385 | if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, | 383 | if ((dev = pci_get_device(PCI_VENDOR_ID_VIA, |
| 386 | PCI_DEVICE_ID_VIA_82C586_2, dev))) { | 384 | PCI_DEVICE_ID_VIA_82C586_2, dev))) { |
| 387 | dev->irq = 11; | 385 | dev->irq = 11; |
| 388 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); | 386 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); |
| 387 | } | ||
| 389 | pci_dev_put(dev); | 388 | pci_dev_put(dev); |
| 390 | } | 389 | } |
| 391 | } | 390 | } |
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/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index a2060e4d5de6..3c55c76c6fd5 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c | |||
| @@ -13,7 +13,10 @@ | |||
| 13 | 13 | ||
| 14 | #include "pci.h" | 14 | #include "pci.h" |
| 15 | 15 | ||
| 16 | #define MMCONFIG_APER_SIZE (256*1024*1024) | 16 | /* aperture is up to 256MB but BIOS may reserve less */ |
| 17 | #define MMCONFIG_APER_MIN (2 * 1024*1024) | ||
| 18 | #define MMCONFIG_APER_MAX (256 * 1024*1024) | ||
| 19 | |||
| 17 | /* Verify the first 16 busses. We assume that systems with more busses | 20 | /* Verify the first 16 busses. We assume that systems with more busses |
| 18 | get MCFG right. */ | 21 | get MCFG right. */ |
| 19 | #define MAX_CHECK_BUS 16 | 22 | #define MAX_CHECK_BUS 16 |
| @@ -175,9 +178,10 @@ void __init pci_mmcfg_init(void) | |||
| 175 | return; | 178 | return; |
| 176 | 179 | ||
| 177 | if (!e820_all_mapped(pci_mmcfg_config[0].base_address, | 180 | if (!e820_all_mapped(pci_mmcfg_config[0].base_address, |
| 178 | pci_mmcfg_config[0].base_address + MMCONFIG_APER_SIZE, | 181 | pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN, |
| 179 | E820_RESERVED)) { | 182 | E820_RESERVED)) { |
| 180 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area is not E820-reserved\n"); | 183 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n", |
| 184 | pci_mmcfg_config[0].base_address); | ||
| 181 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); | 185 | printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); |
| 182 | return; | 186 | return; |
| 183 | } | 187 | } |
| @@ -190,7 +194,8 @@ void __init pci_mmcfg_init(void) | |||
| 190 | } | 194 | } |
| 191 | for (i = 0; i < pci_mmcfg_config_num; ++i) { | 195 | for (i = 0; i < pci_mmcfg_config_num; ++i) { |
| 192 | pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i]; | 196 | pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i]; |
| 193 | pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE); | 197 | pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, |
| 198 | MMCONFIG_APER_MAX); | ||
| 194 | if (!pci_mmcfg_virt[i].virt) { | 199 | if (!pci_mmcfg_virt[i].virt) { |
| 195 | printk("PCI: Cannot map mmconfig aperture for segment %d\n", | 200 | printk("PCI: Cannot map mmconfig aperture for segment %d\n", |
| 196 | pci_mmcfg_config[i].pci_segment_group_number); | 201 | pci_mmcfg_config[i].pci_segment_group_number); |
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/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/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/pci/Makefile b/drivers/pci/Makefile index 6707df968934..f2d152b818f0 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile | |||
| @@ -26,7 +26,11 @@ obj-$(CONFIG_PPC32) += setup-irq.o | |||
| 26 | obj-$(CONFIG_PPC64) += setup-bus.o | 26 | obj-$(CONFIG_PPC64) += setup-bus.o |
| 27 | obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o | 27 | obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o |
| 28 | obj-$(CONFIG_X86_VISWS) += setup-irq.o | 28 | obj-$(CONFIG_X86_VISWS) += setup-irq.o |
| 29 | obj-$(CONFIG_PCI_MSI) += msi.o | 29 | |
| 30 | msiobj-y := msi.o msi-apic.o | ||
| 31 | msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o | ||
| 32 | msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o | ||
| 33 | obj-$(CONFIG_PCI_MSI) += $(msiobj-y) | ||
| 30 | 34 | ||
| 31 | # | 35 | # |
| 32 | # ACPI Related PCI FW Functions | 36 | # ACPI Related PCI FW Functions |
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index eed67d9e73bc..723092682023 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c | |||
| @@ -81,9 +81,9 @@ void __devinit pci_bus_add_device(struct pci_dev *dev) | |||
| 81 | { | 81 | { |
| 82 | device_add(&dev->dev); | 82 | device_add(&dev->dev); |
| 83 | 83 | ||
| 84 | spin_lock(&pci_bus_lock); | 84 | down_write(&pci_bus_sem); |
| 85 | list_add_tail(&dev->global_list, &pci_devices); | 85 | list_add_tail(&dev->global_list, &pci_devices); |
| 86 | spin_unlock(&pci_bus_lock); | 86 | up_write(&pci_bus_sem); |
| 87 | 87 | ||
| 88 | pci_proc_attach_device(dev); | 88 | pci_proc_attach_device(dev); |
| 89 | pci_create_sysfs_dev_files(dev); | 89 | pci_create_sysfs_dev_files(dev); |
| @@ -125,10 +125,10 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus) | |||
| 125 | */ | 125 | */ |
| 126 | if (dev->subordinate) { | 126 | if (dev->subordinate) { |
| 127 | if (list_empty(&dev->subordinate->node)) { | 127 | if (list_empty(&dev->subordinate->node)) { |
| 128 | spin_lock(&pci_bus_lock); | 128 | down_write(&pci_bus_sem); |
| 129 | list_add_tail(&dev->subordinate->node, | 129 | list_add_tail(&dev->subordinate->node, |
| 130 | &dev->bus->children); | 130 | &dev->bus->children); |
| 131 | spin_unlock(&pci_bus_lock); | 131 | up_write(&pci_bus_sem); |
| 132 | } | 132 | } |
| 133 | pci_bus_add_devices(dev->subordinate); | 133 | pci_bus_add_devices(dev->subordinate); |
| 134 | 134 | ||
| @@ -168,7 +168,7 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), | |||
| 168 | struct list_head *next; | 168 | struct list_head *next; |
| 169 | 169 | ||
| 170 | bus = top; | 170 | bus = top; |
| 171 | spin_lock(&pci_bus_lock); | 171 | down_read(&pci_bus_sem); |
| 172 | next = top->devices.next; | 172 | next = top->devices.next; |
| 173 | for (;;) { | 173 | for (;;) { |
| 174 | if (next == &bus->devices) { | 174 | if (next == &bus->devices) { |
| @@ -180,22 +180,19 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), | |||
| 180 | continue; | 180 | continue; |
| 181 | } | 181 | } |
| 182 | dev = list_entry(next, struct pci_dev, bus_list); | 182 | dev = list_entry(next, struct pci_dev, bus_list); |
| 183 | pci_dev_get(dev); | ||
| 184 | if (dev->subordinate) { | 183 | if (dev->subordinate) { |
| 185 | /* this is a pci-pci bridge, do its devices next */ | 184 | /* this is a pci-pci bridge, do its devices next */ |
| 186 | next = dev->subordinate->devices.next; | 185 | next = dev->subordinate->devices.next; |
| 187 | bus = dev->subordinate; | 186 | bus = dev->subordinate; |
| 188 | } else | 187 | } else |
| 189 | next = dev->bus_list.next; | 188 | next = dev->bus_list.next; |
| 190 | spin_unlock(&pci_bus_lock); | ||
| 191 | 189 | ||
| 192 | /* Run device routines with the bus unlocked */ | 190 | /* Run device routines with the device locked */ |
| 191 | down(&dev->dev.sem); | ||
| 193 | cb(dev, userdata); | 192 | cb(dev, userdata); |
| 194 | 193 | up(&dev->dev.sem); | |
| 195 | spin_lock(&pci_bus_lock); | ||
| 196 | pci_dev_put(dev); | ||
| 197 | } | 194 | } |
| 198 | spin_unlock(&pci_bus_lock); | 195 | up_read(&pci_bus_sem); |
| 199 | } | 196 | } |
| 200 | EXPORT_SYMBOL_GPL(pci_walk_bus); | 197 | EXPORT_SYMBOL_GPL(pci_walk_bus); |
| 201 | 198 | ||
diff --git a/drivers/pci/msi-altix.c b/drivers/pci/msi-altix.c new file mode 100644 index 000000000000..bed4183a5e39 --- /dev/null +++ b/drivers/pci/msi-altix.c | |||
| @@ -0,0 +1,210 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/types.h> | ||
| 10 | #include <linux/pci.h> | ||
| 11 | #include <linux/cpumask.h> | ||
| 12 | |||
| 13 | #include <asm/sn/addrs.h> | ||
| 14 | #include <asm/sn/intr.h> | ||
| 15 | #include <asm/sn/pcibus_provider_defs.h> | ||
| 16 | #include <asm/sn/pcidev.h> | ||
| 17 | #include <asm/sn/nodepda.h> | ||
| 18 | |||
| 19 | #include "msi.h" | ||
| 20 | |||
| 21 | struct sn_msi_info { | ||
| 22 | u64 pci_addr; | ||
| 23 | struct sn_irq_info *sn_irq_info; | ||
| 24 | }; | ||
| 25 | |||
| 26 | static struct sn_msi_info *sn_msi_info; | ||
| 27 | |||
| 28 | static void | ||
| 29 | sn_msi_teardown(unsigned int vector) | ||
| 30 | { | ||
| 31 | nasid_t nasid; | ||
| 32 | int widget; | ||
| 33 | struct pci_dev *pdev; | ||
| 34 | struct pcidev_info *sn_pdev; | ||
| 35 | struct sn_irq_info *sn_irq_info; | ||
| 36 | struct pcibus_bussoft *bussoft; | ||
| 37 | struct sn_pcibus_provider *provider; | ||
| 38 | |||
| 39 | sn_irq_info = sn_msi_info[vector].sn_irq_info; | ||
| 40 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | ||
| 41 | return; | ||
| 42 | |||
| 43 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | ||
| 44 | pdev = sn_pdev->pdi_linux_pcidev; | ||
| 45 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
| 46 | |||
| 47 | (*provider->dma_unmap)(pdev, | ||
| 48 | sn_msi_info[vector].pci_addr, | ||
| 49 | PCI_DMA_FROMDEVICE); | ||
| 50 | sn_msi_info[vector].pci_addr = 0; | ||
| 51 | |||
| 52 | bussoft = SN_PCIDEV_BUSSOFT(pdev); | ||
| 53 | nasid = NASID_GET(bussoft->bs_base); | ||
| 54 | widget = (nasid & 1) ? | ||
| 55 | TIO_SWIN_WIDGETNUM(bussoft->bs_base) : | ||
| 56 | SWIN_WIDGETNUM(bussoft->bs_base); | ||
| 57 | |||
| 58 | sn_intr_free(nasid, widget, sn_irq_info); | ||
| 59 | sn_msi_info[vector].sn_irq_info = NULL; | ||
| 60 | |||
| 61 | return; | ||
| 62 | } | ||
| 63 | |||
| 64 | int | ||
| 65 | sn_msi_setup(struct pci_dev *pdev, unsigned int vector, | ||
| 66 | u32 *addr_hi, u32 *addr_lo, u32 *data) | ||
| 67 | { | ||
| 68 | int widget; | ||
| 69 | int status; | ||
| 70 | nasid_t nasid; | ||
| 71 | u64 bus_addr; | ||
| 72 | struct sn_irq_info *sn_irq_info; | ||
| 73 | struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); | ||
| 74 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
| 75 | |||
| 76 | if (bussoft == NULL) | ||
| 77 | return -EINVAL; | ||
| 78 | |||
| 79 | if (provider == NULL || provider->dma_map_consistent == NULL) | ||
| 80 | return -EINVAL; | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Set up the vector plumbing. Let the prom (via sn_intr_alloc) | ||
| 84 | * decide which cpu to direct this msi at by default. | ||
| 85 | */ | ||
| 86 | |||
| 87 | nasid = NASID_GET(bussoft->bs_base); | ||
| 88 | widget = (nasid & 1) ? | ||
| 89 | TIO_SWIN_WIDGETNUM(bussoft->bs_base) : | ||
| 90 | SWIN_WIDGETNUM(bussoft->bs_base); | ||
| 91 | |||
| 92 | sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); | ||
| 93 | if (! sn_irq_info) | ||
| 94 | return -ENOMEM; | ||
| 95 | |||
| 96 | status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1); | ||
| 97 | if (status) { | ||
| 98 | kfree(sn_irq_info); | ||
| 99 | return -ENOMEM; | ||
| 100 | } | ||
| 101 | |||
| 102 | sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */ | ||
| 103 | sn_irq_fixup(pdev, sn_irq_info); | ||
| 104 | |||
| 105 | /* Prom probably should fill these in, but doesn't ... */ | ||
| 106 | sn_irq_info->irq_bridge_type = bussoft->bs_asic_type; | ||
| 107 | sn_irq_info->irq_bridge = (void *)bussoft->bs_base; | ||
| 108 | |||
| 109 | /* | ||
| 110 | * Map the xio address into bus space | ||
| 111 | */ | ||
| 112 | bus_addr = (*provider->dma_map_consistent)(pdev, | ||
| 113 | sn_irq_info->irq_xtalkaddr, | ||
| 114 | sizeof(sn_irq_info->irq_xtalkaddr), | ||
| 115 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | ||
| 116 | if (! bus_addr) { | ||
| 117 | sn_intr_free(nasid, widget, sn_irq_info); | ||
| 118 | kfree(sn_irq_info); | ||
| 119 | return -ENOMEM; | ||
| 120 | } | ||
| 121 | |||
| 122 | sn_msi_info[vector].sn_irq_info = sn_irq_info; | ||
| 123 | sn_msi_info[vector].pci_addr = bus_addr; | ||
| 124 | |||
| 125 | *addr_hi = (u32)(bus_addr >> 32); | ||
| 126 | *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); | ||
| 127 | |||
| 128 | /* | ||
| 129 | * In the SN platform, bit 16 is a "send vector" bit which | ||
| 130 | * must be present in order to move the vector through the system. | ||
| 131 | */ | ||
| 132 | *data = 0x100 + (unsigned int)vector; | ||
| 133 | |||
| 134 | #ifdef CONFIG_SMP | ||
| 135 | set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0); | ||
| 136 | #endif | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | static void | ||
| 142 | sn_msi_target(unsigned int vector, unsigned int cpu, | ||
| 143 | u32 *addr_hi, u32 *addr_lo) | ||
| 144 | { | ||
| 145 | int slice; | ||
| 146 | nasid_t nasid; | ||
| 147 | u64 bus_addr; | ||
| 148 | struct pci_dev *pdev; | ||
| 149 | struct pcidev_info *sn_pdev; | ||
| 150 | struct sn_irq_info *sn_irq_info; | ||
| 151 | struct sn_irq_info *new_irq_info; | ||
| 152 | struct sn_pcibus_provider *provider; | ||
| 153 | |||
| 154 | sn_irq_info = sn_msi_info[vector].sn_irq_info; | ||
| 155 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | ||
| 156 | return; | ||
| 157 | |||
| 158 | /* | ||
| 159 | * Release XIO resources for the old MSI PCI address | ||
| 160 | */ | ||
| 161 | |||
| 162 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | ||
| 163 | pdev = sn_pdev->pdi_linux_pcidev; | ||
| 164 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
| 165 | |||
| 166 | bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo); | ||
| 167 | (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); | ||
| 168 | sn_msi_info[vector].pci_addr = 0; | ||
| 169 | |||
| 170 | nasid = cpuid_to_nasid(cpu); | ||
| 171 | slice = cpuid_to_slice(cpu); | ||
| 172 | |||
| 173 | new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); | ||
| 174 | sn_msi_info[vector].sn_irq_info = new_irq_info; | ||
| 175 | if (new_irq_info == NULL) | ||
| 176 | return; | ||
| 177 | |||
| 178 | /* | ||
| 179 | * Map the xio address into bus space | ||
| 180 | */ | ||
| 181 | |||
| 182 | bus_addr = (*provider->dma_map_consistent)(pdev, | ||
| 183 | new_irq_info->irq_xtalkaddr, | ||
| 184 | sizeof(new_irq_info->irq_xtalkaddr), | ||
| 185 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | ||
| 186 | |||
| 187 | sn_msi_info[vector].pci_addr = bus_addr; | ||
| 188 | *addr_hi = (u32)(bus_addr >> 32); | ||
| 189 | *addr_lo = (u32)(bus_addr & 0x00000000ffffffff); | ||
| 190 | } | ||
| 191 | |||
| 192 | struct msi_ops sn_msi_ops = { | ||
| 193 | .setup = sn_msi_setup, | ||
| 194 | .teardown = sn_msi_teardown, | ||
| 195 | #ifdef CONFIG_SMP | ||
| 196 | .target = sn_msi_target, | ||
| 197 | #endif | ||
| 198 | }; | ||
| 199 | |||
| 200 | int | ||
| 201 | sn_msi_init(void) | ||
| 202 | { | ||
| 203 | sn_msi_info = | ||
| 204 | kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL); | ||
| 205 | if (! sn_msi_info) | ||
| 206 | return -ENOMEM; | ||
| 207 | |||
| 208 | msi_register(&sn_msi_ops); | ||
| 209 | return 0; | ||
| 210 | } | ||
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c new file mode 100644 index 000000000000..0eb5fe9003a2 --- /dev/null +++ b/drivers/pci/msi-apic.c | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | /* | ||
| 2 | * MSI hooks for standard x86 apic | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include <linux/pci.h> | ||
| 6 | #include <linux/irq.h> | ||
| 7 | |||
| 8 | #include "msi.h" | ||
| 9 | |||
| 10 | /* | ||
| 11 | * Shifts for APIC-based data | ||
| 12 | */ | ||
| 13 | |||
| 14 | #define MSI_DATA_VECTOR_SHIFT 0 | ||
| 15 | #define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT) | ||
| 16 | |||
| 17 | #define MSI_DATA_DELIVERY_SHIFT 8 | ||
| 18 | #define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT) | ||
| 19 | #define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT) | ||
| 20 | |||
| 21 | #define MSI_DATA_LEVEL_SHIFT 14 | ||
| 22 | #define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) | ||
| 23 | #define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) | ||
| 24 | |||
| 25 | #define MSI_DATA_TRIGGER_SHIFT 15 | ||
| 26 | #define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) | ||
| 27 | #define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) | ||
| 28 | |||
| 29 | /* | ||
| 30 | * Shift/mask fields for APIC-based bus address | ||
| 31 | */ | ||
| 32 | |||
| 33 | #define MSI_ADDR_HEADER 0xfee00000 | ||
| 34 | |||
| 35 | #define MSI_ADDR_DESTID_MASK 0xfff0000f | ||
| 36 | #define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT) | ||
| 37 | |||
| 38 | #define MSI_ADDR_DESTMODE_SHIFT 2 | ||
| 39 | #define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT) | ||
| 40 | #define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT) | ||
| 41 | |||
| 42 | #define MSI_ADDR_REDIRECTION_SHIFT 3 | ||
| 43 | #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) | ||
| 44 | #define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) | ||
| 45 | |||
| 46 | |||
| 47 | static void | ||
| 48 | msi_target_apic(unsigned int vector, | ||
| 49 | unsigned int dest_cpu, | ||
| 50 | u32 *address_hi, /* in/out */ | ||
| 51 | u32 *address_lo) /* in/out */ | ||
| 52 | { | ||
| 53 | u32 addr = *address_lo; | ||
| 54 | |||
| 55 | addr &= MSI_ADDR_DESTID_MASK; | ||
| 56 | addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu)); | ||
| 57 | |||
| 58 | *address_lo = addr; | ||
| 59 | } | ||
| 60 | |||
| 61 | static int | ||
| 62 | msi_setup_apic(struct pci_dev *pdev, /* unused in generic */ | ||
| 63 | unsigned int vector, | ||
| 64 | u32 *address_hi, | ||
| 65 | u32 *address_lo, | ||
| 66 | u32 *data) | ||
| 67 | { | ||
| 68 | unsigned long dest_phys_id; | ||
| 69 | |||
| 70 | dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); | ||
| 71 | |||
| 72 | *address_hi = 0; | ||
| 73 | *address_lo = MSI_ADDR_HEADER | | ||
| 74 | MSI_ADDR_DESTMODE_PHYS | | ||
| 75 | MSI_ADDR_REDIRECTION_CPU | | ||
| 76 | MSI_ADDR_DESTID_CPU(dest_phys_id); | ||
| 77 | |||
| 78 | *data = MSI_DATA_TRIGGER_EDGE | | ||
| 79 | MSI_DATA_LEVEL_ASSERT | | ||
| 80 | MSI_DATA_DELIVERY_FIXED | | ||
| 81 | MSI_DATA_VECTOR(vector); | ||
| 82 | |||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | static void | ||
| 87 | msi_teardown_apic(unsigned int vector) | ||
| 88 | { | ||
| 89 | return; /* no-op */ | ||
| 90 | } | ||
| 91 | |||
| 92 | /* | ||
| 93 | * Generic ops used on most IA archs/platforms. Set with msi_register() | ||
| 94 | */ | ||
| 95 | |||
| 96 | struct msi_ops msi_apic_ops = { | ||
| 97 | .setup = msi_setup_apic, | ||
| 98 | .teardown = msi_teardown_apic, | ||
| 99 | .target = msi_target_apic, | ||
| 100 | }; | ||
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9855c4c920b8..7f8429284fab 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
| @@ -23,8 +23,6 @@ | |||
| 23 | #include "pci.h" | 23 | #include "pci.h" |
| 24 | #include "msi.h" | 24 | #include "msi.h" |
| 25 | 25 | ||
| 26 | #define MSI_TARGET_CPU first_cpu(cpu_online_map) | ||
| 27 | |||
| 28 | static DEFINE_SPINLOCK(msi_lock); | 26 | static DEFINE_SPINLOCK(msi_lock); |
| 29 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; | 27 | static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL }; |
| 30 | static kmem_cache_t* msi_cachep; | 28 | static kmem_cache_t* msi_cachep; |
| @@ -37,9 +35,17 @@ static int nr_msix_devices; | |||
| 37 | 35 | ||
| 38 | #ifndef CONFIG_X86_IO_APIC | 36 | #ifndef CONFIG_X86_IO_APIC |
| 39 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; | 37 | int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; |
| 40 | u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; | ||
| 41 | #endif | 38 | #endif |
| 42 | 39 | ||
| 40 | static struct msi_ops *msi_ops; | ||
| 41 | |||
| 42 | int | ||
| 43 | msi_register(struct msi_ops *ops) | ||
| 44 | { | ||
| 45 | msi_ops = ops; | ||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 43 | static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) | 49 | static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags) |
| 44 | { | 50 | { |
| 45 | memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); | 51 | memset(p, 0, NR_IRQS * sizeof(struct msi_desc)); |
| @@ -92,7 +98,7 @@ static void msi_set_mask_bit(unsigned int vector, int flag) | |||
| 92 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | 98 | static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) |
| 93 | { | 99 | { |
| 94 | struct msi_desc *entry; | 100 | struct msi_desc *entry; |
| 95 | struct msg_address address; | 101 | u32 address_hi, address_lo; |
| 96 | unsigned int irq = vector; | 102 | unsigned int irq = vector; |
| 97 | unsigned int dest_cpu = first_cpu(cpu_mask); | 103 | unsigned int dest_cpu = first_cpu(cpu_mask); |
| 98 | 104 | ||
| @@ -108,28 +114,36 @@ static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask) | |||
| 108 | if (!pos) | 114 | if (!pos) |
| 109 | return; | 115 | return; |
| 110 | 116 | ||
| 117 | pci_read_config_dword(entry->dev, msi_upper_address_reg(pos), | ||
| 118 | &address_hi); | ||
| 111 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), | 119 | pci_read_config_dword(entry->dev, msi_lower_address_reg(pos), |
| 112 | &address.lo_address.value); | 120 | &address_lo); |
| 113 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | 121 | |
| 114 | address.lo_address.value |= (cpu_physical_id(dest_cpu) << | 122 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); |
| 115 | MSI_TARGET_CPU_SHIFT); | 123 | |
| 116 | entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); | 124 | pci_write_config_dword(entry->dev, msi_upper_address_reg(pos), |
| 125 | address_hi); | ||
| 117 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), | 126 | pci_write_config_dword(entry->dev, msi_lower_address_reg(pos), |
| 118 | address.lo_address.value); | 127 | address_lo); |
| 119 | set_native_irq_info(irq, cpu_mask); | 128 | set_native_irq_info(irq, cpu_mask); |
| 120 | break; | 129 | break; |
| 121 | } | 130 | } |
| 122 | case PCI_CAP_ID_MSIX: | 131 | case PCI_CAP_ID_MSIX: |
| 123 | { | 132 | { |
| 124 | int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + | 133 | int offset_hi = |
| 125 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; | 134 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
| 126 | 135 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET; | |
| 127 | address.lo_address.value = readl(entry->mask_base + offset); | 136 | int offset_lo = |
| 128 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | 137 | entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + |
| 129 | address.lo_address.value |= (cpu_physical_id(dest_cpu) << | 138 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET; |
| 130 | MSI_TARGET_CPU_SHIFT); | 139 | |
| 131 | entry->msi_attrib.current_cpu = cpu_physical_id(dest_cpu); | 140 | address_hi = readl(entry->mask_base + offset_hi); |
| 132 | writel(address.lo_address.value, entry->mask_base + offset); | 141 | address_lo = readl(entry->mask_base + offset_lo); |
| 142 | |||
| 143 | msi_ops->target(vector, dest_cpu, &address_hi, &address_lo); | ||
| 144 | |||
| 145 | writel(address_hi, entry->mask_base + offset_hi); | ||
| 146 | writel(address_lo, entry->mask_base + offset_lo); | ||
| 133 | set_native_irq_info(irq, cpu_mask); | 147 | set_native_irq_info(irq, cpu_mask); |
| 134 | break; | 148 | break; |
| 135 | } | 149 | } |
| @@ -251,30 +265,6 @@ static struct hw_interrupt_type msi_irq_wo_maskbit_type = { | |||
| 251 | .set_affinity = set_msi_affinity | 265 | .set_affinity = set_msi_affinity |
| 252 | }; | 266 | }; |
| 253 | 267 | ||
| 254 | static void msi_data_init(struct msg_data *msi_data, | ||
| 255 | unsigned int vector) | ||
| 256 | { | ||
| 257 | memset(msi_data, 0, sizeof(struct msg_data)); | ||
| 258 | msi_data->vector = (u8)vector; | ||
| 259 | msi_data->delivery_mode = MSI_DELIVERY_MODE; | ||
| 260 | msi_data->level = MSI_LEVEL_MODE; | ||
| 261 | msi_data->trigger = MSI_TRIGGER_MODE; | ||
| 262 | } | ||
| 263 | |||
| 264 | static void msi_address_init(struct msg_address *msi_address) | ||
| 265 | { | ||
| 266 | unsigned int dest_id; | ||
| 267 | unsigned long dest_phys_id = cpu_physical_id(MSI_TARGET_CPU); | ||
| 268 | |||
| 269 | memset(msi_address, 0, sizeof(struct msg_address)); | ||
| 270 | msi_address->hi_address = (u32)0; | ||
| 271 | dest_id = (MSI_ADDRESS_HEADER << MSI_ADDRESS_HEADER_SHIFT); | ||
| 272 | msi_address->lo_address.u.dest_mode = MSI_PHYSICAL_MODE; | ||
| 273 | msi_address->lo_address.u.redirection_hint = MSI_REDIRECTION_HINT_MODE; | ||
| 274 | msi_address->lo_address.u.dest_id = dest_id; | ||
| 275 | msi_address->lo_address.value |= (dest_phys_id << MSI_TARGET_CPU_SHIFT); | ||
| 276 | } | ||
| 277 | |||
| 278 | static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); | 268 | static int msi_free_vector(struct pci_dev* dev, int vector, int reassign); |
| 279 | static int assign_msi_vector(void) | 269 | static int assign_msi_vector(void) |
| 280 | { | 270 | { |
| @@ -369,13 +359,29 @@ static int msi_init(void) | |||
| 369 | return status; | 359 | return status; |
| 370 | } | 360 | } |
| 371 | 361 | ||
| 362 | status = msi_arch_init(); | ||
| 363 | if (status < 0) { | ||
| 364 | pci_msi_enable = 0; | ||
| 365 | printk(KERN_WARNING | ||
| 366 | "PCI: MSI arch init failed. MSI disabled.\n"); | ||
| 367 | return status; | ||
| 368 | } | ||
| 369 | |||
| 370 | if (! msi_ops) { | ||
| 371 | printk(KERN_WARNING | ||
| 372 | "PCI: MSI ops not registered. MSI disabled.\n"); | ||
| 373 | status = -EINVAL; | ||
| 374 | return status; | ||
| 375 | } | ||
| 376 | |||
| 377 | last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); | ||
| 372 | status = msi_cache_init(); | 378 | status = msi_cache_init(); |
| 373 | if (status < 0) { | 379 | if (status < 0) { |
| 374 | pci_msi_enable = 0; | 380 | pci_msi_enable = 0; |
| 375 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); | 381 | printk(KERN_WARNING "PCI: MSI cache init failed\n"); |
| 376 | return status; | 382 | return status; |
| 377 | } | 383 | } |
| 378 | last_alloc_vector = assign_irq_vector(AUTO_ASSIGN); | 384 | |
| 379 | if (last_alloc_vector < 0) { | 385 | if (last_alloc_vector < 0) { |
| 380 | pci_msi_enable = 0; | 386 | pci_msi_enable = 0; |
| 381 | printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); | 387 | printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n"); |
| @@ -442,9 +448,11 @@ static void enable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
| 442 | /* Set enabled bits to single MSI & enable MSI_enable bit */ | 448 | /* Set enabled bits to single MSI & enable MSI_enable bit */ |
| 443 | msi_enable(control, 1); | 449 | msi_enable(control, 1); |
| 444 | pci_write_config_word(dev, msi_control_reg(pos), control); | 450 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 451 | dev->msi_enabled = 1; | ||
| 445 | } else { | 452 | } else { |
| 446 | msix_enable(control); | 453 | msix_enable(control); |
| 447 | pci_write_config_word(dev, msi_control_reg(pos), control); | 454 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 455 | dev->msix_enabled = 1; | ||
| 448 | } | 456 | } |
| 449 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { | 457 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { |
| 450 | /* PCI Express Endpoint device detected */ | 458 | /* PCI Express Endpoint device detected */ |
| @@ -461,9 +469,11 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type) | |||
| 461 | /* Set enabled bits to single MSI & enable MSI_enable bit */ | 469 | /* Set enabled bits to single MSI & enable MSI_enable bit */ |
| 462 | msi_disable(control); | 470 | msi_disable(control); |
| 463 | pci_write_config_word(dev, msi_control_reg(pos), control); | 471 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 472 | dev->msi_enabled = 0; | ||
| 464 | } else { | 473 | } else { |
| 465 | msix_disable(control); | 474 | msix_disable(control); |
| 466 | pci_write_config_word(dev, msi_control_reg(pos), control); | 475 | pci_write_config_word(dev, msi_control_reg(pos), control); |
| 476 | dev->msix_enabled = 0; | ||
| 467 | } | 477 | } |
| 468 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { | 478 | if (pci_find_capability(dev, PCI_CAP_ID_EXP)) { |
| 469 | /* PCI Express Endpoint device detected */ | 479 | /* PCI Express Endpoint device detected */ |
| @@ -538,7 +548,6 @@ int pci_save_msi_state(struct pci_dev *dev) | |||
| 538 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); | 548 | pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); |
| 539 | if (control & PCI_MSI_FLAGS_MASKBIT) | 549 | if (control & PCI_MSI_FLAGS_MASKBIT) |
| 540 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); | 550 | pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); |
| 541 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | ||
| 542 | save_state->cap_nr = PCI_CAP_ID_MSI; | 551 | save_state->cap_nr = PCI_CAP_ID_MSI; |
| 543 | pci_add_saved_cap(dev, save_state); | 552 | pci_add_saved_cap(dev, save_state); |
| 544 | return 0; | 553 | return 0; |
| @@ -575,6 +584,8 @@ void pci_restore_msi_state(struct pci_dev *dev) | |||
| 575 | int pci_save_msix_state(struct pci_dev *dev) | 584 | int pci_save_msix_state(struct pci_dev *dev) |
| 576 | { | 585 | { |
| 577 | int pos; | 586 | int pos; |
| 587 | int temp; | ||
| 588 | int vector, head, tail = 0; | ||
| 578 | u16 control; | 589 | u16 control; |
| 579 | struct pci_cap_saved_state *save_state; | 590 | struct pci_cap_saved_state *save_state; |
| 580 | 591 | ||
| @@ -582,6 +593,7 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
| 582 | if (pos <= 0 || dev->no_msi) | 593 | if (pos <= 0 || dev->no_msi) |
| 583 | return 0; | 594 | return 0; |
| 584 | 595 | ||
| 596 | /* save the capability */ | ||
| 585 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 597 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
| 586 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) | 598 | if (!(control & PCI_MSIX_FLAGS_ENABLE)) |
| 587 | return 0; | 599 | return 0; |
| @@ -593,7 +605,38 @@ int pci_save_msix_state(struct pci_dev *dev) | |||
| 593 | } | 605 | } |
| 594 | *((u16 *)&save_state->data[0]) = control; | 606 | *((u16 *)&save_state->data[0]) = control; |
| 595 | 607 | ||
| 596 | disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); | 608 | /* save the table */ |
| 609 | temp = dev->irq; | ||
| 610 | if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) { | ||
| 611 | kfree(save_state); | ||
| 612 | return -EINVAL; | ||
| 613 | } | ||
| 614 | |||
| 615 | vector = head = dev->irq; | ||
| 616 | while (head != tail) { | ||
| 617 | int j; | ||
| 618 | void __iomem *base; | ||
| 619 | struct msi_desc *entry; | ||
| 620 | |||
| 621 | entry = msi_desc[vector]; | ||
| 622 | base = entry->mask_base; | ||
| 623 | j = entry->msi_attrib.entry_nr; | ||
| 624 | |||
| 625 | entry->address_lo_save = | ||
| 626 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 627 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | ||
| 628 | entry->address_hi_save = | ||
| 629 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 630 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | ||
| 631 | entry->data_save = | ||
| 632 | readl(base + j * PCI_MSIX_ENTRY_SIZE + | ||
| 633 | PCI_MSIX_ENTRY_DATA_OFFSET); | ||
| 634 | |||
| 635 | tail = msi_desc[vector]->link.tail; | ||
| 636 | vector = tail; | ||
| 637 | } | ||
| 638 | dev->irq = temp; | ||
| 639 | |||
| 597 | save_state->cap_nr = PCI_CAP_ID_MSIX; | 640 | save_state->cap_nr = PCI_CAP_ID_MSIX; |
| 598 | pci_add_saved_cap(dev, save_state); | 641 | pci_add_saved_cap(dev, save_state); |
| 599 | return 0; | 642 | return 0; |
| @@ -606,8 +649,6 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
| 606 | int vector, head, tail = 0; | 649 | int vector, head, tail = 0; |
| 607 | void __iomem *base; | 650 | void __iomem *base; |
| 608 | int j; | 651 | int j; |
| 609 | struct msg_address address; | ||
| 610 | struct msg_data data; | ||
| 611 | struct msi_desc *entry; | 652 | struct msi_desc *entry; |
| 612 | int temp; | 653 | int temp; |
| 613 | struct pci_cap_saved_state *save_state; | 654 | struct pci_cap_saved_state *save_state; |
| @@ -633,20 +674,13 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
| 633 | base = entry->mask_base; | 674 | base = entry->mask_base; |
| 634 | j = entry->msi_attrib.entry_nr; | 675 | j = entry->msi_attrib.entry_nr; |
| 635 | 676 | ||
| 636 | msi_address_init(&address); | 677 | writel(entry->address_lo_save, |
| 637 | msi_data_init(&data, vector); | ||
| 638 | |||
| 639 | address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; | ||
| 640 | address.lo_address.value |= entry->msi_attrib.current_cpu << | ||
| 641 | MSI_TARGET_CPU_SHIFT; | ||
| 642 | |||
| 643 | writel(address.lo_address.value, | ||
| 644 | base + j * PCI_MSIX_ENTRY_SIZE + | 678 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 645 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | 679 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
| 646 | writel(address.hi_address, | 680 | writel(entry->address_hi_save, |
| 647 | base + j * PCI_MSIX_ENTRY_SIZE + | 681 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 648 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | 682 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
| 649 | writel(*(u32*)&data, | 683 | writel(entry->data_save, |
| 650 | base + j * PCI_MSIX_ENTRY_SIZE + | 684 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 651 | PCI_MSIX_ENTRY_DATA_OFFSET); | 685 | PCI_MSIX_ENTRY_DATA_OFFSET); |
| 652 | 686 | ||
| @@ -660,30 +694,32 @@ void pci_restore_msix_state(struct pci_dev *dev) | |||
| 660 | } | 694 | } |
| 661 | #endif | 695 | #endif |
| 662 | 696 | ||
| 663 | static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | 697 | static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry) |
| 664 | { | 698 | { |
| 665 | struct msg_address address; | 699 | int status; |
| 666 | struct msg_data data; | 700 | u32 address_hi; |
| 701 | u32 address_lo; | ||
| 702 | u32 data; | ||
| 667 | int pos, vector = dev->irq; | 703 | int pos, vector = dev->irq; |
| 668 | u16 control; | 704 | u16 control; |
| 669 | 705 | ||
| 670 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); | 706 | pos = pci_find_capability(dev, PCI_CAP_ID_MSI); |
| 671 | pci_read_config_word(dev, msi_control_reg(pos), &control); | 707 | pci_read_config_word(dev, msi_control_reg(pos), &control); |
| 708 | |||
| 672 | /* Configure MSI capability structure */ | 709 | /* Configure MSI capability structure */ |
| 673 | msi_address_init(&address); | 710 | status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data); |
| 674 | msi_data_init(&data, vector); | 711 | if (status < 0) |
| 675 | entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> | 712 | return status; |
| 676 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | 713 | |
| 677 | pci_write_config_dword(dev, msi_lower_address_reg(pos), | 714 | pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo); |
| 678 | address.lo_address.value); | ||
| 679 | if (is_64bit_address(control)) { | 715 | if (is_64bit_address(control)) { |
| 680 | pci_write_config_dword(dev, | 716 | pci_write_config_dword(dev, |
| 681 | msi_upper_address_reg(pos), address.hi_address); | 717 | msi_upper_address_reg(pos), address_hi); |
| 682 | pci_write_config_word(dev, | 718 | pci_write_config_word(dev, |
| 683 | msi_data_reg(pos, 1), *((u32*)&data)); | 719 | msi_data_reg(pos, 1), data); |
| 684 | } else | 720 | } else |
| 685 | pci_write_config_word(dev, | 721 | pci_write_config_word(dev, |
| 686 | msi_data_reg(pos, 0), *((u32*)&data)); | 722 | msi_data_reg(pos, 0), data); |
| 687 | if (entry->msi_attrib.maskbit) { | 723 | if (entry->msi_attrib.maskbit) { |
| 688 | unsigned int maskbits, temp; | 724 | unsigned int maskbits, temp; |
| 689 | /* All MSIs are unmasked by default, Mask them all */ | 725 | /* All MSIs are unmasked by default, Mask them all */ |
| @@ -697,6 +733,8 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
| 697 | msi_mask_bits_reg(pos, is_64bit_address(control)), | 733 | msi_mask_bits_reg(pos, is_64bit_address(control)), |
| 698 | maskbits); | 734 | maskbits); |
| 699 | } | 735 | } |
| 736 | |||
| 737 | return 0; | ||
| 700 | } | 738 | } |
| 701 | 739 | ||
| 702 | /** | 740 | /** |
| @@ -710,6 +748,7 @@ static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) | |||
| 710 | **/ | 748 | **/ |
| 711 | static int msi_capability_init(struct pci_dev *dev) | 749 | static int msi_capability_init(struct pci_dev *dev) |
| 712 | { | 750 | { |
| 751 | int status; | ||
| 713 | struct msi_desc *entry; | 752 | struct msi_desc *entry; |
| 714 | int pos, vector; | 753 | int pos, vector; |
| 715 | u16 control; | 754 | u16 control; |
| @@ -742,7 +781,12 @@ static int msi_capability_init(struct pci_dev *dev) | |||
| 742 | /* Replace with MSI handler */ | 781 | /* Replace with MSI handler */ |
| 743 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); | 782 | irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); |
| 744 | /* Configure MSI capability structure */ | 783 | /* Configure MSI capability structure */ |
| 745 | msi_register_init(dev, entry); | 784 | status = msi_register_init(dev, entry); |
| 785 | if (status != 0) { | ||
| 786 | dev->irq = entry->msi_attrib.default_vector; | ||
| 787 | kmem_cache_free(msi_cachep, entry); | ||
| 788 | return status; | ||
| 789 | } | ||
| 746 | 790 | ||
| 747 | attach_msi_entry(entry, vector); | 791 | attach_msi_entry(entry, vector); |
| 748 | /* Set MSI enabled bits */ | 792 | /* Set MSI enabled bits */ |
| @@ -765,8 +809,10 @@ static int msix_capability_init(struct pci_dev *dev, | |||
| 765 | struct msix_entry *entries, int nvec) | 809 | struct msix_entry *entries, int nvec) |
| 766 | { | 810 | { |
| 767 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; | 811 | struct msi_desc *head = NULL, *tail = NULL, *entry = NULL; |
| 768 | struct msg_address address; | 812 | u32 address_hi; |
| 769 | struct msg_data data; | 813 | u32 address_lo; |
| 814 | u32 data; | ||
| 815 | int status; | ||
| 770 | int vector, pos, i, j, nr_entries, temp = 0; | 816 | int vector, pos, i, j, nr_entries, temp = 0; |
| 771 | unsigned long phys_addr; | 817 | unsigned long phys_addr; |
| 772 | u32 table_offset; | 818 | u32 table_offset; |
| @@ -822,18 +868,20 @@ static int msix_capability_init(struct pci_dev *dev, | |||
| 822 | /* Replace with MSI-X handler */ | 868 | /* Replace with MSI-X handler */ |
| 823 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); | 869 | irq_handler_init(PCI_CAP_ID_MSIX, vector, 1); |
| 824 | /* Configure MSI-X capability structure */ | 870 | /* Configure MSI-X capability structure */ |
| 825 | msi_address_init(&address); | 871 | status = msi_ops->setup(dev, vector, |
| 826 | msi_data_init(&data, vector); | 872 | &address_hi, |
| 827 | entry->msi_attrib.current_cpu = | 873 | &address_lo, |
| 828 | ((address.lo_address.u.dest_id >> | 874 | &data); |
| 829 | MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); | 875 | if (status < 0) |
| 830 | writel(address.lo_address.value, | 876 | break; |
| 877 | |||
| 878 | writel(address_lo, | ||
| 831 | base + j * PCI_MSIX_ENTRY_SIZE + | 879 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 832 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); | 880 | PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); |
| 833 | writel(address.hi_address, | 881 | writel(address_hi, |
| 834 | base + j * PCI_MSIX_ENTRY_SIZE + | 882 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 835 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); | 883 | PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); |
| 836 | writel(*(u32*)&data, | 884 | writel(data, |
| 837 | base + j * PCI_MSIX_ENTRY_SIZE + | 885 | base + j * PCI_MSIX_ENTRY_SIZE + |
| 838 | PCI_MSIX_ENTRY_DATA_OFFSET); | 886 | PCI_MSIX_ENTRY_DATA_OFFSET); |
| 839 | attach_msi_entry(entry, vector); | 887 | attach_msi_entry(entry, vector); |
| @@ -865,6 +913,7 @@ static int msix_capability_init(struct pci_dev *dev, | |||
| 865 | **/ | 913 | **/ |
| 866 | int pci_enable_msi(struct pci_dev* dev) | 914 | int pci_enable_msi(struct pci_dev* dev) |
| 867 | { | 915 | { |
| 916 | struct pci_bus *bus; | ||
| 868 | int pos, temp, status = -EINVAL; | 917 | int pos, temp, status = -EINVAL; |
| 869 | u16 control; | 918 | u16 control; |
| 870 | 919 | ||
| @@ -874,8 +923,9 @@ int pci_enable_msi(struct pci_dev* dev) | |||
| 874 | if (dev->no_msi) | 923 | if (dev->no_msi) |
| 875 | return status; | 924 | return status; |
| 876 | 925 | ||
| 877 | if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | 926 | for (bus = dev->bus; bus; bus = bus->parent) |
| 878 | return -EINVAL; | 927 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) |
| 928 | return -EINVAL; | ||
| 879 | 929 | ||
| 880 | temp = dev->irq; | 930 | temp = dev->irq; |
| 881 | 931 | ||
| @@ -887,23 +937,23 @@ int pci_enable_msi(struct pci_dev* dev) | |||
| 887 | if (!pos) | 937 | if (!pos) |
| 888 | return -EINVAL; | 938 | return -EINVAL; |
| 889 | 939 | ||
| 890 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
| 891 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
| 892 | return 0; /* Already in MSI mode */ | ||
| 893 | |||
| 894 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { | 940 | if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) { |
| 895 | /* Lookup Sucess */ | 941 | /* Lookup Sucess */ |
| 896 | unsigned long flags; | 942 | unsigned long flags; |
| 897 | 943 | ||
| 944 | pci_read_config_word(dev, msi_control_reg(pos), &control); | ||
| 945 | if (control & PCI_MSI_FLAGS_ENABLE) | ||
| 946 | return 0; /* Already in MSI mode */ | ||
| 898 | spin_lock_irqsave(&msi_lock, flags); | 947 | spin_lock_irqsave(&msi_lock, flags); |
| 899 | if (!vector_irq[dev->irq]) { | 948 | if (!vector_irq[dev->irq]) { |
| 900 | msi_desc[dev->irq]->msi_attrib.state = 0; | 949 | msi_desc[dev->irq]->msi_attrib.state = 0; |
| 901 | vector_irq[dev->irq] = -1; | 950 | vector_irq[dev->irq] = -1; |
| 902 | nr_released_vectors--; | 951 | nr_released_vectors--; |
| 903 | spin_unlock_irqrestore(&msi_lock, flags); | 952 | spin_unlock_irqrestore(&msi_lock, flags); |
| 904 | msi_register_init(dev, msi_desc[dev->irq]); | 953 | status = msi_register_init(dev, msi_desc[dev->irq]); |
| 905 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); | 954 | if (status == 0) |
| 906 | return 0; | 955 | enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); |
| 956 | return status; | ||
| 907 | } | 957 | } |
| 908 | spin_unlock_irqrestore(&msi_lock, flags); | 958 | spin_unlock_irqrestore(&msi_lock, flags); |
| 909 | dev->irq = temp; | 959 | dev->irq = temp; |
| @@ -980,6 +1030,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
| 980 | void __iomem *base; | 1030 | void __iomem *base; |
| 981 | unsigned long flags; | 1031 | unsigned long flags; |
| 982 | 1032 | ||
| 1033 | msi_ops->teardown(vector); | ||
| 1034 | |||
| 983 | spin_lock_irqsave(&msi_lock, flags); | 1035 | spin_lock_irqsave(&msi_lock, flags); |
| 984 | entry = msi_desc[vector]; | 1036 | entry = msi_desc[vector]; |
| 985 | if (!entry || entry->dev != dev) { | 1037 | if (!entry || entry->dev != dev) { |
| @@ -1008,33 +1060,8 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign) | |||
| 1008 | entry_nr * PCI_MSIX_ENTRY_SIZE + | 1060 | entry_nr * PCI_MSIX_ENTRY_SIZE + |
| 1009 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); | 1061 | PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET); |
| 1010 | 1062 | ||
| 1011 | if (head == vector) { | 1063 | if (head == vector) |
| 1012 | /* | ||
| 1013 | * Detect last MSI-X vector to be released. | ||
| 1014 | * Release the MSI-X memory-mapped table. | ||
| 1015 | */ | ||
| 1016 | #if 0 | ||
| 1017 | int pos, nr_entries; | ||
| 1018 | unsigned long phys_addr; | ||
| 1019 | u32 table_offset; | ||
| 1020 | u16 control; | ||
| 1021 | u8 bir; | ||
| 1022 | |||
| 1023 | pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); | ||
| 1024 | pci_read_config_word(dev, msi_control_reg(pos), | ||
| 1025 | &control); | ||
| 1026 | nr_entries = multi_msix_capable(control); | ||
| 1027 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
| 1028 | &table_offset); | ||
| 1029 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
| 1030 | table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; | ||
| 1031 | phys_addr = pci_resource_start(dev, bir) + table_offset; | ||
| 1032 | /* | ||
| 1033 | * FIXME! and what did you want to do with phys_addr? | ||
| 1034 | */ | ||
| 1035 | #endif | ||
| 1036 | iounmap(base); | 1064 | iounmap(base); |
| 1037 | } | ||
| 1038 | } | 1065 | } |
| 1039 | 1066 | ||
| 1040 | return 0; | 1067 | return 0; |
| @@ -1108,6 +1135,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec) | |||
| 1108 | **/ | 1135 | **/ |
| 1109 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | 1136 | int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) |
| 1110 | { | 1137 | { |
| 1138 | struct pci_bus *bus; | ||
| 1111 | int status, pos, nr_entries, free_vectors; | 1139 | int status, pos, nr_entries, free_vectors; |
| 1112 | int i, j, temp; | 1140 | int i, j, temp; |
| 1113 | u16 control; | 1141 | u16 control; |
| @@ -1116,6 +1144,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) | |||
| 1116 | if (!pci_msi_enable || !dev || !entries) | 1144 | if (!pci_msi_enable || !dev || !entries) |
| 1117 | return -EINVAL; | 1145 | return -EINVAL; |
| 1118 | 1146 | ||
| 1147 | if (dev->no_msi) | ||
| 1148 | return -EINVAL; | ||
| 1149 | |||
| 1150 | for (bus = dev->bus; bus; bus = bus->parent) | ||
| 1151 | if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) | ||
| 1152 | return -EINVAL; | ||
| 1153 | |||
| 1119 | status = msi_init(); | 1154 | status = msi_init(); |
| 1120 | if (status < 0) | 1155 | if (status < 0) |
| 1121 | return status; | 1156 | return status; |
| @@ -1300,24 +1335,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev) | |||
| 1300 | } | 1335 | } |
| 1301 | msi_free_vector(dev, vector, 0); | 1336 | msi_free_vector(dev, vector, 0); |
| 1302 | if (warning) { | 1337 | if (warning) { |
| 1303 | /* Force to release the MSI-X memory-mapped table */ | ||
| 1304 | #if 0 | ||
| 1305 | unsigned long phys_addr; | ||
| 1306 | u32 table_offset; | ||
| 1307 | u16 control; | ||
| 1308 | u8 bir; | ||
| 1309 | |||
| 1310 | pci_read_config_word(dev, msi_control_reg(pos), | ||
| 1311 | &control); | ||
| 1312 | pci_read_config_dword(dev, msix_table_offset_reg(pos), | ||
| 1313 | &table_offset); | ||
| 1314 | bir = (u8)(table_offset & PCI_MSIX_FLAGS_BIRMASK); | ||
| 1315 | table_offset &= ~PCI_MSIX_FLAGS_BIRMASK; | ||
| 1316 | phys_addr = pci_resource_start(dev, bir) + table_offset; | ||
| 1317 | /* | ||
| 1318 | * FIXME! and what did you want to do with phys_addr? | ||
| 1319 | */ | ||
| 1320 | #endif | ||
| 1321 | iounmap(base); | 1338 | iounmap(base); |
| 1322 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " | 1339 | printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() " |
| 1323 | "called without free_irq() on all MSI-X vectors\n", | 1340 | "called without free_irq() on all MSI-X vectors\n", |
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h index 4ac52d441e47..56951c39d3a3 100644 --- a/drivers/pci/msi.h +++ b/drivers/pci/msi.h | |||
| @@ -6,6 +6,68 @@ | |||
| 6 | #ifndef MSI_H | 6 | #ifndef MSI_H |
| 7 | #define MSI_H | 7 | #define MSI_H |
| 8 | 8 | ||
| 9 | /* | ||
| 10 | * MSI operation vector. Used by the msi core code (drivers/pci/msi.c) | ||
| 11 | * to abstract platform-specific tasks relating to MSI address generation | ||
| 12 | * and resource management. | ||
| 13 | */ | ||
| 14 | struct msi_ops { | ||
| 15 | /** | ||
| 16 | * setup - generate an MSI bus address and data for a given vector | ||
| 17 | * @pdev: PCI device context (in) | ||
| 18 | * @vector: vector allocated by the msi core (in) | ||
| 19 | * @addr_hi: upper 32 bits of PCI bus MSI address (out) | ||
| 20 | * @addr_lo: lower 32 bits of PCI bus MSI address (out) | ||
| 21 | * @data: MSI data payload (out) | ||
| 22 | * | ||
| 23 | * Description: The setup op is used to generate a PCI bus addres and | ||
| 24 | * data which the msi core will program into the card MSI capability | ||
| 25 | * registers. The setup routine is responsible for picking an initial | ||
| 26 | * cpu to target the MSI at. The setup routine is responsible for | ||
| 27 | * examining pdev to determine the MSI capabilities of the card and | ||
| 28 | * generating a suitable address/data. The setup routine is | ||
| 29 | * responsible for allocating and tracking any system resources it | ||
| 30 | * needs to route the MSI to the cpu it picks, and for associating | ||
| 31 | * those resources with the passed in vector. | ||
| 32 | * | ||
| 33 | * Returns 0 if the MSI address/data was successfully setup. | ||
| 34 | **/ | ||
| 35 | |||
| 36 | int (*setup) (struct pci_dev *pdev, unsigned int vector, | ||
| 37 | u32 *addr_hi, u32 *addr_lo, u32 *data); | ||
| 38 | |||
| 39 | /** | ||
| 40 | * teardown - release resources allocated by setup | ||
| 41 | * @vector: vector context for resources (in) | ||
| 42 | * | ||
| 43 | * Description: The teardown op is used to release any resources | ||
| 44 | * that were allocated in the setup routine associated with the passed | ||
| 45 | * in vector. | ||
| 46 | **/ | ||
| 47 | |||
| 48 | void (*teardown) (unsigned int vector); | ||
| 49 | |||
| 50 | /** | ||
| 51 | * target - retarget an MSI at a different cpu | ||
| 52 | * @vector: vector context for resources (in) | ||
| 53 | * @cpu: new cpu to direct vector at (in) | ||
| 54 | * @addr_hi: new value of PCI bus upper 32 bits (in/out) | ||
| 55 | * @addr_lo: new value of PCI bus lower 32 bits (in/out) | ||
| 56 | * | ||
| 57 | * Description: The target op is used to redirect an MSI vector | ||
| 58 | * at a different cpu. addr_hi/addr_lo coming in are the existing | ||
| 59 | * values that the MSI core has programmed into the card. The | ||
| 60 | * target code is responsible for freeing any resources (if any) | ||
| 61 | * associated with the old address, and generating a new PCI bus | ||
| 62 | * addr_hi/addr_lo that will redirect the vector at the indicated cpu. | ||
| 63 | **/ | ||
| 64 | |||
| 65 | void (*target) (unsigned int vector, unsigned int cpu, | ||
| 66 | u32 *addr_hi, u32 *addr_lo); | ||
| 67 | }; | ||
| 68 | |||
| 69 | extern int msi_register(struct msi_ops *ops); | ||
| 70 | |||
| 9 | #include <asm/msi.h> | 71 | #include <asm/msi.h> |
| 10 | 72 | ||
| 11 | /* | 73 | /* |
| @@ -63,67 +125,6 @@ extern int pci_vector_resources(int last, int nr_released); | |||
| 63 | #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) | 125 | #define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK) |
| 64 | #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) | 126 | #define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK) |
| 65 | 127 | ||
| 66 | /* | ||
| 67 | * MSI Defined Data Structures | ||
| 68 | */ | ||
| 69 | #define MSI_ADDRESS_HEADER 0xfee | ||
| 70 | #define MSI_ADDRESS_HEADER_SHIFT 12 | ||
| 71 | #define MSI_ADDRESS_HEADER_MASK 0xfff000 | ||
| 72 | #define MSI_ADDRESS_DEST_ID_MASK 0xfff0000f | ||
| 73 | #define MSI_TARGET_CPU_MASK 0xff | ||
| 74 | #define MSI_DELIVERY_MODE 0 | ||
| 75 | #define MSI_LEVEL_MODE 1 /* Edge always assert */ | ||
| 76 | #define MSI_TRIGGER_MODE 0 /* MSI is edge sensitive */ | ||
| 77 | #define MSI_PHYSICAL_MODE 0 | ||
| 78 | #define MSI_LOGICAL_MODE 1 | ||
| 79 | #define MSI_REDIRECTION_HINT_MODE 0 | ||
| 80 | |||
| 81 | struct msg_data { | ||
| 82 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
| 83 | __u32 vector : 8; | ||
| 84 | __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ | ||
| 85 | __u32 reserved_1 : 3; | ||
| 86 | __u32 level : 1; /* 0: deassert | 1: assert */ | ||
| 87 | __u32 trigger : 1; /* 0: edge | 1: level */ | ||
| 88 | __u32 reserved_2 : 16; | ||
| 89 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
| 90 | __u32 reserved_2 : 16; | ||
| 91 | __u32 trigger : 1; /* 0: edge | 1: level */ | ||
| 92 | __u32 level : 1; /* 0: deassert | 1: assert */ | ||
| 93 | __u32 reserved_1 : 3; | ||
| 94 | __u32 delivery_mode : 3; /* 000b: FIXED | 001b: lowest prior */ | ||
| 95 | __u32 vector : 8; | ||
| 96 | #else | ||
| 97 | #error "Bitfield endianness not defined! Check your byteorder.h" | ||
| 98 | #endif | ||
| 99 | } __attribute__ ((packed)); | ||
| 100 | |||
| 101 | struct msg_address { | ||
| 102 | union { | ||
| 103 | struct { | ||
| 104 | #if defined(__LITTLE_ENDIAN_BITFIELD) | ||
| 105 | __u32 reserved_1 : 2; | ||
| 106 | __u32 dest_mode : 1; /*0:physic | 1:logic */ | ||
| 107 | __u32 redirection_hint: 1; /*0: dedicated CPU | ||
| 108 | 1: lowest priority */ | ||
| 109 | __u32 reserved_2 : 4; | ||
| 110 | __u32 dest_id : 24; /* Destination ID */ | ||
| 111 | #elif defined(__BIG_ENDIAN_BITFIELD) | ||
| 112 | __u32 dest_id : 24; /* Destination ID */ | ||
| 113 | __u32 reserved_2 : 4; | ||
| 114 | __u32 redirection_hint: 1; /*0: dedicated CPU | ||
| 115 | 1: lowest priority */ | ||
| 116 | __u32 dest_mode : 1; /*0:physic | 1:logic */ | ||
| 117 | __u32 reserved_1 : 2; | ||
| 118 | #else | ||
| 119 | #error "Bitfield endianness not defined! Check your byteorder.h" | ||
| 120 | #endif | ||
| 121 | }u; | ||
| 122 | __u32 value; | ||
| 123 | }lo_address; | ||
| 124 | __u32 hi_address; | ||
| 125 | } __attribute__ ((packed)); | ||
| 126 | |||
| 127 | struct msi_desc { | 128 | struct msi_desc { |
| 128 | struct { | 129 | struct { |
| 129 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ | 130 | __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */ |
| @@ -132,7 +133,7 @@ struct msi_desc { | |||
| 132 | __u8 reserved: 1; /* reserved */ | 133 | __u8 reserved: 1; /* reserved */ |
| 133 | __u8 entry_nr; /* specific enabled entry */ | 134 | __u8 entry_nr; /* specific enabled entry */ |
| 134 | __u8 default_vector; /* default pre-assigned vector */ | 135 | __u8 default_vector; /* default pre-assigned vector */ |
| 135 | __u8 current_cpu; /* current destination cpu */ | 136 | __u8 unused; /* formerly unused destination cpu*/ |
| 136 | }msi_attrib; | 137 | }msi_attrib; |
| 137 | 138 | ||
| 138 | struct { | 139 | struct { |
| @@ -142,6 +143,14 @@ struct msi_desc { | |||
| 142 | 143 | ||
| 143 | void __iomem *mask_base; | 144 | void __iomem *mask_base; |
| 144 | struct pci_dev *dev; | 145 | struct pci_dev *dev; |
| 146 | |||
| 147 | #ifdef CONFIG_PM | ||
| 148 | /* PM save area for MSIX address/data */ | ||
| 149 | |||
| 150 | u32 address_hi_save; | ||
| 151 | u32 address_lo_save; | ||
| 152 | u32 data_save; | ||
| 153 | #endif | ||
| 145 | }; | 154 | }; |
| 146 | 155 | ||
| 147 | #endif /* MSI_H */ | 156 | #endif /* MSI_H */ |
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c2ecae5ff0c1..bb7456c1dbac 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
| @@ -267,7 +267,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) | |||
| 267 | 267 | ||
| 268 | 268 | ||
| 269 | /* ACPI bus type */ | 269 | /* ACPI bus type */ |
| 270 | static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) | 270 | static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) |
| 271 | { | 271 | { |
| 272 | struct pci_dev * pci_dev; | 272 | struct pci_dev * pci_dev; |
| 273 | acpi_integer addr; | 273 | acpi_integer addr; |
| @@ -281,7 +281,7 @@ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) | |||
| 281 | return 0; | 281 | return 0; |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) | 284 | static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) |
| 285 | { | 285 | { |
| 286 | int num; | 286 | int num; |
| 287 | unsigned int seg, bus; | 287 | unsigned int seg, bus; |
| @@ -299,21 +299,21 @@ static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) | |||
| 299 | return 0; | 299 | return 0; |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | static struct acpi_bus_type pci_acpi_bus = { | 302 | static struct acpi_bus_type acpi_pci_bus = { |
| 303 | .bus = &pci_bus_type, | 303 | .bus = &pci_bus_type, |
| 304 | .find_device = pci_acpi_find_device, | 304 | .find_device = acpi_pci_find_device, |
| 305 | .find_bridge = pci_acpi_find_root_bridge, | 305 | .find_bridge = acpi_pci_find_root_bridge, |
| 306 | }; | 306 | }; |
| 307 | 307 | ||
| 308 | static int __init pci_acpi_init(void) | 308 | static int __init acpi_pci_init(void) |
| 309 | { | 309 | { |
| 310 | int ret; | 310 | int ret; |
| 311 | 311 | ||
| 312 | ret = register_acpi_bus_type(&pci_acpi_bus); | 312 | ret = register_acpi_bus_type(&acpi_pci_bus); |
| 313 | if (ret) | 313 | if (ret) |
| 314 | return 0; | 314 | return 0; |
| 315 | platform_pci_choose_state = acpi_pci_choose_state; | 315 | platform_pci_choose_state = acpi_pci_choose_state; |
| 316 | platform_pci_set_power_state = acpi_pci_set_power_state; | 316 | platform_pci_set_power_state = acpi_pci_set_power_state; |
| 317 | return 0; | 317 | return 0; |
| 318 | } | 318 | } |
| 319 | arch_initcall(pci_acpi_init); | 319 | arch_initcall(acpi_pci_init); |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 56ac2bc003c7..bc405c035ce3 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
| @@ -43,6 +43,29 @@ pci_config_attr(subsystem_vendor, "0x%04x\n"); | |||
| 43 | pci_config_attr(subsystem_device, "0x%04x\n"); | 43 | pci_config_attr(subsystem_device, "0x%04x\n"); |
| 44 | pci_config_attr(class, "0x%06x\n"); | 44 | pci_config_attr(class, "0x%06x\n"); |
| 45 | pci_config_attr(irq, "%u\n"); | 45 | pci_config_attr(irq, "%u\n"); |
| 46 | pci_config_attr(is_enabled, "%u\n"); | ||
| 47 | |||
| 48 | static ssize_t broken_parity_status_show(struct device *dev, | ||
| 49 | struct device_attribute *attr, | ||
| 50 | char *buf) | ||
| 51 | { | ||
| 52 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 53 | return sprintf (buf, "%u\n", pdev->broken_parity_status); | ||
| 54 | } | ||
| 55 | |||
| 56 | static ssize_t broken_parity_status_store(struct device *dev, | ||
| 57 | struct device_attribute *attr, | ||
| 58 | const char *buf, size_t count) | ||
| 59 | { | ||
| 60 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 61 | ssize_t consumed = -EINVAL; | ||
| 62 | |||
| 63 | if ((count > 0) && (*buf == '0' || *buf == '1')) { | ||
| 64 | pdev->broken_parity_status = *buf == '1' ? 1 : 0; | ||
| 65 | consumed = count; | ||
| 66 | } | ||
| 67 | return consumed; | ||
| 68 | } | ||
| 46 | 69 | ||
| 47 | static ssize_t local_cpus_show(struct device *dev, | 70 | static ssize_t local_cpus_show(struct device *dev, |
| 48 | struct device_attribute *attr, char *buf) | 71 | struct device_attribute *attr, char *buf) |
| @@ -90,6 +113,25 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | |||
| 90 | (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), | 113 | (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8), |
| 91 | (u8)(pci_dev->class)); | 114 | (u8)(pci_dev->class)); |
| 92 | } | 115 | } |
| 116 | static ssize_t | ||
| 117 | is_enabled_store(struct device *dev, struct device_attribute *attr, | ||
| 118 | const char *buf, size_t count) | ||
| 119 | { | ||
| 120 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 121 | |||
| 122 | /* this can crash the machine when done on the "wrong" device */ | ||
| 123 | if (!capable(CAP_SYS_ADMIN)) | ||
| 124 | return count; | ||
| 125 | |||
| 126 | if (*buf == '0') | ||
| 127 | pci_disable_device(pdev); | ||
| 128 | |||
| 129 | if (*buf == '1') | ||
| 130 | pci_enable_device(pdev); | ||
| 131 | |||
| 132 | return count; | ||
| 133 | } | ||
| 134 | |||
| 93 | 135 | ||
| 94 | struct device_attribute pci_dev_attrs[] = { | 136 | struct device_attribute pci_dev_attrs[] = { |
| 95 | __ATTR_RO(resource), | 137 | __ATTR_RO(resource), |
| @@ -101,6 +143,9 @@ struct device_attribute pci_dev_attrs[] = { | |||
| 101 | __ATTR_RO(irq), | 143 | __ATTR_RO(irq), |
| 102 | __ATTR_RO(local_cpus), | 144 | __ATTR_RO(local_cpus), |
| 103 | __ATTR_RO(modalias), | 145 | __ATTR_RO(modalias), |
| 146 | __ATTR(enable, 0600, is_enabled_show, is_enabled_store), | ||
| 147 | __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), | ||
| 148 | broken_parity_status_show,broken_parity_status_store), | ||
| 104 | __ATTR_NULL, | 149 | __ATTR_NULL, |
| 105 | }; | 150 | }; |
| 106 | 151 | ||
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index fde41cc14734..d408a3c30426 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
| @@ -517,7 +517,12 @@ pci_enable_device_bars(struct pci_dev *dev, int bars) | |||
| 517 | int | 517 | int |
| 518 | pci_enable_device(struct pci_dev *dev) | 518 | pci_enable_device(struct pci_dev *dev) |
| 519 | { | 519 | { |
| 520 | int err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); | 520 | int err; |
| 521 | |||
| 522 | if (dev->is_enabled) | ||
| 523 | return 0; | ||
| 524 | |||
| 525 | err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1); | ||
| 521 | if (err) | 526 | if (err) |
| 522 | return err; | 527 | return err; |
| 523 | pci_fixup_device(pci_fixup_enable, dev); | 528 | pci_fixup_device(pci_fixup_enable, dev); |
| @@ -546,7 +551,14 @@ void | |||
| 546 | pci_disable_device(struct pci_dev *dev) | 551 | pci_disable_device(struct pci_dev *dev) |
| 547 | { | 552 | { |
| 548 | u16 pci_command; | 553 | u16 pci_command; |
| 549 | 554 | ||
| 555 | if (dev->msi_enabled) | ||
| 556 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), | ||
| 557 | PCI_CAP_ID_MSI); | ||
| 558 | if (dev->msix_enabled) | ||
| 559 | disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), | ||
| 560 | PCI_CAP_ID_MSIX); | ||
| 561 | |||
| 550 | pci_read_config_word(dev, PCI_COMMAND, &pci_command); | 562 | pci_read_config_word(dev, PCI_COMMAND, &pci_command); |
| 551 | if (pci_command & PCI_COMMAND_MASTER) { | 563 | if (pci_command & PCI_COMMAND_MASTER) { |
| 552 | pci_command &= ~PCI_COMMAND_MASTER; | 564 | pci_command &= ~PCI_COMMAND_MASTER; |
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 30630cbe2fe3..29bdeca031a8 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
| @@ -40,7 +40,7 @@ extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int | |||
| 40 | extern void pci_remove_legacy_files(struct pci_bus *bus); | 40 | extern void pci_remove_legacy_files(struct pci_bus *bus); |
| 41 | 41 | ||
| 42 | /* Lock for read/write access to pci device and bus lists */ | 42 | /* Lock for read/write access to pci device and bus lists */ |
| 43 | extern spinlock_t pci_bus_lock; | 43 | extern struct rw_semaphore pci_bus_sem; |
| 44 | 44 | ||
| 45 | #ifdef CONFIG_X86_IO_APIC | 45 | #ifdef CONFIG_X86_IO_APIC |
| 46 | extern int pci_msi_quirk; | 46 | extern int pci_msi_quirk; |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a10ed9dab2c2..f89dbc3738b7 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
| @@ -180,25 +180,31 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) | |||
| 180 | res->flags |= pci_calc_resource_flags(l); | 180 | res->flags |= pci_calc_resource_flags(l); |
| 181 | if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) | 181 | if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK)) |
| 182 | == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { | 182 | == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) { |
| 183 | pci_read_config_dword(dev, reg+4, &l); | 183 | u32 szhi, lhi; |
| 184 | pci_read_config_dword(dev, reg+4, &lhi); | ||
| 185 | pci_write_config_dword(dev, reg+4, ~0); | ||
| 186 | pci_read_config_dword(dev, reg+4, &szhi); | ||
| 187 | pci_write_config_dword(dev, reg+4, lhi); | ||
| 188 | szhi = pci_size(lhi, szhi, 0xffffffff); | ||
| 184 | next++; | 189 | next++; |
| 185 | #if BITS_PER_LONG == 64 | 190 | #if BITS_PER_LONG == 64 |
| 186 | res->start |= ((unsigned long) l) << 32; | 191 | res->start |= ((unsigned long) lhi) << 32; |
| 187 | res->end = res->start + sz; | 192 | res->end = res->start + sz; |
| 188 | pci_write_config_dword(dev, reg+4, ~0); | 193 | if (szhi) { |
| 189 | pci_read_config_dword(dev, reg+4, &sz); | ||
| 190 | pci_write_config_dword(dev, reg+4, l); | ||
| 191 | sz = pci_size(l, sz, 0xffffffff); | ||
| 192 | if (sz) { | ||
| 193 | /* This BAR needs > 4GB? Wow. */ | 194 | /* This BAR needs > 4GB? Wow. */ |
| 194 | res->end |= (unsigned long)sz<<32; | 195 | res->end |= (unsigned long)szhi<<32; |
| 195 | } | 196 | } |
| 196 | #else | 197 | #else |
| 197 | if (l) { | 198 | if (szhi) { |
| 198 | printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev)); | 199 | printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev)); |
| 199 | res->start = 0; | 200 | res->start = 0; |
| 200 | res->flags = 0; | 201 | res->flags = 0; |
| 201 | continue; | 202 | } else if (lhi) { |
| 203 | /* 64-bit wide address, treat as disabled */ | ||
| 204 | pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK); | ||
| 205 | pci_write_config_dword(dev, reg+4, 0); | ||
| 206 | res->start = 0; | ||
| 207 | res->end = sz; | ||
| 202 | } | 208 | } |
| 203 | #endif | 209 | #endif |
| 204 | } | 210 | } |
| @@ -377,9 +383,9 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de | |||
| 377 | 383 | ||
| 378 | child = pci_alloc_child_bus(parent, dev, busnr); | 384 | child = pci_alloc_child_bus(parent, dev, busnr); |
| 379 | if (child) { | 385 | if (child) { |
| 380 | spin_lock(&pci_bus_lock); | 386 | down_write(&pci_bus_sem); |
| 381 | list_add_tail(&child->node, &parent->children); | 387 | list_add_tail(&child->node, &parent->children); |
| 382 | spin_unlock(&pci_bus_lock); | 388 | up_write(&pci_bus_sem); |
| 383 | } | 389 | } |
| 384 | return child; | 390 | return child; |
| 385 | } | 391 | } |
| @@ -838,9 +844,9 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus) | |||
| 838 | * and the bus list for fixup functions, etc. | 844 | * and the bus list for fixup functions, etc. |
| 839 | */ | 845 | */ |
| 840 | INIT_LIST_HEAD(&dev->global_list); | 846 | INIT_LIST_HEAD(&dev->global_list); |
| 841 | spin_lock(&pci_bus_lock); | 847 | down_write(&pci_bus_sem); |
| 842 | list_add_tail(&dev->bus_list, &bus->devices); | 848 | list_add_tail(&dev->bus_list, &bus->devices); |
| 843 | spin_unlock(&pci_bus_lock); | 849 | up_write(&pci_bus_sem); |
| 844 | } | 850 | } |
| 845 | 851 | ||
| 846 | struct pci_dev * __devinit | 852 | struct pci_dev * __devinit |
| @@ -975,9 +981,10 @@ struct pci_bus * __devinit pci_create_bus(struct device *parent, | |||
| 975 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); | 981 | pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); |
| 976 | goto err_out; | 982 | goto err_out; |
| 977 | } | 983 | } |
| 978 | spin_lock(&pci_bus_lock); | 984 | |
| 985 | down_write(&pci_bus_sem); | ||
| 979 | list_add_tail(&b->node, &pci_root_buses); | 986 | list_add_tail(&b->node, &pci_root_buses); |
| 980 | spin_unlock(&pci_bus_lock); | 987 | up_write(&pci_bus_sem); |
| 981 | 988 | ||
| 982 | memset(dev, 0, sizeof(*dev)); | 989 | memset(dev, 0, sizeof(*dev)); |
| 983 | dev->parent = parent; | 990 | dev->parent = parent; |
| @@ -1017,9 +1024,9 @@ class_dev_create_file_err: | |||
| 1017 | class_dev_reg_err: | 1024 | class_dev_reg_err: |
| 1018 | device_unregister(dev); | 1025 | device_unregister(dev); |
| 1019 | dev_reg_err: | 1026 | dev_reg_err: |
| 1020 | spin_lock(&pci_bus_lock); | 1027 | down_write(&pci_bus_sem); |
| 1021 | list_del(&b->node); | 1028 | list_del(&b->node); |
| 1022 | spin_unlock(&pci_bus_lock); | 1029 | up_write(&pci_bus_sem); |
| 1023 | err_out: | 1030 | err_out: |
| 1024 | kfree(dev); | 1031 | kfree(dev); |
| 1025 | kfree(b); | 1032 | kfree(b); |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d378478612fb..4364d793f73b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
| @@ -24,6 +24,17 @@ | |||
| 24 | #include <linux/acpi.h> | 24 | #include <linux/acpi.h> |
| 25 | #include "pci.h" | 25 | #include "pci.h" |
| 26 | 26 | ||
| 27 | /* The Mellanox Tavor device gives false positive parity errors | ||
| 28 | * Mark this device with a broken_parity_status, to allow | ||
| 29 | * PCI scanning code to "skip" this now blacklisted device. | ||
| 30 | */ | ||
| 31 | static void __devinit quirk_mellanox_tavor(struct pci_dev *dev) | ||
| 32 | { | ||
| 33 | dev->broken_parity_status = 1; /* This device gives false positives */ | ||
| 34 | } | ||
| 35 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR,quirk_mellanox_tavor); | ||
| 36 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE,quirk_mellanox_tavor); | ||
| 37 | |||
| 27 | /* Deal with broken BIOS'es that neglect to enable passive release, | 38 | /* Deal with broken BIOS'es that neglect to enable passive release, |
| 28 | which can cause problems in combination with the 82441FX/PPro MTRRs */ | 39 | which can cause problems in combination with the 82441FX/PPro MTRRs */ |
| 29 | static void __devinit quirk_passive_release(struct pci_dev *dev) | 40 | static void __devinit quirk_passive_release(struct pci_dev *dev) |
| @@ -878,27 +889,30 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e | |||
| 878 | * when a PCI-Soundcard is added. The BIOS only gives Options | 889 | * when a PCI-Soundcard is added. The BIOS only gives Options |
| 879 | * "Disabled" and "AUTO". This Quirk Sets the corresponding | 890 | * "Disabled" and "AUTO". This Quirk Sets the corresponding |
| 880 | * Register-Value to enable the Soundcard. | 891 | * Register-Value to enable the Soundcard. |
| 892 | * | ||
| 893 | * FIXME: Presently this quirk will run on anything that has an 8237 | ||
| 894 | * which isn't correct, we need to check DMI tables or something in | ||
| 895 | * order to make sure it only runs on the MSI-K8T-Neo2Fir. Because it | ||
| 896 | * runs everywhere at present we suppress the printk output in most | ||
| 897 | * irrelevant cases. | ||
| 881 | */ | 898 | */ |
| 882 | static void __init k8t_sound_hostbridge(struct pci_dev *dev) | 899 | static void __init k8t_sound_hostbridge(struct pci_dev *dev) |
| 883 | { | 900 | { |
| 884 | unsigned char val; | 901 | unsigned char val; |
| 885 | 902 | ||
| 886 | printk(KERN_INFO "PCI: Quirk-MSI-K8T Soundcard On\n"); | ||
| 887 | pci_read_config_byte(dev, 0x50, &val); | 903 | pci_read_config_byte(dev, 0x50, &val); |
| 888 | if (val == 0x88 || val == 0xc8) { | 904 | if (val == 0x88 || val == 0xc8) { |
| 905 | /* Assume it's probably a MSI-K8T-Neo2Fir */ | ||
| 906 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n"); | ||
| 889 | pci_write_config_byte(dev, 0x50, val & (~0x40)); | 907 | pci_write_config_byte(dev, 0x50, val & (~0x40)); |
| 890 | 908 | ||
| 891 | /* Verify the Change for Status output */ | 909 | /* Verify the Change for Status output */ |
| 892 | pci_read_config_byte(dev, 0x50, &val); | 910 | pci_read_config_byte(dev, 0x50, &val); |
| 893 | if (val & 0x40) | 911 | if (val & 0x40) |
| 894 | printk(KERN_INFO "PCI: MSI-K8T soundcard still off\n"); | 912 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n"); |
| 895 | else | 913 | else |
| 896 | printk(KERN_INFO "PCI: MSI-K8T soundcard on\n"); | 914 | printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n"); |
| 897 | } else { | ||
| 898 | printk(KERN_INFO "PCI: Unexpected Value in PCI-Register: " | ||
| 899 | "no Change!\n"); | ||
| 900 | } | 915 | } |
| 901 | |||
| 902 | } | 916 | } |
| 903 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); | 917 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge); |
| 904 | 918 | ||
| @@ -1485,6 +1499,25 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) | |||
| 1485 | } | 1499 | } |
| 1486 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); | 1500 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io); |
| 1487 | 1501 | ||
| 1502 | /* Under some circumstances, AER is not linked with extended capabilities. | ||
| 1503 | * Force it to be linked by setting the corresponding control bit in the | ||
| 1504 | * config space. | ||
| 1505 | */ | ||
| 1506 | static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev) | ||
| 1507 | { | ||
| 1508 | uint8_t b; | ||
| 1509 | if (pci_read_config_byte(dev, 0xf41, &b) == 0) { | ||
| 1510 | if (!(b & 0x20)) { | ||
| 1511 | pci_write_config_byte(dev, 0xf41, b | 0x20); | ||
| 1512 | printk(KERN_INFO | ||
| 1513 | "PCI: Linking AER extended capability on %s\n", | ||
| 1514 | pci_name(dev)); | ||
| 1515 | } | ||
| 1516 | } | ||
| 1517 | } | ||
| 1518 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, | ||
| 1519 | quirk_nvidia_ck804_pcie_aer_ext_cap); | ||
| 1520 | |||
| 1488 | EXPORT_SYMBOL(pcie_mch_quirk); | 1521 | EXPORT_SYMBOL(pcie_mch_quirk); |
| 1489 | #ifdef CONFIG_HOTPLUG | 1522 | #ifdef CONFIG_HOTPLUG |
| 1490 | EXPORT_SYMBOL(pci_fixup_device); | 1523 | EXPORT_SYMBOL(pci_fixup_device); |
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 1a6bf9de166f..99ffbd478b29 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c | |||
| @@ -22,18 +22,18 @@ static void pci_destroy_dev(struct pci_dev *dev) | |||
| 22 | pci_proc_detach_device(dev); | 22 | pci_proc_detach_device(dev); |
| 23 | pci_remove_sysfs_dev_files(dev); | 23 | pci_remove_sysfs_dev_files(dev); |
| 24 | device_unregister(&dev->dev); | 24 | device_unregister(&dev->dev); |
| 25 | spin_lock(&pci_bus_lock); | 25 | down_write(&pci_bus_sem); |
| 26 | list_del(&dev->global_list); | 26 | list_del(&dev->global_list); |
| 27 | dev->global_list.next = dev->global_list.prev = NULL; | 27 | dev->global_list.next = dev->global_list.prev = NULL; |
| 28 | spin_unlock(&pci_bus_lock); | 28 | up_write(&pci_bus_sem); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | /* Remove the device from the device lists, and prevent any further | 31 | /* Remove the device from the device lists, and prevent any further |
| 32 | * list accesses from this device */ | 32 | * list accesses from this device */ |
| 33 | spin_lock(&pci_bus_lock); | 33 | down_write(&pci_bus_sem); |
| 34 | list_del(&dev->bus_list); | 34 | list_del(&dev->bus_list); |
| 35 | dev->bus_list.next = dev->bus_list.prev = NULL; | 35 | dev->bus_list.next = dev->bus_list.prev = NULL; |
| 36 | spin_unlock(&pci_bus_lock); | 36 | up_write(&pci_bus_sem); |
| 37 | 37 | ||
| 38 | pci_free_resources(dev); | 38 | pci_free_resources(dev); |
| 39 | pci_dev_put(dev); | 39 | pci_dev_put(dev); |
| @@ -62,9 +62,9 @@ void pci_remove_bus(struct pci_bus *pci_bus) | |||
| 62 | { | 62 | { |
| 63 | pci_proc_detach_bus(pci_bus); | 63 | pci_proc_detach_bus(pci_bus); |
| 64 | 64 | ||
| 65 | spin_lock(&pci_bus_lock); | 65 | down_write(&pci_bus_sem); |
| 66 | list_del(&pci_bus->node); | 66 | list_del(&pci_bus->node); |
| 67 | spin_unlock(&pci_bus_lock); | 67 | up_write(&pci_bus_sem); |
| 68 | pci_remove_legacy_files(pci_bus); | 68 | pci_remove_legacy_files(pci_bus); |
| 69 | class_device_remove_file(&pci_bus->class_dev, | 69 | class_device_remove_file(&pci_bus->class_dev, |
| 70 | &class_device_attr_cpuaffinity); | 70 | &class_device_attr_cpuaffinity); |
diff --git a/drivers/pci/search.c b/drivers/pci/search.c index ce7dd6e7be60..622b3f8ba820 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 14 | #include "pci.h" | 14 | #include "pci.h" |
| 15 | 15 | ||
| 16 | DEFINE_SPINLOCK(pci_bus_lock); | 16 | DECLARE_RWSEM(pci_bus_sem); |
| 17 | 17 | ||
| 18 | static struct pci_bus * __devinit | 18 | static struct pci_bus * __devinit |
| 19 | pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) | 19 | pci_do_find_bus(struct pci_bus* bus, unsigned char busnr) |
| @@ -72,11 +72,11 @@ pci_find_next_bus(const struct pci_bus *from) | |||
| 72 | struct pci_bus *b = NULL; | 72 | struct pci_bus *b = NULL; |
| 73 | 73 | ||
| 74 | WARN_ON(in_interrupt()); | 74 | WARN_ON(in_interrupt()); |
| 75 | spin_lock(&pci_bus_lock); | 75 | down_read(&pci_bus_sem); |
| 76 | n = from ? from->node.next : pci_root_buses.next; | 76 | n = from ? from->node.next : pci_root_buses.next; |
| 77 | if (n != &pci_root_buses) | 77 | if (n != &pci_root_buses) |
| 78 | b = pci_bus_b(n); | 78 | b = pci_bus_b(n); |
| 79 | spin_unlock(&pci_bus_lock); | 79 | up_read(&pci_bus_sem); |
| 80 | return b; | 80 | return b; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| @@ -124,7 +124,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) | |||
| 124 | struct pci_dev *dev; | 124 | struct pci_dev *dev; |
| 125 | 125 | ||
| 126 | WARN_ON(in_interrupt()); | 126 | WARN_ON(in_interrupt()); |
| 127 | spin_lock(&pci_bus_lock); | 127 | down_read(&pci_bus_sem); |
| 128 | 128 | ||
| 129 | list_for_each(tmp, &bus->devices) { | 129 | list_for_each(tmp, &bus->devices) { |
| 130 | dev = pci_dev_b(tmp); | 130 | dev = pci_dev_b(tmp); |
| @@ -135,7 +135,7 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn) | |||
| 135 | dev = NULL; | 135 | dev = NULL; |
| 136 | out: | 136 | out: |
| 137 | pci_dev_get(dev); | 137 | pci_dev_get(dev); |
| 138 | spin_unlock(&pci_bus_lock); | 138 | up_read(&pci_bus_sem); |
| 139 | return dev; | 139 | return dev; |
| 140 | } | 140 | } |
| 141 | 141 | ||
| @@ -167,7 +167,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, | |||
| 167 | struct pci_dev *dev; | 167 | struct pci_dev *dev; |
| 168 | 168 | ||
| 169 | WARN_ON(in_interrupt()); | 169 | WARN_ON(in_interrupt()); |
| 170 | spin_lock(&pci_bus_lock); | 170 | down_read(&pci_bus_sem); |
| 171 | n = from ? from->global_list.next : pci_devices.next; | 171 | n = from ? from->global_list.next : pci_devices.next; |
| 172 | 172 | ||
| 173 | while (n && (n != &pci_devices)) { | 173 | while (n && (n != &pci_devices)) { |
| @@ -181,7 +181,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, | |||
| 181 | } | 181 | } |
| 182 | dev = NULL; | 182 | dev = NULL; |
| 183 | exit: | 183 | exit: |
| 184 | spin_unlock(&pci_bus_lock); | 184 | up_read(&pci_bus_sem); |
| 185 | return dev; | 185 | return dev; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| @@ -232,7 +232,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, | |||
| 232 | struct pci_dev *dev; | 232 | struct pci_dev *dev; |
| 233 | 233 | ||
| 234 | WARN_ON(in_interrupt()); | 234 | WARN_ON(in_interrupt()); |
| 235 | spin_lock(&pci_bus_lock); | 235 | down_read(&pci_bus_sem); |
| 236 | n = from ? from->global_list.next : pci_devices.next; | 236 | n = from ? from->global_list.next : pci_devices.next; |
| 237 | 237 | ||
| 238 | while (n && (n != &pci_devices)) { | 238 | while (n && (n != &pci_devices)) { |
| @@ -247,7 +247,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, | |||
| 247 | dev = NULL; | 247 | dev = NULL; |
| 248 | exit: | 248 | exit: |
| 249 | dev = pci_dev_get(dev); | 249 | dev = pci_dev_get(dev); |
| 250 | spin_unlock(&pci_bus_lock); | 250 | up_read(&pci_bus_sem); |
| 251 | pci_dev_put(from); | 251 | pci_dev_put(from); |
| 252 | return dev; | 252 | return dev; |
| 253 | } | 253 | } |
| @@ -292,7 +292,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p | |||
| 292 | struct pci_dev *dev; | 292 | struct pci_dev *dev; |
| 293 | 293 | ||
| 294 | WARN_ON(in_interrupt()); | 294 | WARN_ON(in_interrupt()); |
| 295 | spin_lock(&pci_bus_lock); | 295 | down_read(&pci_bus_sem); |
| 296 | n = from ? from->global_list.prev : pci_devices.prev; | 296 | n = from ? from->global_list.prev : pci_devices.prev; |
| 297 | 297 | ||
| 298 | while (n && (n != &pci_devices)) { | 298 | while (n && (n != &pci_devices)) { |
| @@ -304,7 +304,7 @@ pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct p | |||
| 304 | } | 304 | } |
| 305 | dev = NULL; | 305 | dev = NULL; |
| 306 | exit: | 306 | exit: |
| 307 | spin_unlock(&pci_bus_lock); | 307 | up_read(&pci_bus_sem); |
| 308 | return dev; | 308 | return dev; |
| 309 | } | 309 | } |
| 310 | 310 | ||
| @@ -328,7 +328,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) | |||
| 328 | struct pci_dev *dev; | 328 | struct pci_dev *dev; |
| 329 | 329 | ||
| 330 | WARN_ON(in_interrupt()); | 330 | WARN_ON(in_interrupt()); |
| 331 | spin_lock(&pci_bus_lock); | 331 | down_read(&pci_bus_sem); |
| 332 | n = from ? from->global_list.next : pci_devices.next; | 332 | n = from ? from->global_list.next : pci_devices.next; |
| 333 | 333 | ||
| 334 | while (n && (n != &pci_devices)) { | 334 | while (n && (n != &pci_devices)) { |
| @@ -340,7 +340,7 @@ struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from) | |||
| 340 | dev = NULL; | 340 | dev = NULL; |
| 341 | exit: | 341 | exit: |
| 342 | dev = pci_dev_get(dev); | 342 | dev = pci_dev_get(dev); |
| 343 | spin_unlock(&pci_bus_lock); | 343 | up_read(&pci_bus_sem); |
| 344 | pci_dev_put(from); | 344 | pci_dev_put(from); |
| 345 | return dev; | 345 | return dev; |
| 346 | } | 346 | } |
| @@ -362,7 +362,7 @@ int pci_dev_present(const struct pci_device_id *ids) | |||
| 362 | int found = 0; | 362 | int found = 0; |
| 363 | 363 | ||
| 364 | WARN_ON(in_interrupt()); | 364 | WARN_ON(in_interrupt()); |
| 365 | spin_lock(&pci_bus_lock); | 365 | down_read(&pci_bus_sem); |
| 366 | while (ids->vendor || ids->subvendor || ids->class_mask) { | 366 | while (ids->vendor || ids->subvendor || ids->class_mask) { |
| 367 | list_for_each_entry(dev, &pci_devices, global_list) { | 367 | list_for_each_entry(dev, &pci_devices, global_list) { |
| 368 | if (pci_match_one_device(ids, dev)) { | 368 | if (pci_match_one_device(ids, dev)) { |
| @@ -372,8 +372,8 @@ int pci_dev_present(const struct pci_device_id *ids) | |||
| 372 | } | 372 | } |
| 373 | ids++; | 373 | ids++; |
| 374 | } | 374 | } |
| 375 | exit: | 375 | exit: |
| 376 | spin_unlock(&pci_bus_lock); | 376 | up_read(&pci_bus_sem); |
| 377 | return found; | 377 | return found; |
| 378 | } | 378 | } |
| 379 | EXPORT_SYMBOL(pci_dev_present); | 379 | EXPORT_SYMBOL(pci_dev_present); |
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 28ce3a7ee434..35086e80faa9 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
| @@ -55,9 +55,10 @@ pbus_assign_resources_sorted(struct pci_bus *bus) | |||
| 55 | list_for_each_entry(dev, &bus->devices, bus_list) { | 55 | list_for_each_entry(dev, &bus->devices, bus_list) { |
| 56 | u16 class = dev->class >> 8; | 56 | u16 class = dev->class >> 8; |
| 57 | 57 | ||
| 58 | /* Don't touch classless devices and host bridges. */ | 58 | /* Don't touch classless devices or host bridges or ioapics. */ |
| 59 | if (class == PCI_CLASS_NOT_DEFINED || | 59 | if (class == PCI_CLASS_NOT_DEFINED || |
| 60 | class == PCI_CLASS_BRIDGE_HOST) | 60 | class == PCI_CLASS_BRIDGE_HOST || |
| 61 | class == PCI_CLASS_SYSTEM_PIC) | ||
| 61 | continue; | 62 | continue; |
| 62 | 63 | ||
| 63 | pdev_sort_resources(dev, &head); | 64 | pdev_sort_resources(dev, &head); |
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index ea9277b7f899..577f4b55c46d 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c | |||
| @@ -155,6 +155,46 @@ int pci_assign_resource(struct pci_dev *dev, int resno) | |||
| 155 | return ret; | 155 | return ret; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | #ifdef CONFIG_EMBEDDED | ||
| 159 | int pci_assign_resource_fixed(struct pci_dev *dev, int resno) | ||
| 160 | { | ||
| 161 | struct pci_bus *bus = dev->bus; | ||
| 162 | struct resource *res = dev->resource + resno; | ||
| 163 | unsigned int type_mask; | ||
| 164 | int i, ret = -EBUSY; | ||
| 165 | |||
| 166 | type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH; | ||
| 167 | |||
| 168 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) { | ||
| 169 | struct resource *r = bus->resource[i]; | ||
| 170 | if (!r) | ||
| 171 | continue; | ||
| 172 | |||
| 173 | /* type_mask must match */ | ||
| 174 | if ((res->flags ^ r->flags) & type_mask) | ||
| 175 | continue; | ||
| 176 | |||
| 177 | ret = request_resource(r, res); | ||
| 178 | |||
| 179 | if (ret == 0) | ||
| 180 | break; | ||
| 181 | } | ||
| 182 | |||
| 183 | if (ret) { | ||
| 184 | printk(KERN_ERR "PCI: Failed to allocate %s resource " | ||
| 185 | "#%d:%llx@%llx for %s\n", | ||
| 186 | res->flags & IORESOURCE_IO ? "I/O" : "mem", | ||
| 187 | resno, (unsigned long long)(res->end - res->start + 1), | ||
| 188 | (unsigned long long)res->start, pci_name(dev)); | ||
| 189 | } else if (resno < PCI_BRIDGE_RESOURCES) { | ||
| 190 | pci_update_resource(dev, res, resno); | ||
| 191 | } | ||
| 192 | |||
| 193 | return ret; | ||
| 194 | } | ||
| 195 | EXPORT_SYMBOL_GPL(pci_assign_resource_fixed); | ||
| 196 | #endif | ||
| 197 | |||
| 158 | /* Sort resources by alignment */ | 198 | /* Sort resources by alignment */ |
| 159 | void __devinit | 199 | void __devinit |
| 160 | pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) | 200 | pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) |
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 77bb2351500c..680f6063954b 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c | |||
| @@ -397,30 +397,6 @@ | |||
| 397 | #include "ql1280_fw.h" | 397 | #include "ql1280_fw.h" |
| 398 | #include "ql1040_fw.h" | 398 | #include "ql1040_fw.h" |
| 399 | 399 | ||
| 400 | |||
| 401 | /* | ||
| 402 | * Missing PCI ID's | ||
| 403 | */ | ||
| 404 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP1080 | ||
| 405 | #define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080 | ||
| 406 | #endif | ||
| 407 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP1240 | ||
| 408 | #define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240 | ||
| 409 | #endif | ||
| 410 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP1280 | ||
| 411 | #define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280 | ||
| 412 | #endif | ||
| 413 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP10160 | ||
| 414 | #define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016 | ||
| 415 | #endif | ||
| 416 | #ifndef PCI_DEVICE_ID_QLOGIC_ISP12160 | ||
| 417 | #define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216 | ||
| 418 | #endif | ||
| 419 | |||
| 420 | #ifndef PCI_VENDOR_ID_AMI | ||
| 421 | #define PCI_VENDOR_ID_AMI 0x101e | ||
| 422 | #endif | ||
| 423 | |||
| 424 | #ifndef BITS_PER_LONG | 400 | #ifndef BITS_PER_LONG |
| 425 | #error "BITS_PER_LONG not defined!" | 401 | #error "BITS_PER_LONG not defined!" |
| 426 | #endif | 402 | #endif |
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 8a29ce340b47..27d658704cf9 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c | |||
| @@ -433,13 +433,14 @@ err_out: | |||
| 433 | 433 | ||
| 434 | 434 | ||
| 435 | /* | 435 | /* |
| 436 | * 0x1725/0x7174 is the Vitesse VSC-7174 | 436 | * Intel 31244 is supposed to be identical. |
| 437 | * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical | 437 | * Compatibility is untested as of yet. |
| 438 | * compatibility is untested as of yet | ||
| 439 | */ | 438 | */ |
| 440 | static const struct pci_device_id vsc_sata_pci_tbl[] = { | 439 | static const struct pci_device_id vsc_sata_pci_tbl[] = { |
| 441 | { 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | 440 | { PCI_VENDOR_ID_VITESSE, PCI_DEVICE_ID_VITESSE_VSC7174, |
| 442 | { 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | 441 | PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, |
| 442 | { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GD31244, | ||
| 443 | PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, | ||
| 443 | { } | 444 | { } |
| 444 | }; | 445 | }; |
| 445 | 446 | ||
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/drivers/w1/Kconfig b/drivers/w1/Kconfig index 5e61ed59a41e..f2d9a08e89ae 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig | |||
| @@ -3,7 +3,7 @@ menu "Dallas's 1-wire bus" | |||
| 3 | config W1 | 3 | config W1 |
| 4 | tristate "Dallas's 1-wire support" | 4 | tristate "Dallas's 1-wire support" |
| 5 | ---help--- | 5 | ---help--- |
| 6 | Dallas's 1-wire bus is useful to connect slow 1-pin devices | 6 | Dallas' 1-wire bus is useful to connect slow 1-pin devices |
| 7 | such as iButtons and thermal sensors. | 7 | such as iButtons and thermal sensors. |
| 8 | 8 | ||
| 9 | If you want W1 support, you should say Y here. | 9 | If you want W1 support, you should say Y here. |
| @@ -11,6 +11,18 @@ config W1 | |||
| 11 | This W1 support can also be built as a module. If so, the module | 11 | This W1 support can also be built as a module. If so, the module |
| 12 | will be called wire.ko. | 12 | will be called wire.ko. |
| 13 | 13 | ||
| 14 | config W1_CON | ||
| 15 | depends on CONNECTOR && W1 | ||
| 16 | bool "Userspace communication over connector" | ||
| 17 | default y | ||
| 18 | --- help --- | ||
| 19 | This allows to communicate with userspace using connector [Documentation/connector]. | ||
| 20 | There are three types of messages between w1 core and userspace: | ||
| 21 | 1. Events. They are generated each time new master or slave device found | ||
| 22 | either due to automatic or requested search. | ||
| 23 | 2. Userspace commands. Includes read/write and search/alarm search comamnds. | ||
| 24 | 3. Replies to userspace commands. | ||
| 25 | |||
| 14 | source drivers/w1/masters/Kconfig | 26 | source drivers/w1/masters/Kconfig |
| 15 | source drivers/w1/slaves/Kconfig | 27 | source drivers/w1/slaves/Kconfig |
| 16 | 28 | ||
diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile index 0c2aa22d8c04..93845a2c7c21 100644 --- a/drivers/w1/Makefile +++ b/drivers/w1/Makefile | |||
| @@ -2,10 +2,6 @@ | |||
| 2 | # Makefile for the Dallas's 1-wire bus. | 2 | # Makefile for the Dallas's 1-wire bus. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | ifneq ($(CONFIG_NET), y) | ||
| 6 | EXTRA_CFLAGS += -DNETLINK_DISABLED | ||
| 7 | endif | ||
| 8 | |||
| 9 | ifeq ($(CONFIG_W1_DS2433_CRC), y) | 5 | ifeq ($(CONFIG_W1_DS2433_CRC), y) |
| 10 | EXTRA_CFLAGS += -DCONFIG_W1_F23_CRC | 6 | EXTRA_CFLAGS += -DCONFIG_W1_F23_CRC |
| 11 | endif | 7 | endif |
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index c6bad4dbdc64..2fb425536eae 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig | |||
| @@ -15,24 +15,15 @@ config W1_MASTER_MATROX | |||
| 15 | This support is also available as a module. If so, the module | 15 | This support is also available as a module. If so, the module |
| 16 | will be called matrox_w1.ko. | 16 | will be called matrox_w1.ko. |
| 17 | 17 | ||
| 18 | config W1_MASTER_DS9490 | 18 | config W1_MASTER_DS2490 |
| 19 | tristate "DS9490R transport layer driver" | 19 | tristate "DS2490 USB <-> W1 transport layer for 1-wire" |
| 20 | depends on W1 && USB | 20 | depends on W1 && USB |
| 21 | help | 21 | help |
| 22 | Say Y here if you want to have a driver for DS9490R UWB <-> W1 bridge. | 22 | Say Y here if you want to have a driver for DS2490 based USB <-> W1 bridges, |
| 23 | 23 | for example DS9490*. | |
| 24 | This support is also available as a module. If so, the module | 24 | |
| 25 | will be called ds9490r.ko. | 25 | This support is also available as a module. If so, the module |
| 26 | 26 | will be called ds2490.ko. | |
| 27 | config W1_MASTER_DS9490_BRIDGE | ||
| 28 | tristate "DS9490R USB <-> W1 transport layer for 1-wire" | ||
| 29 | depends on W1_MASTER_DS9490 | ||
| 30 | help | ||
| 31 | Say Y here if you want to communicate with your 1-wire devices | ||
| 32 | using DS9490R USB bridge. | ||
| 33 | |||
| 34 | This support is also available as a module. If so, the module | ||
| 35 | will be called ds_w1_bridge.ko. | ||
| 36 | 27 | ||
| 37 | config W1_MASTER_DS2482 | 28 | config W1_MASTER_DS2482 |
| 38 | tristate "Maxim DS2482 I2C to 1-Wire bridge" | 29 | tristate "Maxim DS2482 I2C to 1-Wire bridge" |
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index 1f3c8b983dc1..4cee256a8134 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile | |||
| @@ -3,11 +3,6 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o | 5 | obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o |
| 6 | 6 | obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o | |
| 7 | obj-$(CONFIG_W1_MASTER_DS9490) += ds9490r.o | ||
| 8 | ds9490r-objs := dscore.o | ||
| 9 | |||
| 10 | obj-$(CONFIG_W1_MASTER_DS9490_BRIDGE) += ds_w1_bridge.o | ||
| 11 | |||
| 12 | obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o | 7 | obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o |
| 13 | 8 | ||
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index d1cacd23576b..af492cc48db2 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c | |||
| @@ -125,7 +125,7 @@ struct ds2482_w1_chan { | |||
| 125 | 125 | ||
| 126 | struct ds2482_data { | 126 | struct ds2482_data { |
| 127 | struct i2c_client client; | 127 | struct i2c_client client; |
| 128 | struct semaphore access_lock; | 128 | struct mutex access_lock; |
| 129 | 129 | ||
| 130 | /* 1-wire interface(s) */ | 130 | /* 1-wire interface(s) */ |
| 131 | int w1_count; /* 1 or 8 */ | 131 | int w1_count; /* 1 or 8 */ |
| @@ -265,7 +265,7 @@ static u8 ds2482_w1_touch_bit(void *data, u8 bit) | |||
| 265 | struct ds2482_data *pdev = pchan->pdev; | 265 | struct ds2482_data *pdev = pchan->pdev; |
| 266 | int status = -1; | 266 | int status = -1; |
| 267 | 267 | ||
| 268 | down(&pdev->access_lock); | 268 | mutex_lock(&pdev->access_lock); |
| 269 | 269 | ||
| 270 | /* Select the channel */ | 270 | /* Select the channel */ |
| 271 | ds2482_wait_1wire_idle(pdev); | 271 | ds2482_wait_1wire_idle(pdev); |
| @@ -277,7 +277,7 @@ static u8 ds2482_w1_touch_bit(void *data, u8 bit) | |||
| 277 | bit ? 0xFF : 0)) | 277 | bit ? 0xFF : 0)) |
| 278 | status = ds2482_wait_1wire_idle(pdev); | 278 | status = ds2482_wait_1wire_idle(pdev); |
| 279 | 279 | ||
| 280 | up(&pdev->access_lock); | 280 | mutex_unlock(&pdev->access_lock); |
| 281 | 281 | ||
| 282 | return (status & DS2482_REG_STS_SBR) ? 1 : 0; | 282 | return (status & DS2482_REG_STS_SBR) ? 1 : 0; |
| 283 | } | 283 | } |
| @@ -297,7 +297,7 @@ static u8 ds2482_w1_triplet(void *data, u8 dbit) | |||
| 297 | struct ds2482_data *pdev = pchan->pdev; | 297 | struct ds2482_data *pdev = pchan->pdev; |
| 298 | int status = (3 << 5); | 298 | int status = (3 << 5); |
| 299 | 299 | ||
| 300 | down(&pdev->access_lock); | 300 | mutex_lock(&pdev->access_lock); |
| 301 | 301 | ||
| 302 | /* Select the channel */ | 302 | /* Select the channel */ |
| 303 | ds2482_wait_1wire_idle(pdev); | 303 | ds2482_wait_1wire_idle(pdev); |
| @@ -309,7 +309,7 @@ static u8 ds2482_w1_triplet(void *data, u8 dbit) | |||
| 309 | dbit ? 0xFF : 0)) | 309 | dbit ? 0xFF : 0)) |
| 310 | status = ds2482_wait_1wire_idle(pdev); | 310 | status = ds2482_wait_1wire_idle(pdev); |
| 311 | 311 | ||
| 312 | up(&pdev->access_lock); | 312 | mutex_unlock(&pdev->access_lock); |
| 313 | 313 | ||
| 314 | /* Decode the status */ | 314 | /* Decode the status */ |
| 315 | return (status >> 5); | 315 | return (status >> 5); |
| @@ -326,7 +326,7 @@ static void ds2482_w1_write_byte(void *data, u8 byte) | |||
| 326 | struct ds2482_w1_chan *pchan = data; | 326 | struct ds2482_w1_chan *pchan = data; |
| 327 | struct ds2482_data *pdev = pchan->pdev; | 327 | struct ds2482_data *pdev = pchan->pdev; |
| 328 | 328 | ||
| 329 | down(&pdev->access_lock); | 329 | mutex_lock(&pdev->access_lock); |
| 330 | 330 | ||
| 331 | /* Select the channel */ | 331 | /* Select the channel */ |
| 332 | ds2482_wait_1wire_idle(pdev); | 332 | ds2482_wait_1wire_idle(pdev); |
| @@ -336,7 +336,7 @@ static void ds2482_w1_write_byte(void *data, u8 byte) | |||
| 336 | /* Send the write byte command */ | 336 | /* Send the write byte command */ |
| 337 | ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte); | 337 | ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte); |
| 338 | 338 | ||
| 339 | up(&pdev->access_lock); | 339 | mutex_unlock(&pdev->access_lock); |
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | /** | 342 | /** |
| @@ -351,7 +351,7 @@ static u8 ds2482_w1_read_byte(void *data) | |||
| 351 | struct ds2482_data *pdev = pchan->pdev; | 351 | struct ds2482_data *pdev = pchan->pdev; |
| 352 | int result; | 352 | int result; |
| 353 | 353 | ||
| 354 | down(&pdev->access_lock); | 354 | mutex_lock(&pdev->access_lock); |
| 355 | 355 | ||
| 356 | /* Select the channel */ | 356 | /* Select the channel */ |
| 357 | ds2482_wait_1wire_idle(pdev); | 357 | ds2482_wait_1wire_idle(pdev); |
| @@ -370,7 +370,7 @@ static u8 ds2482_w1_read_byte(void *data) | |||
| 370 | /* Read the data byte */ | 370 | /* Read the data byte */ |
| 371 | result = i2c_smbus_read_byte(&pdev->client); | 371 | result = i2c_smbus_read_byte(&pdev->client); |
| 372 | 372 | ||
| 373 | up(&pdev->access_lock); | 373 | mutex_unlock(&pdev->access_lock); |
| 374 | 374 | ||
| 375 | return result; | 375 | return result; |
| 376 | } | 376 | } |
| @@ -389,7 +389,7 @@ static u8 ds2482_w1_reset_bus(void *data) | |||
| 389 | int err; | 389 | int err; |
| 390 | u8 retval = 1; | 390 | u8 retval = 1; |
| 391 | 391 | ||
| 392 | down(&pdev->access_lock); | 392 | mutex_lock(&pdev->access_lock); |
| 393 | 393 | ||
| 394 | /* Select the channel */ | 394 | /* Select the channel */ |
| 395 | ds2482_wait_1wire_idle(pdev); | 395 | ds2482_wait_1wire_idle(pdev); |
| @@ -409,7 +409,7 @@ static u8 ds2482_w1_reset_bus(void *data) | |||
| 409 | 0xF0); | 409 | 0xF0); |
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | up(&pdev->access_lock); | 412 | mutex_unlock(&pdev->access_lock); |
| 413 | 413 | ||
| 414 | return retval; | 414 | return retval; |
| 415 | } | 415 | } |
| @@ -482,7 +482,7 @@ static int ds2482_detect(struct i2c_adapter *adapter, int address, int kind) | |||
| 482 | snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00", | 482 | snprintf(new_client->name, sizeof(new_client->name), "ds2482-%d00", |
| 483 | data->w1_count); | 483 | data->w1_count); |
| 484 | 484 | ||
| 485 | init_MUTEX(&data->access_lock); | 485 | mutex_init(&data->access_lock); |
| 486 | 486 | ||
| 487 | /* Tell the I2C layer a new client has arrived */ | 487 | /* Tell the I2C layer a new client has arrived */ |
| 488 | if ((err = i2c_attach_client(new_client))) | 488 | if ((err = i2c_attach_client(new_client))) |
diff --git a/drivers/w1/masters/dscore.c b/drivers/w1/masters/ds2490.c index 2cf7776a7080..299e274d241a 100644 --- a/drivers/w1/masters/dscore.c +++ b/drivers/w1/masters/ds2490.c | |||
| @@ -24,7 +24,136 @@ | |||
| 24 | #include <linux/mod_devicetable.h> | 24 | #include <linux/mod_devicetable.h> |
| 25 | #include <linux/usb.h> | 25 | #include <linux/usb.h> |
| 26 | 26 | ||
| 27 | #include "dscore.h" | 27 | #include "../w1_int.h" |
| 28 | #include "../w1.h" | ||
| 29 | |||
| 30 | /* COMMAND TYPE CODES */ | ||
| 31 | #define CONTROL_CMD 0x00 | ||
| 32 | #define COMM_CMD 0x01 | ||
| 33 | #define MODE_CMD 0x02 | ||
| 34 | |||
| 35 | /* CONTROL COMMAND CODES */ | ||
| 36 | #define CTL_RESET_DEVICE 0x0000 | ||
| 37 | #define CTL_START_EXE 0x0001 | ||
| 38 | #define CTL_RESUME_EXE 0x0002 | ||
| 39 | #define CTL_HALT_EXE_IDLE 0x0003 | ||
| 40 | #define CTL_HALT_EXE_DONE 0x0004 | ||
| 41 | #define CTL_FLUSH_COMM_CMDS 0x0007 | ||
| 42 | #define CTL_FLUSH_RCV_BUFFER 0x0008 | ||
| 43 | #define CTL_FLUSH_XMT_BUFFER 0x0009 | ||
| 44 | #define CTL_GET_COMM_CMDS 0x000A | ||
| 45 | |||
| 46 | /* MODE COMMAND CODES */ | ||
| 47 | #define MOD_PULSE_EN 0x0000 | ||
| 48 | #define MOD_SPEED_CHANGE_EN 0x0001 | ||
| 49 | #define MOD_1WIRE_SPEED 0x0002 | ||
| 50 | #define MOD_STRONG_PU_DURATION 0x0003 | ||
| 51 | #define MOD_PULLDOWN_SLEWRATE 0x0004 | ||
| 52 | #define MOD_PROG_PULSE_DURATION 0x0005 | ||
| 53 | #define MOD_WRITE1_LOWTIME 0x0006 | ||
| 54 | #define MOD_DSOW0_TREC 0x0007 | ||
| 55 | |||
| 56 | /* COMMUNICATION COMMAND CODES */ | ||
| 57 | #define COMM_ERROR_ESCAPE 0x0601 | ||
| 58 | #define COMM_SET_DURATION 0x0012 | ||
| 59 | #define COMM_BIT_IO 0x0020 | ||
| 60 | #define COMM_PULSE 0x0030 | ||
| 61 | #define COMM_1_WIRE_RESET 0x0042 | ||
| 62 | #define COMM_BYTE_IO 0x0052 | ||
| 63 | #define COMM_MATCH_ACCESS 0x0064 | ||
| 64 | #define COMM_BLOCK_IO 0x0074 | ||
| 65 | #define COMM_READ_STRAIGHT 0x0080 | ||
| 66 | #define COMM_DO_RELEASE 0x6092 | ||
| 67 | #define COMM_SET_PATH 0x00A2 | ||
| 68 | #define COMM_WRITE_SRAM_PAGE 0x00B2 | ||
| 69 | #define COMM_WRITE_EPROM 0x00C4 | ||
| 70 | #define COMM_READ_CRC_PROT_PAGE 0x00D4 | ||
| 71 | #define COMM_READ_REDIRECT_PAGE_CRC 0x21E4 | ||
| 72 | #define COMM_SEARCH_ACCESS 0x00F4 | ||
| 73 | |||
| 74 | /* Communication command bits */ | ||
| 75 | #define COMM_TYPE 0x0008 | ||
| 76 | #define COMM_SE 0x0008 | ||
| 77 | #define COMM_D 0x0008 | ||
| 78 | #define COMM_Z 0x0008 | ||
| 79 | #define COMM_CH 0x0008 | ||
| 80 | #define COMM_SM 0x0008 | ||
| 81 | #define COMM_R 0x0008 | ||
| 82 | #define COMM_IM 0x0001 | ||
| 83 | |||
| 84 | #define COMM_PS 0x4000 | ||
| 85 | #define COMM_PST 0x4000 | ||
| 86 | #define COMM_CIB 0x4000 | ||
| 87 | #define COMM_RTS 0x4000 | ||
| 88 | #define COMM_DT 0x2000 | ||
| 89 | #define COMM_SPU 0x1000 | ||
| 90 | #define COMM_F 0x0800 | ||
| 91 | #define COMM_NTP 0x0400 | ||
| 92 | #define COMM_ICP 0x0200 | ||
| 93 | #define COMM_RST 0x0100 | ||
| 94 | |||
| 95 | #define PULSE_PROG 0x01 | ||
| 96 | #define PULSE_SPUE 0x02 | ||
| 97 | |||
| 98 | #define BRANCH_MAIN 0xCC | ||
| 99 | #define BRANCH_AUX 0x33 | ||
| 100 | |||
| 101 | /* | ||
| 102 | * Duration of the strong pull-up pulse in milliseconds. | ||
| 103 | */ | ||
| 104 | #define PULLUP_PULSE_DURATION 750 | ||
| 105 | |||
| 106 | /* Status flags */ | ||
| 107 | #define ST_SPUA 0x01 /* Strong Pull-up is active */ | ||
| 108 | #define ST_PRGA 0x02 /* 12V programming pulse is being generated */ | ||
| 109 | #define ST_12VP 0x04 /* external 12V programming voltage is present */ | ||
| 110 | #define ST_PMOD 0x08 /* DS2490 powered from USB and external sources */ | ||
| 111 | #define ST_HALT 0x10 /* DS2490 is currently halted */ | ||
| 112 | #define ST_IDLE 0x20 /* DS2490 is currently idle */ | ||
| 113 | #define ST_EPOF 0x80 | ||
| 114 | |||
| 115 | #define SPEED_NORMAL 0x00 | ||
| 116 | #define SPEED_FLEXIBLE 0x01 | ||
| 117 | #define SPEED_OVERDRIVE 0x02 | ||
| 118 | |||
| 119 | #define NUM_EP 4 | ||
| 120 | #define EP_CONTROL 0 | ||
| 121 | #define EP_STATUS 1 | ||
| 122 | #define EP_DATA_OUT 2 | ||
| 123 | #define EP_DATA_IN 3 | ||
| 124 | |||
| 125 | struct ds_device | ||
| 126 | { | ||
| 127 | struct list_head ds_entry; | ||
| 128 | |||
| 129 | struct usb_device *udev; | ||
| 130 | struct usb_interface *intf; | ||
| 131 | |||
| 132 | int ep[NUM_EP]; | ||
| 133 | |||
| 134 | struct w1_bus_master master; | ||
| 135 | }; | ||
| 136 | |||
| 137 | struct ds_status | ||
| 138 | { | ||
| 139 | u8 enable; | ||
| 140 | u8 speed; | ||
| 141 | u8 pullup_dur; | ||
| 142 | u8 ppuls_dur; | ||
| 143 | u8 pulldown_slew; | ||
| 144 | u8 write1_time; | ||
| 145 | u8 write0_time; | ||
| 146 | u8 reserved0; | ||
| 147 | u8 status; | ||
| 148 | u8 command0; | ||
| 149 | u8 command1; | ||
| 150 | u8 command_buffer_status; | ||
| 151 | u8 data_out_buffer_status; | ||
| 152 | u8 data_in_buffer_status; | ||
| 153 | u8 reserved1; | ||
| 154 | u8 reserved2; | ||
| 155 | |||
| 156 | }; | ||
| 28 | 157 | ||
| 29 | static struct usb_device_id ds_id_table [] = { | 158 | static struct usb_device_id ds_id_table [] = { |
| 30 | { USB_DEVICE(0x04fa, 0x2490) }, | 159 | { USB_DEVICE(0x04fa, 0x2490) }, |
| @@ -35,21 +164,12 @@ MODULE_DEVICE_TABLE(usb, ds_id_table); | |||
| 35 | static int ds_probe(struct usb_interface *, const struct usb_device_id *); | 164 | static int ds_probe(struct usb_interface *, const struct usb_device_id *); |
| 36 | static void ds_disconnect(struct usb_interface *); | 165 | static void ds_disconnect(struct usb_interface *); |
| 37 | 166 | ||
| 38 | int ds_touch_bit(struct ds_device *, u8, u8 *); | ||
| 39 | int ds_read_byte(struct ds_device *, u8 *); | ||
| 40 | int ds_read_bit(struct ds_device *, u8 *); | ||
| 41 | int ds_write_byte(struct ds_device *, u8); | ||
| 42 | int ds_write_bit(struct ds_device *, u8); | ||
| 43 | static int ds_start_pulse(struct ds_device *, int); | ||
| 44 | int ds_reset(struct ds_device *, struct ds_status *); | ||
| 45 | struct ds_device * ds_get_device(void); | ||
| 46 | void ds_put_device(struct ds_device *); | ||
| 47 | |||
| 48 | static inline void ds_dump_status(unsigned char *, unsigned char *, int); | 167 | static inline void ds_dump_status(unsigned char *, unsigned char *, int); |
| 49 | static int ds_send_control(struct ds_device *, u16, u16); | 168 | static int ds_send_control(struct ds_device *, u16, u16); |
| 50 | static int ds_send_control_mode(struct ds_device *, u16, u16); | ||
| 51 | static int ds_send_control_cmd(struct ds_device *, u16, u16); | 169 | static int ds_send_control_cmd(struct ds_device *, u16, u16); |
| 52 | 170 | ||
| 171 | static LIST_HEAD(ds_devices); | ||
| 172 | static DEFINE_MUTEX(ds_mutex); | ||
| 53 | 173 | ||
| 54 | static struct usb_driver ds_driver = { | 174 | static struct usb_driver ds_driver = { |
| 55 | .name = "DS9490R", | 175 | .name = "DS9490R", |
| @@ -58,20 +178,6 @@ static struct usb_driver ds_driver = { | |||
| 58 | .id_table = ds_id_table, | 178 | .id_table = ds_id_table, |
| 59 | }; | 179 | }; |
| 60 | 180 | ||
| 61 | static struct ds_device *ds_dev; | ||
| 62 | |||
| 63 | struct ds_device * ds_get_device(void) | ||
| 64 | { | ||
| 65 | if (ds_dev) | ||
| 66 | atomic_inc(&ds_dev->refcnt); | ||
| 67 | return ds_dev; | ||
| 68 | } | ||
| 69 | |||
| 70 | void ds_put_device(struct ds_device *dev) | ||
| 71 | { | ||
| 72 | atomic_dec(&dev->refcnt); | ||
| 73 | } | ||
| 74 | |||
| 75 | static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) | 181 | static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) |
| 76 | { | 182 | { |
| 77 | int err; | 183 | int err; |
| @@ -86,7 +192,7 @@ static int ds_send_control_cmd(struct ds_device *dev, u16 value, u16 index) | |||
| 86 | 192 | ||
| 87 | return err; | 193 | return err; |
| 88 | } | 194 | } |
| 89 | 195 | #if 0 | |
| 90 | static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) | 196 | static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) |
| 91 | { | 197 | { |
| 92 | int err; | 198 | int err; |
| @@ -101,7 +207,7 @@ static int ds_send_control_mode(struct ds_device *dev, u16 value, u16 index) | |||
| 101 | 207 | ||
| 102 | return err; | 208 | return err; |
| 103 | } | 209 | } |
| 104 | 210 | #endif | |
| 105 | static int ds_send_control(struct ds_device *dev, u16 value, u16 index) | 211 | static int ds_send_control(struct ds_device *dev, u16 value, u16 index) |
| 106 | { | 212 | { |
| 107 | int err; | 213 | int err; |
| @@ -324,7 +430,7 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st) | |||
| 324 | return 0; | 430 | return 0; |
| 325 | } | 431 | } |
| 326 | 432 | ||
| 327 | int ds_reset(struct ds_device *dev, struct ds_status *st) | 433 | static int ds_reset(struct ds_device *dev, struct ds_status *st) |
| 328 | { | 434 | { |
| 329 | int err; | 435 | int err; |
| 330 | 436 | ||
| @@ -345,7 +451,7 @@ int ds_reset(struct ds_device *dev, struct ds_status *st) | |||
| 345 | } | 451 | } |
| 346 | 452 | ||
| 347 | #if 0 | 453 | #if 0 |
| 348 | int ds_set_speed(struct ds_device *dev, int speed) | 454 | static int ds_set_speed(struct ds_device *dev, int speed) |
| 349 | { | 455 | { |
| 350 | int err; | 456 | int err; |
| 351 | 457 | ||
| @@ -395,7 +501,7 @@ static int ds_start_pulse(struct ds_device *dev, int delay) | |||
| 395 | return err; | 501 | return err; |
| 396 | } | 502 | } |
| 397 | 503 | ||
| 398 | int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) | 504 | static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) |
| 399 | { | 505 | { |
| 400 | int err, count; | 506 | int err, count; |
| 401 | struct ds_status st; | 507 | struct ds_status st; |
| @@ -427,7 +533,7 @@ int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit) | |||
| 427 | return 0; | 533 | return 0; |
| 428 | } | 534 | } |
| 429 | 535 | ||
| 430 | int ds_write_bit(struct ds_device *dev, u8 bit) | 536 | static int ds_write_bit(struct ds_device *dev, u8 bit) |
| 431 | { | 537 | { |
| 432 | int err; | 538 | int err; |
| 433 | struct ds_status st; | 539 | struct ds_status st; |
| @@ -441,7 +547,7 @@ int ds_write_bit(struct ds_device *dev, u8 bit) | |||
| 441 | return 0; | 547 | return 0; |
| 442 | } | 548 | } |
| 443 | 549 | ||
| 444 | int ds_write_byte(struct ds_device *dev, u8 byte) | 550 | static int ds_write_byte(struct ds_device *dev, u8 byte) |
| 445 | { | 551 | { |
| 446 | int err; | 552 | int err; |
| 447 | struct ds_status st; | 553 | struct ds_status st; |
| @@ -464,26 +570,7 @@ int ds_write_byte(struct ds_device *dev, u8 byte) | |||
| 464 | return !(byte == rbyte); | 570 | return !(byte == rbyte); |
| 465 | } | 571 | } |
| 466 | 572 | ||
| 467 | int ds_read_bit(struct ds_device *dev, u8 *bit) | 573 | static int ds_read_byte(struct ds_device *dev, u8 *byte) |
| 468 | { | ||
| 469 | int err; | ||
| 470 | |||
| 471 | err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE); | ||
| 472 | if (err) | ||
| 473 | return err; | ||
| 474 | |||
| 475 | err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_SPU | COMM_D, 0); | ||
| 476 | if (err) | ||
| 477 | return err; | ||
| 478 | |||
| 479 | err = ds_recv_data(dev, bit, sizeof(*bit)); | ||
| 480 | if (err < 0) | ||
| 481 | return err; | ||
| 482 | |||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | int ds_read_byte(struct ds_device *dev, u8 *byte) | ||
| 487 | { | 574 | { |
| 488 | int err; | 575 | int err; |
| 489 | struct ds_status st; | 576 | struct ds_status st; |
| @@ -501,7 +588,7 @@ int ds_read_byte(struct ds_device *dev, u8 *byte) | |||
| 501 | return 0; | 588 | return 0; |
| 502 | } | 589 | } |
| 503 | 590 | ||
| 504 | int ds_read_block(struct ds_device *dev, u8 *buf, int len) | 591 | static int ds_read_block(struct ds_device *dev, u8 *buf, int len) |
| 505 | { | 592 | { |
| 506 | struct ds_status st; | 593 | struct ds_status st; |
| 507 | int err; | 594 | int err; |
| @@ -527,7 +614,7 @@ int ds_read_block(struct ds_device *dev, u8 *buf, int len) | |||
| 527 | return err; | 614 | return err; |
| 528 | } | 615 | } |
| 529 | 616 | ||
| 530 | int ds_write_block(struct ds_device *dev, u8 *buf, int len) | 617 | static int ds_write_block(struct ds_device *dev, u8 *buf, int len) |
| 531 | { | 618 | { |
| 532 | int err; | 619 | int err; |
| 533 | struct ds_status st; | 620 | struct ds_status st; |
| @@ -555,7 +642,7 @@ int ds_write_block(struct ds_device *dev, u8 *buf, int len) | |||
| 555 | 642 | ||
| 556 | #if 0 | 643 | #if 0 |
| 557 | 644 | ||
| 558 | int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search) | 645 | static int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int conditional_search) |
| 559 | { | 646 | { |
| 560 | int err; | 647 | int err; |
| 561 | u16 value, index; | 648 | u16 value, index; |
| @@ -584,7 +671,7 @@ int ds_search(struct ds_device *dev, u64 init, u64 *buf, u8 id_number, int condi | |||
| 584 | return err/8; | 671 | return err/8; |
| 585 | } | 672 | } |
| 586 | 673 | ||
| 587 | int ds_match_access(struct ds_device *dev, u64 init) | 674 | static int ds_match_access(struct ds_device *dev, u64 init) |
| 588 | { | 675 | { |
| 589 | int err; | 676 | int err; |
| 590 | struct ds_status st; | 677 | struct ds_status st; |
| @@ -604,7 +691,7 @@ int ds_match_access(struct ds_device *dev, u64 init) | |||
| 604 | return 0; | 691 | return 0; |
| 605 | } | 692 | } |
| 606 | 693 | ||
| 607 | int ds_set_path(struct ds_device *dev, u64 init) | 694 | static int ds_set_path(struct ds_device *dev, u64 init) |
| 608 | { | 695 | { |
| 609 | int err; | 696 | int err; |
| 610 | struct ds_status st; | 697 | struct ds_status st; |
| @@ -630,45 +717,156 @@ int ds_set_path(struct ds_device *dev, u64 init) | |||
| 630 | 717 | ||
| 631 | #endif /* 0 */ | 718 | #endif /* 0 */ |
| 632 | 719 | ||
| 720 | static u8 ds9490r_touch_bit(void *data, u8 bit) | ||
| 721 | { | ||
| 722 | u8 ret; | ||
| 723 | struct ds_device *dev = data; | ||
| 724 | |||
| 725 | if (ds_touch_bit(dev, bit, &ret)) | ||
| 726 | return 0; | ||
| 727 | |||
| 728 | return ret; | ||
| 729 | } | ||
| 730 | |||
| 731 | static void ds9490r_write_bit(void *data, u8 bit) | ||
| 732 | { | ||
| 733 | struct ds_device *dev = data; | ||
| 734 | |||
| 735 | ds_write_bit(dev, bit); | ||
| 736 | } | ||
| 737 | |||
| 738 | static void ds9490r_write_byte(void *data, u8 byte) | ||
| 739 | { | ||
| 740 | struct ds_device *dev = data; | ||
| 741 | |||
| 742 | ds_write_byte(dev, byte); | ||
| 743 | } | ||
| 744 | |||
| 745 | static u8 ds9490r_read_bit(void *data) | ||
| 746 | { | ||
| 747 | struct ds_device *dev = data; | ||
| 748 | int err; | ||
| 749 | u8 bit = 0; | ||
| 750 | |||
| 751 | err = ds_touch_bit(dev, 1, &bit); | ||
| 752 | if (err) | ||
| 753 | return 0; | ||
| 754 | |||
| 755 | return bit & 1; | ||
| 756 | } | ||
| 757 | |||
| 758 | static u8 ds9490r_read_byte(void *data) | ||
| 759 | { | ||
| 760 | struct ds_device *dev = data; | ||
| 761 | int err; | ||
| 762 | u8 byte = 0; | ||
| 763 | |||
| 764 | err = ds_read_byte(dev, &byte); | ||
| 765 | if (err) | ||
| 766 | return 0; | ||
| 767 | |||
| 768 | return byte; | ||
| 769 | } | ||
| 770 | |||
| 771 | static void ds9490r_write_block(void *data, const u8 *buf, int len) | ||
| 772 | { | ||
| 773 | struct ds_device *dev = data; | ||
| 774 | |||
| 775 | ds_write_block(dev, (u8 *)buf, len); | ||
| 776 | } | ||
| 777 | |||
| 778 | static u8 ds9490r_read_block(void *data, u8 *buf, int len) | ||
| 779 | { | ||
| 780 | struct ds_device *dev = data; | ||
| 781 | int err; | ||
| 782 | |||
| 783 | err = ds_read_block(dev, buf, len); | ||
| 784 | if (err < 0) | ||
| 785 | return 0; | ||
| 786 | |||
| 787 | return len; | ||
| 788 | } | ||
| 789 | |||
| 790 | static u8 ds9490r_reset(void *data) | ||
| 791 | { | ||
| 792 | struct ds_device *dev = data; | ||
| 793 | struct ds_status st; | ||
| 794 | int err; | ||
| 795 | |||
| 796 | memset(&st, 0, sizeof(st)); | ||
| 797 | |||
| 798 | err = ds_reset(dev, &st); | ||
| 799 | if (err) | ||
| 800 | return 1; | ||
| 801 | |||
| 802 | return 0; | ||
| 803 | } | ||
| 804 | |||
| 805 | static int ds_w1_init(struct ds_device *dev) | ||
| 806 | { | ||
| 807 | memset(&dev->master, 0, sizeof(struct w1_bus_master)); | ||
| 808 | |||
| 809 | dev->master.data = dev; | ||
| 810 | dev->master.touch_bit = &ds9490r_touch_bit; | ||
| 811 | dev->master.read_bit = &ds9490r_read_bit; | ||
| 812 | dev->master.write_bit = &ds9490r_write_bit; | ||
| 813 | dev->master.read_byte = &ds9490r_read_byte; | ||
| 814 | dev->master.write_byte = &ds9490r_write_byte; | ||
| 815 | dev->master.read_block = &ds9490r_read_block; | ||
| 816 | dev->master.write_block = &ds9490r_write_block; | ||
| 817 | dev->master.reset_bus = &ds9490r_reset; | ||
| 818 | |||
| 819 | return w1_add_master_device(&dev->master); | ||
| 820 | } | ||
| 821 | |||
| 822 | static void ds_w1_fini(struct ds_device *dev) | ||
| 823 | { | ||
| 824 | w1_remove_master_device(&dev->master); | ||
| 825 | } | ||
| 826 | |||
| 633 | static int ds_probe(struct usb_interface *intf, | 827 | static int ds_probe(struct usb_interface *intf, |
| 634 | const struct usb_device_id *udev_id) | 828 | const struct usb_device_id *udev_id) |
| 635 | { | 829 | { |
| 636 | struct usb_device *udev = interface_to_usbdev(intf); | 830 | struct usb_device *udev = interface_to_usbdev(intf); |
| 637 | struct usb_endpoint_descriptor *endpoint; | 831 | struct usb_endpoint_descriptor *endpoint; |
| 638 | struct usb_host_interface *iface_desc; | 832 | struct usb_host_interface *iface_desc; |
| 833 | struct ds_device *dev; | ||
| 639 | int i, err; | 834 | int i, err; |
| 640 | 835 | ||
| 641 | ds_dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL); | 836 | dev = kmalloc(sizeof(struct ds_device), GFP_KERNEL); |
| 642 | if (!ds_dev) { | 837 | if (!dev) { |
| 643 | printk(KERN_INFO "Failed to allocate new DS9490R structure.\n"); | 838 | printk(KERN_INFO "Failed to allocate new DS9490R structure.\n"); |
| 644 | return -ENOMEM; | 839 | return -ENOMEM; |
| 645 | } | 840 | } |
| 841 | dev->udev = usb_get_dev(udev); | ||
| 842 | if (!dev->udev) { | ||
| 843 | err = -ENOMEM; | ||
| 844 | goto err_out_free; | ||
| 845 | } | ||
| 846 | memset(dev->ep, 0, sizeof(dev->ep)); | ||
| 646 | 847 | ||
| 647 | ds_dev->udev = usb_get_dev(udev); | 848 | usb_set_intfdata(intf, dev); |
| 648 | usb_set_intfdata(intf, ds_dev); | ||
| 649 | 849 | ||
| 650 | err = usb_set_interface(ds_dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3); | 850 | err = usb_set_interface(dev->udev, intf->altsetting[0].desc.bInterfaceNumber, 3); |
| 651 | if (err) { | 851 | if (err) { |
| 652 | printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n", | 852 | printk(KERN_ERR "Failed to set alternative setting 3 for %d interface: err=%d.\n", |
| 653 | intf->altsetting[0].desc.bInterfaceNumber, err); | 853 | intf->altsetting[0].desc.bInterfaceNumber, err); |
| 654 | return err; | 854 | goto err_out_clear; |
| 655 | } | 855 | } |
| 656 | 856 | ||
| 657 | err = usb_reset_configuration(ds_dev->udev); | 857 | err = usb_reset_configuration(dev->udev); |
| 658 | if (err) { | 858 | if (err) { |
| 659 | printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err); | 859 | printk(KERN_ERR "Failed to reset configuration: err=%d.\n", err); |
| 660 | return err; | 860 | goto err_out_clear; |
| 661 | } | 861 | } |
| 662 | 862 | ||
| 663 | iface_desc = &intf->altsetting[0]; | 863 | iface_desc = &intf->altsetting[0]; |
| 664 | if (iface_desc->desc.bNumEndpoints != NUM_EP-1) { | 864 | if (iface_desc->desc.bNumEndpoints != NUM_EP-1) { |
| 665 | printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints); | 865 | printk(KERN_INFO "Num endpoints=%d. It is not DS9490R.\n", iface_desc->desc.bNumEndpoints); |
| 666 | return -ENODEV; | 866 | err = -EINVAL; |
| 867 | goto err_out_clear; | ||
| 667 | } | 868 | } |
| 668 | 869 | ||
| 669 | atomic_set(&ds_dev->refcnt, 0); | ||
| 670 | memset(ds_dev->ep, 0, sizeof(ds_dev->ep)); | ||
| 671 | |||
| 672 | /* | 870 | /* |
| 673 | * This loop doesn'd show control 0 endpoint, | 871 | * This loop doesn'd show control 0 endpoint, |
| 674 | * so we will fill only 1-3 endpoints entry. | 872 | * so we will fill only 1-3 endpoints entry. |
| @@ -676,54 +874,31 @@ static int ds_probe(struct usb_interface *intf, | |||
| 676 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | 874 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { |
| 677 | endpoint = &iface_desc->endpoint[i].desc; | 875 | endpoint = &iface_desc->endpoint[i].desc; |
| 678 | 876 | ||
| 679 | ds_dev->ep[i+1] = endpoint->bEndpointAddress; | 877 | dev->ep[i+1] = endpoint->bEndpointAddress; |
| 680 | 878 | #if 0 | |
| 681 | printk("%d: addr=%x, size=%d, dir=%s, type=%x\n", | 879 | printk("%d: addr=%x, size=%d, dir=%s, type=%x\n", |
| 682 | i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize), | 880 | i, endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize), |
| 683 | (endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT", | 881 | (endpoint->bEndpointAddress & USB_DIR_IN)?"IN":"OUT", |
| 684 | endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); | 882 | endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); |
| 883 | #endif | ||
| 685 | } | 884 | } |
| 686 | 885 | ||
| 687 | #if 0 | 886 | err = ds_w1_init(dev); |
| 688 | { | 887 | if (err) |
| 689 | int err, i; | 888 | goto err_out_clear; |
| 690 | u64 buf[3]; | ||
| 691 | u64 init=0xb30000002078ee81ull; | ||
| 692 | struct ds_status st; | ||
| 693 | |||
| 694 | ds_reset(ds_dev, &st); | ||
| 695 | err = ds_search(ds_dev, init, buf, 3, 0); | ||
| 696 | if (err < 0) | ||
| 697 | return err; | ||
| 698 | for (i=0; i<err; ++i) | ||
| 699 | printk("%d: %llx\n", i, buf[i]); | ||
| 700 | |||
| 701 | printk("Resetting...\n"); | ||
| 702 | ds_reset(ds_dev, &st); | ||
| 703 | printk("Setting path for %llx.\n", init); | ||
| 704 | err = ds_set_path(ds_dev, init); | ||
| 705 | if (err) | ||
| 706 | return err; | ||
| 707 | printk("Calling MATCH_ACCESS.\n"); | ||
| 708 | err = ds_match_access(ds_dev, init); | ||
| 709 | if (err) | ||
| 710 | return err; | ||
| 711 | |||
| 712 | printk("Searching the bus...\n"); | ||
| 713 | err = ds_search(ds_dev, init, buf, 3, 0); | ||
| 714 | |||
| 715 | printk("ds_search() returned %d\n", err); | ||
| 716 | |||
| 717 | if (err < 0) | ||
| 718 | return err; | ||
| 719 | for (i=0; i<err; ++i) | ||
| 720 | printk("%d: %llx\n", i, buf[i]); | ||
| 721 | 889 | ||
| 722 | return 0; | 890 | mutex_lock(&ds_mutex); |
| 723 | } | 891 | list_add_tail(&dev->ds_entry, &ds_devices); |
| 724 | #endif | 892 | mutex_unlock(&ds_mutex); |
| 725 | 893 | ||
| 726 | return 0; | 894 | return 0; |
| 895 | |||
| 896 | err_out_clear: | ||
| 897 | usb_set_intfdata(intf, NULL); | ||
| 898 | usb_put_dev(dev->udev); | ||
| 899 | err_out_free: | ||
| 900 | kfree(dev); | ||
| 901 | return err; | ||
| 727 | } | 902 | } |
| 728 | 903 | ||
| 729 | static void ds_disconnect(struct usb_interface *intf) | 904 | static void ds_disconnect(struct usb_interface *intf) |
| @@ -731,19 +906,19 @@ static void ds_disconnect(struct usb_interface *intf) | |||
| 731 | struct ds_device *dev; | 906 | struct ds_device *dev; |
| 732 | 907 | ||
| 733 | dev = usb_get_intfdata(intf); | 908 | dev = usb_get_intfdata(intf); |
| 734 | usb_set_intfdata(intf, NULL); | 909 | if (!dev) |
| 910 | return; | ||
| 735 | 911 | ||
| 736 | while (atomic_read(&dev->refcnt)) { | 912 | mutex_lock(&ds_mutex); |
| 737 | printk(KERN_INFO "Waiting for DS to become free: refcnt=%d.\n", | 913 | list_del(&dev->ds_entry); |
| 738 | atomic_read(&dev->refcnt)); | 914 | mutex_unlock(&ds_mutex); |
| 739 | 915 | ||
| 740 | if (msleep_interruptible(1000)) | 916 | ds_w1_fini(dev); |
| 741 | flush_signals(current); | 917 | |
| 742 | } | 918 | usb_set_intfdata(intf, NULL); |
| 743 | 919 | ||
| 744 | usb_put_dev(dev->udev); | 920 | usb_put_dev(dev->udev); |
| 745 | kfree(dev); | 921 | kfree(dev); |
| 746 | ds_dev = NULL; | ||
| 747 | } | 922 | } |
| 748 | 923 | ||
| 749 | static int ds_init(void) | 924 | static int ds_init(void) |
| @@ -769,27 +944,4 @@ module_exit(ds_fini); | |||
| 769 | 944 | ||
| 770 | MODULE_LICENSE("GPL"); | 945 | MODULE_LICENSE("GPL"); |
| 771 | MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); | 946 | MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); |
| 772 | 947 | MODULE_DESCRIPTION("DS2490 USB <-> W1 bus master driver (DS9490*)"); | |
| 773 | EXPORT_SYMBOL(ds_touch_bit); | ||
| 774 | EXPORT_SYMBOL(ds_read_byte); | ||
| 775 | EXPORT_SYMBOL(ds_read_bit); | ||
| 776 | EXPORT_SYMBOL(ds_read_block); | ||
| 777 | EXPORT_SYMBOL(ds_write_byte); | ||
| 778 | EXPORT_SYMBOL(ds_write_bit); | ||
| 779 | EXPORT_SYMBOL(ds_write_block); | ||
| 780 | EXPORT_SYMBOL(ds_reset); | ||
| 781 | EXPORT_SYMBOL(ds_get_device); | ||
| 782 | EXPORT_SYMBOL(ds_put_device); | ||
| 783 | |||
| 784 | /* | ||
| 785 | * This functions can be used for EEPROM programming, | ||
| 786 | * when driver will be included into mainline this will | ||
| 787 | * require uncommenting. | ||
| 788 | */ | ||
| 789 | #if 0 | ||
| 790 | EXPORT_SYMBOL(ds_start_pulse); | ||
| 791 | EXPORT_SYMBOL(ds_set_speed); | ||
| 792 | EXPORT_SYMBOL(ds_detect); | ||
| 793 | EXPORT_SYMBOL(ds_stop_pulse); | ||
| 794 | EXPORT_SYMBOL(ds_search); | ||
| 795 | #endif | ||
diff --git a/drivers/w1/masters/ds_w1_bridge.c b/drivers/w1/masters/ds_w1_bridge.c deleted file mode 100644 index 5d30783a3eb6..000000000000 --- a/drivers/w1/masters/ds_w1_bridge.c +++ /dev/null | |||
| @@ -1,174 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * ds_w1_bridge.c | ||
| 3 | * | ||
| 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | ||
| 5 | * | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/types.h> | ||
| 24 | |||
| 25 | #include "../w1.h" | ||
| 26 | #include "../w1_int.h" | ||
| 27 | #include "dscore.h" | ||
| 28 | |||
| 29 | static struct ds_device *ds_dev; | ||
| 30 | static struct w1_bus_master *ds_bus_master; | ||
| 31 | |||
| 32 | static u8 ds9490r_touch_bit(void *data, u8 bit) | ||
| 33 | { | ||
| 34 | u8 ret; | ||
| 35 | struct ds_device *dev = data; | ||
| 36 | |||
| 37 | if (ds_touch_bit(dev, bit, &ret)) | ||
| 38 | return 0; | ||
| 39 | |||
| 40 | return ret; | ||
| 41 | } | ||
| 42 | |||
| 43 | static void ds9490r_write_bit(void *data, u8 bit) | ||
| 44 | { | ||
| 45 | struct ds_device *dev = data; | ||
| 46 | |||
| 47 | ds_write_bit(dev, bit); | ||
| 48 | } | ||
| 49 | |||
| 50 | static void ds9490r_write_byte(void *data, u8 byte) | ||
| 51 | { | ||
| 52 | struct ds_device *dev = data; | ||
| 53 | |||
| 54 | ds_write_byte(dev, byte); | ||
| 55 | } | ||
| 56 | |||
| 57 | static u8 ds9490r_read_bit(void *data) | ||
| 58 | { | ||
| 59 | struct ds_device *dev = data; | ||
| 60 | int err; | ||
| 61 | u8 bit = 0; | ||
| 62 | |||
| 63 | err = ds_touch_bit(dev, 1, &bit); | ||
| 64 | if (err) | ||
| 65 | return 0; | ||
| 66 | //err = ds_read_bit(dev, &bit); | ||
| 67 | //if (err) | ||
| 68 | // return 0; | ||
| 69 | |||
| 70 | return bit & 1; | ||
| 71 | } | ||
| 72 | |||
| 73 | static u8 ds9490r_read_byte(void *data) | ||
| 74 | { | ||
| 75 | struct ds_device *dev = data; | ||
| 76 | int err; | ||
| 77 | u8 byte = 0; | ||
| 78 | |||
| 79 | err = ds_read_byte(dev, &byte); | ||
| 80 | if (err) | ||
| 81 | return 0; | ||
| 82 | |||
| 83 | return byte; | ||
| 84 | } | ||
| 85 | |||
| 86 | static void ds9490r_write_block(void *data, const u8 *buf, int len) | ||
| 87 | { | ||
| 88 | struct ds_device *dev = data; | ||
| 89 | |||
| 90 | ds_write_block(dev, (u8 *)buf, len); | ||
| 91 | } | ||
| 92 | |||
| 93 | static u8 ds9490r_read_block(void *data, u8 *buf, int len) | ||
| 94 | { | ||
| 95 | struct ds_device *dev = data; | ||
| 96 | int err; | ||
| 97 | |||
| 98 | err = ds_read_block(dev, buf, len); | ||
| 99 | if (err < 0) | ||
| 100 | return 0; | ||
| 101 | |||
| 102 | return len; | ||
| 103 | } | ||
| 104 | |||
| 105 | static u8 ds9490r_reset(void *data) | ||
| 106 | { | ||
| 107 | struct ds_device *dev = data; | ||
| 108 | struct ds_status st; | ||
| 109 | int err; | ||
| 110 | |||
| 111 | memset(&st, 0, sizeof(st)); | ||
| 112 | |||
| 113 | err = ds_reset(dev, &st); | ||
| 114 | if (err) | ||
| 115 | return 1; | ||
| 116 | |||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | static int __devinit ds_w1_init(void) | ||
| 121 | { | ||
| 122 | int err; | ||
| 123 | |||
| 124 | ds_bus_master = kmalloc(sizeof(*ds_bus_master), GFP_KERNEL); | ||
| 125 | if (!ds_bus_master) { | ||
| 126 | printk(KERN_ERR "Failed to allocate DS9490R USB<->W1 bus_master structure.\n"); | ||
| 127 | return -ENOMEM; | ||
| 128 | } | ||
| 129 | |||
| 130 | ds_dev = ds_get_device(); | ||
| 131 | if (!ds_dev) { | ||
| 132 | printk(KERN_ERR "DS9490R is not registered.\n"); | ||
| 133 | err = -ENODEV; | ||
| 134 | goto err_out_free_bus_master; | ||
| 135 | } | ||
| 136 | |||
| 137 | memset(ds_bus_master, 0, sizeof(*ds_bus_master)); | ||
| 138 | |||
| 139 | ds_bus_master->data = ds_dev; | ||
| 140 | ds_bus_master->touch_bit = &ds9490r_touch_bit; | ||
| 141 | ds_bus_master->read_bit = &ds9490r_read_bit; | ||
| 142 | ds_bus_master->write_bit = &ds9490r_write_bit; | ||
| 143 | ds_bus_master->read_byte = &ds9490r_read_byte; | ||
| 144 | ds_bus_master->write_byte = &ds9490r_write_byte; | ||
| 145 | ds_bus_master->read_block = &ds9490r_read_block; | ||
| 146 | ds_bus_master->write_block = &ds9490r_write_block; | ||
| 147 | ds_bus_master->reset_bus = &ds9490r_reset; | ||
| 148 | |||
| 149 | err = w1_add_master_device(ds_bus_master); | ||
| 150 | if (err) | ||
| 151 | goto err_out_put_device; | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | |||
| 155 | err_out_put_device: | ||
| 156 | ds_put_device(ds_dev); | ||
| 157 | err_out_free_bus_master: | ||
| 158 | kfree(ds_bus_master); | ||
| 159 | |||
| 160 | return err; | ||
| 161 | } | ||
| 162 | |||
| 163 | static void __devexit ds_w1_fini(void) | ||
| 164 | { | ||
| 165 | w1_remove_master_device(ds_bus_master); | ||
| 166 | ds_put_device(ds_dev); | ||
| 167 | kfree(ds_bus_master); | ||
| 168 | } | ||
| 169 | |||
| 170 | module_init(ds_w1_init); | ||
| 171 | module_exit(ds_w1_fini); | ||
| 172 | |||
| 173 | MODULE_LICENSE("GPL"); | ||
| 174 | MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); | ||
diff --git a/drivers/w1/masters/dscore.h b/drivers/w1/masters/dscore.h deleted file mode 100644 index 6cf5671d6ebe..000000000000 --- a/drivers/w1/masters/dscore.h +++ /dev/null | |||
| @@ -1,166 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * dscore.h | ||
| 3 | * | ||
| 4 | * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru> | ||
| 5 | * | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #ifndef __DSCORE_H | ||
| 23 | #define __DSCORE_H | ||
| 24 | |||
| 25 | #include <linux/usb.h> | ||
| 26 | #include <asm/atomic.h> | ||
| 27 | |||
| 28 | /* COMMAND TYPE CODES */ | ||
| 29 | #define CONTROL_CMD 0x00 | ||
| 30 | #define COMM_CMD 0x01 | ||
| 31 | #define MODE_CMD 0x02 | ||
| 32 | |||
| 33 | /* CONTROL COMMAND CODES */ | ||
| 34 | #define CTL_RESET_DEVICE 0x0000 | ||
| 35 | #define CTL_START_EXE 0x0001 | ||
| 36 | #define CTL_RESUME_EXE 0x0002 | ||
| 37 | #define CTL_HALT_EXE_IDLE 0x0003 | ||
| 38 | #define CTL_HALT_EXE_DONE 0x0004 | ||
| 39 | #define CTL_FLUSH_COMM_CMDS 0x0007 | ||
| 40 | #define CTL_FLUSH_RCV_BUFFER 0x0008 | ||
| 41 | #define CTL_FLUSH_XMT_BUFFER 0x0009 | ||
| 42 | #define CTL_GET_COMM_CMDS 0x000A | ||
| 43 | |||
| 44 | /* MODE COMMAND CODES */ | ||
| 45 | #define MOD_PULSE_EN 0x0000 | ||
| 46 | #define MOD_SPEED_CHANGE_EN 0x0001 | ||
| 47 | #define MOD_1WIRE_SPEED 0x0002 | ||
| 48 | #define MOD_STRONG_PU_DURATION 0x0003 | ||
| 49 | #define MOD_PULLDOWN_SLEWRATE 0x0004 | ||
| 50 | #define MOD_PROG_PULSE_DURATION 0x0005 | ||
| 51 | #define MOD_WRITE1_LOWTIME 0x0006 | ||
| 52 | #define MOD_DSOW0_TREC 0x0007 | ||
| 53 | |||
| 54 | /* COMMUNICATION COMMAND CODES */ | ||
| 55 | #define COMM_ERROR_ESCAPE 0x0601 | ||
| 56 | #define COMM_SET_DURATION 0x0012 | ||
| 57 | #define COMM_BIT_IO 0x0020 | ||
| 58 | #define COMM_PULSE 0x0030 | ||
| 59 | #define COMM_1_WIRE_RESET 0x0042 | ||
| 60 | #define COMM_BYTE_IO 0x0052 | ||
| 61 | #define COMM_MATCH_ACCESS 0x0064 | ||
| 62 | #define COMM_BLOCK_IO 0x0074 | ||
| 63 | #define COMM_READ_STRAIGHT 0x0080 | ||
| 64 | #define COMM_DO_RELEASE 0x6092 | ||
| 65 | #define COMM_SET_PATH 0x00A2 | ||
| 66 | #define COMM_WRITE_SRAM_PAGE 0x00B2 | ||
| 67 | #define COMM_WRITE_EPROM 0x00C4 | ||
| 68 | #define COMM_READ_CRC_PROT_PAGE 0x00D4 | ||
| 69 | #define COMM_READ_REDIRECT_PAGE_CRC 0x21E4 | ||
| 70 | #define COMM_SEARCH_ACCESS 0x00F4 | ||
| 71 | |||
| 72 | /* Communication command bits */ | ||
| 73 | #define COMM_TYPE 0x0008 | ||
| 74 | #define COMM_SE 0x0008 | ||
| 75 | #define COMM_D 0x0008 | ||
| 76 | #define COMM_Z 0x0008 | ||
| 77 | #define COMM_CH 0x0008 | ||
| 78 | #define COMM_SM 0x0008 | ||
| 79 | #define COMM_R 0x0008 | ||
| 80 | #define COMM_IM 0x0001 | ||
| 81 | |||
| 82 | #define COMM_PS 0x4000 | ||
| 83 | #define COMM_PST 0x4000 | ||
| 84 | #define COMM_CIB 0x4000 | ||
| 85 | #define COMM_RTS 0x4000 | ||
| 86 | #define COMM_DT 0x2000 | ||
| 87 | #define COMM_SPU 0x1000 | ||
| 88 | #define COMM_F 0x0800 | ||
| 89 | #define COMM_NTP 0x0400 | ||
| 90 | #define COMM_ICP 0x0200 | ||
| 91 | #define COMM_RST 0x0100 | ||
| 92 | |||
| 93 | #define PULSE_PROG 0x01 | ||
| 94 | #define PULSE_SPUE 0x02 | ||
| 95 | |||
| 96 | #define BRANCH_MAIN 0xCC | ||
| 97 | #define BRANCH_AUX 0x33 | ||
| 98 | |||
| 99 | /* | ||
| 100 | * Duration of the strong pull-up pulse in milliseconds. | ||
| 101 | */ | ||
| 102 | #define PULLUP_PULSE_DURATION 750 | ||
| 103 | |||
| 104 | /* Status flags */ | ||
| 105 | #define ST_SPUA 0x01 /* Strong Pull-up is active */ | ||
| 106 | #define ST_PRGA 0x02 /* 12V programming pulse is being generated */ | ||
| 107 | #define ST_12VP 0x04 /* external 12V programming voltage is present */ | ||
| 108 | #define ST_PMOD 0x08 /* DS2490 powered from USB and external sources */ | ||
| 109 | #define ST_HALT 0x10 /* DS2490 is currently halted */ | ||
| 110 | #define ST_IDLE 0x20 /* DS2490 is currently idle */ | ||
| 111 | #define ST_EPOF 0x80 | ||
| 112 | |||
| 113 | #define SPEED_NORMAL 0x00 | ||
| 114 | #define SPEED_FLEXIBLE 0x01 | ||
| 115 | #define SPEED_OVERDRIVE 0x02 | ||
| 116 | |||
| 117 | #define NUM_EP 4 | ||
| 118 | #define EP_CONTROL 0 | ||
| 119 | #define EP_STATUS 1 | ||
| 120 | #define EP_DATA_OUT 2 | ||
| 121 | #define EP_DATA_IN 3 | ||
| 122 | |||
| 123 | struct ds_device | ||
| 124 | { | ||
| 125 | struct usb_device *udev; | ||
| 126 | struct usb_interface *intf; | ||
| 127 | |||
| 128 | int ep[NUM_EP]; | ||
| 129 | |||
| 130 | atomic_t refcnt; | ||
| 131 | }; | ||
| 132 | |||
| 133 | struct ds_status | ||
| 134 | { | ||
| 135 | u8 enable; | ||
| 136 | u8 speed; | ||
| 137 | u8 pullup_dur; | ||
| 138 | u8 ppuls_dur; | ||
| 139 | u8 pulldown_slew; | ||
| 140 | u8 write1_time; | ||
| 141 | u8 write0_time; | ||
| 142 | u8 reserved0; | ||
| 143 | u8 status; | ||
| 144 | u8 command0; | ||
| 145 | u8 command1; | ||
| 146 | u8 command_buffer_status; | ||
| 147 | u8 data_out_buffer_status; | ||
| 148 | u8 data_in_buffer_status; | ||
| 149 | u8 reserved1; | ||
| 150 | u8 reserved2; | ||
| 151 | |||
| 152 | }; | ||
| 153 | |||
| 154 | int ds_touch_bit(struct ds_device *, u8, u8 *); | ||
| 155 | int ds_read_byte(struct ds_device *, u8 *); | ||
| 156 | int ds_read_bit(struct ds_device *, u8 *); | ||
| 157 | int ds_write_byte(struct ds_device *, u8); | ||
| 158 | int ds_write_bit(struct ds_device *, u8); | ||
| 159 | int ds_reset(struct ds_device *, struct ds_status *); | ||
| 160 | struct ds_device * ds_get_device(void); | ||
| 161 | void ds_put_device(struct ds_device *); | ||
| 162 | int ds_write_block(struct ds_device *, u8 *, int); | ||
| 163 | int ds_read_block(struct ds_device *, u8 *, int); | ||
| 164 | |||
| 165 | #endif /* __DSCORE_H */ | ||
| 166 | |||
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index f9d4c91fc533..d18d6424cd21 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig | |||
| @@ -28,7 +28,7 @@ config W1_SLAVE_DS2433 | |||
| 28 | 28 | ||
| 29 | config W1_SLAVE_DS2433_CRC | 29 | config W1_SLAVE_DS2433_CRC |
| 30 | bool "Protect DS2433 data with a CRC16" | 30 | bool "Protect DS2433 data with a CRC16" |
| 31 | depends on W1_DS2433 | 31 | depends on W1_SLAVE_DS2433 |
| 32 | select CRC16 | 32 | select CRC16 |
| 33 | help | 33 | help |
| 34 | Say Y here to protect DS2433 data with a CRC16. | 34 | Say Y here to protect DS2433 data with a CRC16. |
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c index fb118be789ea..2ac238f1480e 100644 --- a/drivers/w1/slaves/w1_ds2433.c +++ b/drivers/w1/slaves/w1_ds2433.c | |||
| @@ -22,7 +22,6 @@ | |||
| 22 | #endif | 22 | #endif |
| 23 | 23 | ||
| 24 | #include "../w1.h" | 24 | #include "../w1.h" |
| 25 | #include "../w1_io.h" | ||
| 26 | #include "../w1_int.h" | 25 | #include "../w1_int.h" |
| 27 | #include "../w1_family.h" | 26 | #include "../w1_family.h" |
| 28 | 27 | ||
| @@ -106,11 +105,7 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, | |||
| 106 | if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) | 105 | if ((count = w1_f23_fix_count(off, count, W1_EEPROM_SIZE)) == 0) |
| 107 | return 0; | 106 | return 0; |
| 108 | 107 | ||
| 109 | atomic_inc(&sl->refcnt); | 108 | mutex_lock(&sl->master->mutex); |
| 110 | if (down_interruptible(&sl->master->mutex)) { | ||
| 111 | count = 0; | ||
| 112 | goto out_dec; | ||
| 113 | } | ||
| 114 | 109 | ||
| 115 | #ifdef CONFIG_W1_F23_CRC | 110 | #ifdef CONFIG_W1_F23_CRC |
| 116 | 111 | ||
| @@ -141,9 +136,7 @@ static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off, | |||
| 141 | #endif /* CONFIG_W1_F23_CRC */ | 136 | #endif /* CONFIG_W1_F23_CRC */ |
| 142 | 137 | ||
| 143 | out_up: | 138 | out_up: |
| 144 | up(&sl->master->mutex); | 139 | mutex_unlock(&sl->master->mutex); |
| 145 | out_dec: | ||
| 146 | atomic_dec(&sl->refcnt); | ||
| 147 | 140 | ||
| 148 | return count; | 141 | return count; |
| 149 | } | 142 | } |
| @@ -232,11 +225,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off, | |||
| 232 | } | 225 | } |
| 233 | #endif /* CONFIG_W1_F23_CRC */ | 226 | #endif /* CONFIG_W1_F23_CRC */ |
| 234 | 227 | ||
| 235 | atomic_inc(&sl->refcnt); | 228 | mutex_lock(&sl->master->mutex); |
| 236 | if (down_interruptible(&sl->master->mutex)) { | ||
| 237 | count = 0; | ||
| 238 | goto out_dec; | ||
| 239 | } | ||
| 240 | 229 | ||
| 241 | /* Can only write data to one page at a time */ | 230 | /* Can only write data to one page at a time */ |
| 242 | idx = 0; | 231 | idx = 0; |
| @@ -254,9 +243,7 @@ static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off, | |||
| 254 | } | 243 | } |
| 255 | 244 | ||
| 256 | out_up: | 245 | out_up: |
| 257 | up(&sl->master->mutex); | 246 | mutex_unlock(&sl->master->mutex); |
| 258 | out_dec: | ||
| 259 | atomic_dec(&sl->refcnt); | ||
| 260 | 247 | ||
| 261 | return count; | 248 | return count; |
| 262 | } | 249 | } |
diff --git a/drivers/w1/slaves/w1_smem.c b/drivers/w1/slaves/w1_smem.c index c6d3be54f94c..cc8c02e92593 100644 --- a/drivers/w1/slaves/w1_smem.c +++ b/drivers/w1/slaves/w1_smem.c | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
| 29 | 29 | ||
| 30 | #include "../w1.h" | 30 | #include "../w1.h" |
| 31 | #include "../w1_io.h" | ||
| 32 | #include "../w1_int.h" | 31 | #include "../w1_int.h" |
| 33 | #include "../w1_family.h" | 32 | #include "../w1_family.h" |
| 34 | 33 | ||
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 536d16d78de7..5372cfcbd054 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c | |||
| @@ -29,7 +29,6 @@ | |||
| 29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
| 30 | 30 | ||
| 31 | #include "../w1.h" | 31 | #include "../w1.h" |
| 32 | #include "../w1_io.h" | ||
| 33 | #include "../w1_int.h" | 32 | #include "../w1_int.h" |
| 34 | #include "../w1_family.h" | 33 | #include "../w1_family.h" |
| 35 | 34 | ||
| @@ -166,12 +165,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
| 166 | u8 rom[9], crc, verdict; | 165 | u8 rom[9], crc, verdict; |
| 167 | int i, max_trying = 10; | 166 | int i, max_trying = 10; |
| 168 | 167 | ||
| 169 | atomic_inc(&sl->refcnt); | 168 | mutex_lock(&sl->master->mutex); |
| 170 | smp_mb__after_atomic_inc(); | ||
| 171 | if (down_interruptible(&sl->master->mutex)) { | ||
| 172 | count = 0; | ||
| 173 | goto out_dec; | ||
| 174 | } | ||
| 175 | 169 | ||
| 176 | if (off > W1_SLAVE_DATA_SIZE) { | 170 | if (off > W1_SLAVE_DATA_SIZE) { |
| 177 | count = 0; | 171 | count = 0; |
| @@ -234,10 +228,7 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, si | |||
| 234 | 228 | ||
| 235 | count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid)); | 229 | count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid)); |
| 236 | out: | 230 | out: |
| 237 | up(&dev->mutex); | 231 | mutex_unlock(&dev->mutex); |
| 238 | out_dec: | ||
| 239 | smp_mb__before_atomic_inc(); | ||
| 240 | atomic_dec(&sl->refcnt); | ||
| 241 | 232 | ||
| 242 | return count; | 233 | return count; |
| 243 | } | 234 | } |
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index a698b517e863..de3e9791f80d 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
| @@ -35,7 +35,6 @@ | |||
| 35 | #include <asm/atomic.h> | 35 | #include <asm/atomic.h> |
| 36 | 36 | ||
| 37 | #include "w1.h" | 37 | #include "w1.h" |
| 38 | #include "w1_io.h" | ||
| 39 | #include "w1_log.h" | 38 | #include "w1_log.h" |
| 40 | #include "w1_int.h" | 39 | #include "w1_int.h" |
| 41 | #include "w1_family.h" | 40 | #include "w1_family.h" |
| @@ -55,7 +54,7 @@ module_param_named(control_timeout, w1_control_timeout, int, 0); | |||
| 55 | module_param_named(max_slave_count, w1_max_slave_count, int, 0); | 54 | module_param_named(max_slave_count, w1_max_slave_count, int, 0); |
| 56 | module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); | 55 | module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); |
| 57 | 56 | ||
| 58 | DEFINE_SPINLOCK(w1_mlock); | 57 | DEFINE_MUTEX(w1_mlock); |
| 59 | LIST_HEAD(w1_masters); | 58 | LIST_HEAD(w1_masters); |
| 60 | 59 | ||
| 61 | static struct task_struct *w1_control_thread; | 60 | static struct task_struct *w1_control_thread; |
| @@ -75,8 +74,6 @@ static void w1_master_release(struct device *dev) | |||
| 75 | struct w1_master *md = dev_to_w1_master(dev); | 74 | struct w1_master *md = dev_to_w1_master(dev); |
| 76 | 75 | ||
| 77 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name); | 76 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name); |
| 78 | |||
| 79 | dev_fini_netlink(md); | ||
| 80 | memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); | 77 | memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); |
| 81 | kfree(md); | 78 | kfree(md); |
| 82 | } | 79 | } |
| @@ -85,10 +82,10 @@ static void w1_slave_release(struct device *dev) | |||
| 85 | { | 82 | { |
| 86 | struct w1_slave *sl = dev_to_w1_slave(dev); | 83 | struct w1_slave *sl = dev_to_w1_slave(dev); |
| 87 | 84 | ||
| 88 | dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name); | 85 | printk("%s: Releasing %s.\n", __func__, sl->name); |
| 89 | 86 | ||
| 90 | while (atomic_read(&sl->refcnt)) { | 87 | while (atomic_read(&sl->refcnt)) { |
| 91 | dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n", | 88 | printk("Waiting for %s to become free: refcnt=%d.\n", |
| 92 | sl->name, atomic_read(&sl->refcnt)); | 89 | sl->name, atomic_read(&sl->refcnt)); |
| 93 | if (msleep_interruptible(1000)) | 90 | if (msleep_interruptible(1000)) |
| 94 | flush_signals(current); | 91 | flush_signals(current); |
| @@ -111,7 +108,6 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz | |||
| 111 | { | 108 | { |
| 112 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | 109 | struct w1_slave *sl = kobj_to_w1_slave(kobj); |
| 113 | 110 | ||
| 114 | atomic_inc(&sl->refcnt); | ||
| 115 | if (off > 8) { | 111 | if (off > 8) { |
| 116 | count = 0; | 112 | count = 0; |
| 117 | } else { | 113 | } else { |
| @@ -120,7 +116,6 @@ static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, siz | |||
| 120 | 116 | ||
| 121 | memcpy(buf, (u8 *)&sl->reg_num, count); | 117 | memcpy(buf, (u8 *)&sl->reg_num, count); |
| 122 | } | 118 | } |
| 123 | atomic_dec(&sl->refcnt); | ||
| 124 | 119 | ||
| 125 | return count; | 120 | return count; |
| 126 | } | 121 | } |
| @@ -139,7 +134,63 @@ static struct bin_attribute w1_slave_attr_bin_id = { | |||
| 139 | }; | 134 | }; |
| 140 | 135 | ||
| 141 | /* Default family */ | 136 | /* Default family */ |
| 142 | static struct w1_family w1_default_family; | 137 | |
| 138 | static ssize_t w1_default_write(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
| 139 | { | ||
| 140 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
| 141 | |||
| 142 | mutex_lock(&sl->master->mutex); | ||
| 143 | if (w1_reset_select_slave(sl)) { | ||
| 144 | count = 0; | ||
| 145 | goto out_up; | ||
| 146 | } | ||
| 147 | |||
| 148 | w1_write_block(sl->master, buf, count); | ||
| 149 | |||
| 150 | out_up: | ||
| 151 | mutex_unlock(&sl->master->mutex); | ||
| 152 | return count; | ||
| 153 | } | ||
| 154 | |||
| 155 | static ssize_t w1_default_read(struct kobject *kobj, char *buf, loff_t off, size_t count) | ||
| 156 | { | ||
| 157 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
| 158 | |||
| 159 | mutex_lock(&sl->master->mutex); | ||
| 160 | w1_read_block(sl->master, buf, count); | ||
| 161 | mutex_unlock(&sl->master->mutex); | ||
| 162 | return count; | ||
| 163 | } | ||
| 164 | |||
| 165 | static struct bin_attribute w1_default_attr = { | ||
| 166 | .attr = { | ||
| 167 | .name = "rw", | ||
| 168 | .mode = S_IRUGO | S_IWUSR, | ||
| 169 | .owner = THIS_MODULE, | ||
| 170 | }, | ||
| 171 | .size = PAGE_SIZE, | ||
| 172 | .read = w1_default_read, | ||
| 173 | .write = w1_default_write, | ||
| 174 | }; | ||
| 175 | |||
| 176 | static int w1_default_add_slave(struct w1_slave *sl) | ||
| 177 | { | ||
| 178 | return sysfs_create_bin_file(&sl->dev.kobj, &w1_default_attr); | ||
| 179 | } | ||
| 180 | |||
| 181 | static void w1_default_remove_slave(struct w1_slave *sl) | ||
| 182 | { | ||
| 183 | sysfs_remove_bin_file(&sl->dev.kobj, &w1_default_attr); | ||
| 184 | } | ||
| 185 | |||
| 186 | static struct w1_family_ops w1_default_fops = { | ||
| 187 | .add_slave = w1_default_add_slave, | ||
| 188 | .remove_slave = w1_default_remove_slave, | ||
| 189 | }; | ||
| 190 | |||
| 191 | static struct w1_family w1_default_family = { | ||
| 192 | .fops = &w1_default_fops, | ||
| 193 | }; | ||
| 143 | 194 | ||
| 144 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); | 195 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); |
| 145 | 196 | ||
| @@ -183,12 +234,9 @@ static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_a | |||
| 183 | struct w1_master *md = dev_to_w1_master(dev); | 234 | struct w1_master *md = dev_to_w1_master(dev); |
| 184 | ssize_t count; | 235 | ssize_t count; |
| 185 | 236 | ||
| 186 | if (down_interruptible (&md->mutex)) | 237 | mutex_lock(&md->mutex); |
| 187 | return -EBUSY; | ||
| 188 | |||
| 189 | count = sprintf(buf, "%s\n", md->name); | 238 | count = sprintf(buf, "%s\n", md->name); |
| 190 | 239 | mutex_unlock(&md->mutex); | |
| 191 | up(&md->mutex); | ||
| 192 | 240 | ||
| 193 | return count; | 241 | return count; |
| 194 | } | 242 | } |
| @@ -199,12 +247,9 @@ static ssize_t w1_master_attribute_store_search(struct device * dev, | |||
| 199 | { | 247 | { |
| 200 | struct w1_master *md = dev_to_w1_master(dev); | 248 | struct w1_master *md = dev_to_w1_master(dev); |
| 201 | 249 | ||
| 202 | if (down_interruptible (&md->mutex)) | 250 | mutex_lock(&md->mutex); |
| 203 | return -EBUSY; | ||
| 204 | |||
| 205 | md->search_count = simple_strtol(buf, NULL, 0); | 251 | md->search_count = simple_strtol(buf, NULL, 0); |
| 206 | 252 | mutex_unlock(&md->mutex); | |
| 207 | up(&md->mutex); | ||
| 208 | 253 | ||
| 209 | return count; | 254 | return count; |
| 210 | } | 255 | } |
| @@ -216,12 +261,9 @@ static ssize_t w1_master_attribute_show_search(struct device *dev, | |||
| 216 | struct w1_master *md = dev_to_w1_master(dev); | 261 | struct w1_master *md = dev_to_w1_master(dev); |
| 217 | ssize_t count; | 262 | ssize_t count; |
| 218 | 263 | ||
| 219 | if (down_interruptible (&md->mutex)) | 264 | mutex_lock(&md->mutex); |
| 220 | return -EBUSY; | ||
| 221 | |||
| 222 | count = sprintf(buf, "%d\n", md->search_count); | 265 | count = sprintf(buf, "%d\n", md->search_count); |
| 223 | 266 | mutex_unlock(&md->mutex); | |
| 224 | up(&md->mutex); | ||
| 225 | 267 | ||
| 226 | return count; | 268 | return count; |
| 227 | } | 269 | } |
| @@ -231,12 +273,9 @@ static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct devic | |||
| 231 | struct w1_master *md = dev_to_w1_master(dev); | 273 | struct w1_master *md = dev_to_w1_master(dev); |
| 232 | ssize_t count; | 274 | ssize_t count; |
| 233 | 275 | ||
| 234 | if (down_interruptible(&md->mutex)) | 276 | mutex_lock(&md->mutex); |
| 235 | return -EBUSY; | ||
| 236 | |||
| 237 | count = sprintf(buf, "0x%p\n", md->bus_master); | 277 | count = sprintf(buf, "0x%p\n", md->bus_master); |
| 238 | 278 | mutex_unlock(&md->mutex); | |
| 239 | up(&md->mutex); | ||
| 240 | return count; | 279 | return count; |
| 241 | } | 280 | } |
| 242 | 281 | ||
| @@ -252,12 +291,9 @@ static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, stru | |||
| 252 | struct w1_master *md = dev_to_w1_master(dev); | 291 | struct w1_master *md = dev_to_w1_master(dev); |
| 253 | ssize_t count; | 292 | ssize_t count; |
| 254 | 293 | ||
| 255 | if (down_interruptible(&md->mutex)) | 294 | mutex_lock(&md->mutex); |
| 256 | return -EBUSY; | ||
| 257 | |||
| 258 | count = sprintf(buf, "%d\n", md->max_slave_count); | 295 | count = sprintf(buf, "%d\n", md->max_slave_count); |
| 259 | 296 | mutex_unlock(&md->mutex); | |
| 260 | up(&md->mutex); | ||
| 261 | return count; | 297 | return count; |
| 262 | } | 298 | } |
| 263 | 299 | ||
| @@ -266,12 +302,9 @@ static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct devi | |||
| 266 | struct w1_master *md = dev_to_w1_master(dev); | 302 | struct w1_master *md = dev_to_w1_master(dev); |
| 267 | ssize_t count; | 303 | ssize_t count; |
| 268 | 304 | ||
| 269 | if (down_interruptible(&md->mutex)) | 305 | mutex_lock(&md->mutex); |
| 270 | return -EBUSY; | ||
| 271 | |||
| 272 | count = sprintf(buf, "%lu\n", md->attempts); | 306 | count = sprintf(buf, "%lu\n", md->attempts); |
| 273 | 307 | mutex_unlock(&md->mutex); | |
| 274 | up(&md->mutex); | ||
| 275 | return count; | 308 | return count; |
| 276 | } | 309 | } |
| 277 | 310 | ||
| @@ -280,12 +313,9 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d | |||
| 280 | struct w1_master *md = dev_to_w1_master(dev); | 313 | struct w1_master *md = dev_to_w1_master(dev); |
| 281 | ssize_t count; | 314 | ssize_t count; |
| 282 | 315 | ||
| 283 | if (down_interruptible(&md->mutex)) | 316 | mutex_lock(&md->mutex); |
| 284 | return -EBUSY; | ||
| 285 | |||
| 286 | count = sprintf(buf, "%d\n", md->slave_count); | 317 | count = sprintf(buf, "%d\n", md->slave_count); |
| 287 | 318 | mutex_unlock(&md->mutex); | |
| 288 | up(&md->mutex); | ||
| 289 | return count; | 319 | return count; |
| 290 | } | 320 | } |
| 291 | 321 | ||
| @@ -294,8 +324,7 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device | |||
| 294 | struct w1_master *md = dev_to_w1_master(dev); | 324 | struct w1_master *md = dev_to_w1_master(dev); |
| 295 | int c = PAGE_SIZE; | 325 | int c = PAGE_SIZE; |
| 296 | 326 | ||
| 297 | if (down_interruptible(&md->mutex)) | 327 | mutex_lock(&md->mutex); |
| 298 | return -EBUSY; | ||
| 299 | 328 | ||
| 300 | if (md->slave_count == 0) | 329 | if (md->slave_count == 0) |
| 301 | c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n"); | 330 | c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n"); |
| @@ -310,7 +339,7 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device | |||
| 310 | } | 339 | } |
| 311 | } | 340 | } |
| 312 | 341 | ||
| 313 | up(&md->mutex); | 342 | mutex_unlock(&md->mutex); |
| 314 | 343 | ||
| 315 | return PAGE_SIZE - c; | 344 | return PAGE_SIZE - c; |
| 316 | } | 345 | } |
| @@ -362,7 +391,8 @@ static void w1_destroy_master_attributes(struct w1_master *master) | |||
| 362 | } | 391 | } |
| 363 | 392 | ||
| 364 | #ifdef CONFIG_HOTPLUG | 393 | #ifdef CONFIG_HOTPLUG |
| 365 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | 394 | static int w1_uevent(struct device *dev, char **envp, int num_envp, |
| 395 | char *buffer, int buffer_size) | ||
| 366 | { | 396 | { |
| 367 | struct w1_master *md = NULL; | 397 | struct w1_master *md = NULL; |
| 368 | struct w1_slave *sl = NULL; | 398 | struct w1_slave *sl = NULL; |
| @@ -382,7 +412,8 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer | |||
| 382 | return -EINVAL; | 412 | return -EINVAL; |
| 383 | } | 413 | } |
| 384 | 414 | ||
| 385 | dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", event_owner, name, dev->bus_id); | 415 | dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", |
| 416 | event_owner, name, dev->bus_id); | ||
| 386 | 417 | ||
| 387 | if (dev->driver != &w1_slave_driver || !sl) | 418 | if (dev->driver != &w1_slave_driver || !sl) |
| 388 | return 0; | 419 | return 0; |
| @@ -401,7 +432,8 @@ static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer | |||
| 401 | return 0; | 432 | return 0; |
| 402 | }; | 433 | }; |
| 403 | #else | 434 | #else |
| 404 | static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) | 435 | static int w1_uevent(struct device *dev, char **envp, int num_envp, |
| 436 | char *buffer, int buffer_size) | ||
| 405 | { | 437 | { |
| 406 | return 0; | 438 | return 0; |
| 407 | } | 439 | } |
| @@ -425,7 +457,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
| 425 | (unsigned int) sl->reg_num.family, | 457 | (unsigned int) sl->reg_num.family, |
| 426 | (unsigned long long) sl->reg_num.id); | 458 | (unsigned long long) sl->reg_num.id); |
| 427 | 459 | ||
| 428 | dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, &sl->dev.bus_id[0]); | 460 | dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, |
| 461 | &sl->dev.bus_id[0]); | ||
| 429 | 462 | ||
| 430 | err = device_register(&sl->dev); | 463 | err = device_register(&sl->dev); |
| 431 | if (err < 0) { | 464 | if (err < 0) { |
| @@ -496,6 +529,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
| 496 | sl->master = dev; | 529 | sl->master = dev; |
| 497 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | 530 | set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); |
| 498 | 531 | ||
| 532 | memset(&msg, 0, sizeof(msg)); | ||
| 499 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); | 533 | memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); |
| 500 | atomic_set(&sl->refcnt, 0); | 534 | atomic_set(&sl->refcnt, 0); |
| 501 | init_completion(&sl->released); | 535 | init_completion(&sl->released); |
| @@ -526,7 +560,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) | |||
| 526 | sl->ttl = dev->slave_ttl; | 560 | sl->ttl = dev->slave_ttl; |
| 527 | dev->slave_count++; | 561 | dev->slave_count++; |
| 528 | 562 | ||
| 529 | memcpy(&msg.id.id, rn, sizeof(msg.id.id)); | 563 | memcpy(msg.id.id, rn, sizeof(msg.id)); |
| 530 | msg.type = W1_SLAVE_ADD; | 564 | msg.type = W1_SLAVE_ADD; |
| 531 | w1_netlink_send(dev, &msg); | 565 | w1_netlink_send(dev, &msg); |
| 532 | 566 | ||
| @@ -544,7 +578,8 @@ static void w1_slave_detach(struct w1_slave *sl) | |||
| 544 | if (sl->family->fops && sl->family->fops->remove_slave) | 578 | if (sl->family->fops && sl->family->fops->remove_slave) |
| 545 | sl->family->fops->remove_slave(sl); | 579 | sl->family->fops->remove_slave(sl); |
| 546 | 580 | ||
| 547 | memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id)); | 581 | memset(&msg, 0, sizeof(msg)); |
| 582 | memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id)); | ||
| 548 | msg.type = W1_SLAVE_REMOVE; | 583 | msg.type = W1_SLAVE_REMOVE; |
| 549 | w1_netlink_send(sl->master, &msg); | 584 | w1_netlink_send(sl->master, &msg); |
| 550 | 585 | ||
| @@ -561,7 +596,7 @@ static struct w1_master *w1_search_master(void *data) | |||
| 561 | struct w1_master *dev; | 596 | struct w1_master *dev; |
| 562 | int found = 0; | 597 | int found = 0; |
| 563 | 598 | ||
| 564 | spin_lock_bh(&w1_mlock); | 599 | mutex_lock(&w1_mlock); |
| 565 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | 600 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
| 566 | if (dev->bus_master->data == data) { | 601 | if (dev->bus_master->data == data) { |
| 567 | found = 1; | 602 | found = 1; |
| @@ -569,22 +604,69 @@ static struct w1_master *w1_search_master(void *data) | |||
| 569 | break; | 604 | break; |
| 570 | } | 605 | } |
| 571 | } | 606 | } |
| 572 | spin_unlock_bh(&w1_mlock); | 607 | mutex_unlock(&w1_mlock); |
| 608 | |||
| 609 | return (found)?dev:NULL; | ||
| 610 | } | ||
| 611 | |||
| 612 | struct w1_master *w1_search_master_id(u32 id) | ||
| 613 | { | ||
| 614 | struct w1_master *dev; | ||
| 615 | int found = 0; | ||
| 616 | |||
| 617 | mutex_lock(&w1_mlock); | ||
| 618 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | ||
| 619 | if (dev->id == id) { | ||
| 620 | found = 1; | ||
| 621 | atomic_inc(&dev->refcnt); | ||
| 622 | break; | ||
| 623 | } | ||
| 624 | } | ||
| 625 | mutex_unlock(&w1_mlock); | ||
| 573 | 626 | ||
| 574 | return (found)?dev:NULL; | 627 | return (found)?dev:NULL; |
| 575 | } | 628 | } |
| 576 | 629 | ||
| 630 | struct w1_slave *w1_search_slave(struct w1_reg_num *id) | ||
| 631 | { | ||
| 632 | struct w1_master *dev; | ||
| 633 | struct w1_slave *sl = NULL; | ||
| 634 | int found = 0; | ||
| 635 | |||
| 636 | mutex_lock(&w1_mlock); | ||
| 637 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | ||
| 638 | mutex_lock(&dev->mutex); | ||
| 639 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) { | ||
| 640 | if (sl->reg_num.family == id->family && | ||
| 641 | sl->reg_num.id == id->id && | ||
| 642 | sl->reg_num.crc == id->crc) { | ||
| 643 | found = 1; | ||
| 644 | atomic_inc(&dev->refcnt); | ||
| 645 | atomic_inc(&sl->refcnt); | ||
| 646 | break; | ||
| 647 | } | ||
| 648 | } | ||
| 649 | mutex_unlock(&dev->mutex); | ||
| 650 | |||
| 651 | if (found) | ||
| 652 | break; | ||
| 653 | } | ||
| 654 | mutex_unlock(&w1_mlock); | ||
| 655 | |||
| 656 | return (found)?sl:NULL; | ||
| 657 | } | ||
| 658 | |||
| 577 | void w1_reconnect_slaves(struct w1_family *f) | 659 | void w1_reconnect_slaves(struct w1_family *f) |
| 578 | { | 660 | { |
| 579 | struct w1_master *dev; | 661 | struct w1_master *dev; |
| 580 | 662 | ||
| 581 | spin_lock_bh(&w1_mlock); | 663 | mutex_lock(&w1_mlock); |
| 582 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { | 664 | list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
| 583 | dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", | 665 | dev_dbg(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n", |
| 584 | dev->name, f->fid); | 666 | dev->name, f->fid); |
| 585 | set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); | 667 | set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); |
| 586 | } | 668 | } |
| 587 | spin_unlock_bh(&w1_mlock); | 669 | mutex_unlock(&w1_mlock); |
| 588 | } | 670 | } |
| 589 | 671 | ||
| 590 | static void w1_slave_found(void *data, u64 rn) | 672 | static void w1_slave_found(void *data, u64 rn) |
| @@ -646,7 +728,7 @@ static void w1_slave_found(void *data, u64 rn) | |||
| 646 | * @dev The master device to search | 728 | * @dev The master device to search |
| 647 | * @cb Function to call when a device is found | 729 | * @cb Function to call when a device is found |
| 648 | */ | 730 | */ |
| 649 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb) | 731 | void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) |
| 650 | { | 732 | { |
| 651 | u64 last_rn, rn, tmp64; | 733 | u64 last_rn, rn, tmp64; |
| 652 | int i, slave_count = 0; | 734 | int i, slave_count = 0; |
| @@ -677,7 +759,7 @@ void w1_search(struct w1_master *dev, w1_slave_found_callback cb) | |||
| 677 | } | 759 | } |
| 678 | 760 | ||
| 679 | /* Start the search */ | 761 | /* Start the search */ |
| 680 | w1_write_8(dev, W1_SEARCH); | 762 | w1_write_8(dev, search_type); |
| 681 | for (i = 0; i < 64; ++i) { | 763 | for (i = 0; i < 64; ++i) { |
| 682 | /* Determine the direction/search bit */ | 764 | /* Determine the direction/search bit */ |
| 683 | if (i == desc_bit) | 765 | if (i == desc_bit) |
| @@ -739,23 +821,23 @@ static int w1_control(void *data) | |||
| 739 | if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { | 821 | if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { |
| 740 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); | 822 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
| 741 | 823 | ||
| 742 | spin_lock(&w1_mlock); | 824 | mutex_lock(&w1_mlock); |
| 743 | list_del(&dev->w1_master_entry); | 825 | list_del(&dev->w1_master_entry); |
| 744 | spin_unlock(&w1_mlock); | 826 | mutex_unlock(&w1_mlock); |
| 745 | 827 | ||
| 746 | down(&dev->mutex); | 828 | mutex_lock(&dev->mutex); |
| 747 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | 829 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
| 748 | w1_slave_detach(sl); | 830 | w1_slave_detach(sl); |
| 749 | } | 831 | } |
| 750 | w1_destroy_master_attributes(dev); | 832 | w1_destroy_master_attributes(dev); |
| 751 | up(&dev->mutex); | 833 | mutex_unlock(&dev->mutex); |
| 752 | atomic_dec(&dev->refcnt); | 834 | atomic_dec(&dev->refcnt); |
| 753 | continue; | 835 | continue; |
| 754 | } | 836 | } |
| 755 | 837 | ||
| 756 | if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) { | 838 | if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) { |
| 757 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name); | 839 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name); |
| 758 | down(&dev->mutex); | 840 | mutex_lock(&dev->mutex); |
| 759 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | 841 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
| 760 | if (sl->family->fid == W1_FAMILY_DEFAULT) { | 842 | if (sl->family->fid == W1_FAMILY_DEFAULT) { |
| 761 | struct w1_reg_num rn; | 843 | struct w1_reg_num rn; |
| @@ -768,7 +850,7 @@ static int w1_control(void *data) | |||
| 768 | } | 850 | } |
| 769 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name); | 851 | dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name); |
| 770 | clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); | 852 | clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags); |
| 771 | up(&dev->mutex); | 853 | mutex_unlock(&dev->mutex); |
| 772 | } | 854 | } |
| 773 | } | 855 | } |
| 774 | } | 856 | } |
| @@ -776,10 +858,31 @@ static int w1_control(void *data) | |||
| 776 | return 0; | 858 | return 0; |
| 777 | } | 859 | } |
| 778 | 860 | ||
| 861 | void w1_search_process(struct w1_master *dev, u8 search_type) | ||
| 862 | { | ||
| 863 | struct w1_slave *sl, *sln; | ||
| 864 | |||
| 865 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) | ||
| 866 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | ||
| 867 | |||
| 868 | w1_search_devices(dev, search_type, w1_slave_found); | ||
| 869 | |||
| 870 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | ||
| 871 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { | ||
| 872 | w1_slave_detach(sl); | ||
| 873 | |||
| 874 | dev->slave_count--; | ||
| 875 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | ||
| 876 | sl->ttl = dev->slave_ttl; | ||
| 877 | } | ||
| 878 | |||
| 879 | if (dev->search_count > 0) | ||
| 880 | dev->search_count--; | ||
| 881 | } | ||
| 882 | |||
| 779 | int w1_process(void *data) | 883 | int w1_process(void *data) |
| 780 | { | 884 | { |
| 781 | struct w1_master *dev = (struct w1_master *) data; | 885 | struct w1_master *dev = (struct w1_master *) data; |
| 782 | struct w1_slave *sl, *sln; | ||
| 783 | 886 | ||
| 784 | while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { | 887 | while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) { |
| 785 | try_to_freeze(); | 888 | try_to_freeze(); |
| @@ -794,27 +897,9 @@ int w1_process(void *data) | |||
| 794 | if (dev->search_count == 0) | 897 | if (dev->search_count == 0) |
| 795 | continue; | 898 | continue; |
| 796 | 899 | ||
| 797 | if (down_interruptible(&dev->mutex)) | 900 | mutex_lock(&dev->mutex); |
| 798 | continue; | 901 | w1_search_process(dev, W1_SEARCH); |
| 799 | 902 | mutex_unlock(&dev->mutex); | |
| 800 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) | ||
| 801 | clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); | ||
| 802 | |||
| 803 | w1_search_devices(dev, w1_slave_found); | ||
| 804 | |||
| 805 | list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { | ||
| 806 | if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { | ||
| 807 | w1_slave_detach(sl); | ||
| 808 | |||
| 809 | dev->slave_count--; | ||
| 810 | } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) | ||
| 811 | sl->ttl = dev->slave_ttl; | ||
| 812 | } | ||
| 813 | |||
| 814 | if (dev->search_count > 0) | ||
| 815 | dev->search_count--; | ||
| 816 | |||
| 817 | up(&dev->mutex); | ||
| 818 | } | 903 | } |
| 819 | 904 | ||
| 820 | atomic_dec(&dev->refcnt); | 905 | atomic_dec(&dev->refcnt); |
| @@ -828,6 +913,8 @@ static int w1_init(void) | |||
| 828 | 913 | ||
| 829 | printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n"); | 914 | printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n"); |
| 830 | 915 | ||
| 916 | w1_init_netlink(); | ||
| 917 | |||
| 831 | retval = bus_register(&w1_bus_type); | 918 | retval = bus_register(&w1_bus_type); |
| 832 | if (retval) { | 919 | if (retval) { |
| 833 | printk(KERN_ERR "Failed to register bus. err=%d.\n", retval); | 920 | printk(KERN_ERR "Failed to register bus. err=%d.\n", retval); |
| @@ -880,6 +967,8 @@ static void w1_fini(void) | |||
| 880 | list_for_each_entry(dev, &w1_masters, w1_master_entry) | 967 | list_for_each_entry(dev, &w1_masters, w1_master_entry) |
| 881 | __w1_remove_master_device(dev); | 968 | __w1_remove_master_device(dev); |
| 882 | 969 | ||
| 970 | w1_fini_netlink(); | ||
| 971 | |||
| 883 | kthread_stop(w1_control_thread); | 972 | kthread_stop(w1_control_thread); |
| 884 | 973 | ||
| 885 | driver_unregister(&w1_slave_driver); | 974 | driver_unregister(&w1_slave_driver); |
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 56980505e6c4..f1df5343f4ad 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
| @@ -41,10 +41,7 @@ struct w1_reg_num | |||
| 41 | 41 | ||
| 42 | #include <linux/completion.h> | 42 | #include <linux/completion.h> |
| 43 | #include <linux/device.h> | 43 | #include <linux/device.h> |
| 44 | 44 | #include <linux/mutex.h> | |
| 45 | #include <net/sock.h> | ||
| 46 | |||
| 47 | #include <asm/semaphore.h> | ||
| 48 | 45 | ||
| 49 | #include "w1_family.h" | 46 | #include "w1_family.h" |
| 50 | 47 | ||
| @@ -52,7 +49,7 @@ struct w1_reg_num | |||
| 52 | #define W1_SLAVE_DATA_SIZE 128 | 49 | #define W1_SLAVE_DATA_SIZE 128 |
| 53 | 50 | ||
| 54 | #define W1_SEARCH 0xF0 | 51 | #define W1_SEARCH 0xF0 |
| 55 | #define W1_CONDITIONAL_SEARCH 0xEC | 52 | #define W1_ALARM_SEARCH 0xEC |
| 56 | #define W1_CONVERT_TEMP 0x44 | 53 | #define W1_CONVERT_TEMP 0x44 |
| 57 | #define W1_SKIP_ROM 0xCC | 54 | #define W1_SKIP_ROM 0xCC |
| 58 | #define W1_READ_SCRATCHPAD 0xBE | 55 | #define W1_READ_SCRATCHPAD 0xBE |
| @@ -60,7 +57,7 @@ struct w1_reg_num | |||
| 60 | #define W1_READ_PSUPPLY 0xB4 | 57 | #define W1_READ_PSUPPLY 0xB4 |
| 61 | #define W1_MATCH_ROM 0x55 | 58 | #define W1_MATCH_ROM 0x55 |
| 62 | 59 | ||
| 63 | #define W1_SLAVE_ACTIVE (1<<0) | 60 | #define W1_SLAVE_ACTIVE 0 |
| 64 | 61 | ||
| 65 | struct w1_slave | 62 | struct w1_slave |
| 66 | { | 63 | { |
| @@ -145,8 +142,8 @@ struct w1_bus_master | |||
| 145 | */ | 142 | */ |
| 146 | u8 (*reset_bus)(void *); | 143 | u8 (*reset_bus)(void *); |
| 147 | 144 | ||
| 148 | /** Really nice hardware can handles the ROM searches */ | 145 | /** Really nice hardware can handles the different types of ROM search */ |
| 149 | void (*search)(void *, w1_slave_found_callback); | 146 | void (*search)(void *, u8, w1_slave_found_callback); |
| 150 | }; | 147 | }; |
| 151 | 148 | ||
| 152 | #define W1_MASTER_NEED_EXIT 0 | 149 | #define W1_MASTER_NEED_EXIT 0 |
| @@ -173,19 +170,30 @@ struct w1_master | |||
| 173 | long flags; | 170 | long flags; |
| 174 | 171 | ||
| 175 | struct task_struct *thread; | 172 | struct task_struct *thread; |
| 176 | struct semaphore mutex; | 173 | struct mutex mutex; |
| 177 | 174 | ||
| 178 | struct device_driver *driver; | 175 | struct device_driver *driver; |
| 179 | struct device dev; | 176 | struct device dev; |
| 180 | 177 | ||
| 181 | struct w1_bus_master *bus_master; | 178 | struct w1_bus_master *bus_master; |
| 182 | 179 | ||
| 183 | u32 seq, groups; | 180 | u32 seq; |
| 184 | struct sock *nls; | ||
| 185 | }; | 181 | }; |
| 186 | 182 | ||
| 187 | int w1_create_master_attributes(struct w1_master *); | 183 | int w1_create_master_attributes(struct w1_master *); |
| 188 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb); | 184 | void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); |
| 185 | void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb); | ||
| 186 | struct w1_slave *w1_search_slave(struct w1_reg_num *id); | ||
| 187 | void w1_search_process(struct w1_master *dev, u8 search_type); | ||
| 188 | struct w1_master *w1_search_master_id(u32 id); | ||
| 189 | |||
| 190 | u8 w1_triplet(struct w1_master *dev, int bdir); | ||
| 191 | void w1_write_8(struct w1_master *, u8); | ||
| 192 | int w1_reset_bus(struct w1_master *); | ||
| 193 | u8 w1_calc_crc8(u8 *, int); | ||
| 194 | void w1_write_block(struct w1_master *, const u8 *, int); | ||
| 195 | u8 w1_read_block(struct w1_master *, u8 *, int); | ||
| 196 | int w1_reset_select_slave(struct w1_slave *sl); | ||
| 189 | 197 | ||
| 190 | static inline struct w1_slave* dev_to_w1_slave(struct device *dev) | 198 | static inline struct w1_slave* dev_to_w1_slave(struct device *dev) |
| 191 | { | 199 | { |
| @@ -202,15 +210,14 @@ static inline struct w1_master* dev_to_w1_master(struct device *dev) | |||
| 202 | return container_of(dev, struct w1_master, dev); | 210 | return container_of(dev, struct w1_master, dev); |
| 203 | } | 211 | } |
| 204 | 212 | ||
| 213 | extern struct device_driver w1_master_driver; | ||
| 214 | extern struct device w1_master_device; | ||
| 205 | extern int w1_max_slave_count; | 215 | extern int w1_max_slave_count; |
| 206 | extern int w1_max_slave_ttl; | 216 | extern int w1_max_slave_ttl; |
| 207 | extern spinlock_t w1_mlock; | ||
| 208 | extern struct list_head w1_masters; | 217 | extern struct list_head w1_masters; |
| 209 | extern struct device_driver w1_master_driver; | 218 | extern struct mutex w1_mlock; |
| 210 | extern struct device w1_master_device; | ||
| 211 | 219 | ||
| 212 | int w1_process(void *data); | 220 | extern int w1_process(void *); |
| 213 | void w1_reconnect_slaves(struct w1_family *f); | ||
| 214 | 221 | ||
| 215 | #endif /* __KERNEL__ */ | 222 | #endif /* __KERNEL__ */ |
| 216 | 223 | ||
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c index 0e32c114f906..a3c95bd6890a 100644 --- a/drivers/w1/w1_family.c +++ b/drivers/w1/w1_family.c | |||
| @@ -107,6 +107,12 @@ struct w1_family * w1_family_registered(u8 fid) | |||
| 107 | return (ret) ? f : NULL; | 107 | return (ret) ? f : NULL; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static void __w1_family_put(struct w1_family *f) | ||
| 111 | { | ||
| 112 | if (atomic_dec_and_test(&f->refcnt)) | ||
| 113 | f->need_exit = 1; | ||
| 114 | } | ||
| 115 | |||
| 110 | void w1_family_put(struct w1_family *f) | 116 | void w1_family_put(struct w1_family *f) |
| 111 | { | 117 | { |
| 112 | spin_lock(&w1_flock); | 118 | spin_lock(&w1_flock); |
| @@ -114,19 +120,14 @@ void w1_family_put(struct w1_family *f) | |||
| 114 | spin_unlock(&w1_flock); | 120 | spin_unlock(&w1_flock); |
| 115 | } | 121 | } |
| 116 | 122 | ||
| 117 | void __w1_family_put(struct w1_family *f) | 123 | #if 0 |
| 118 | { | ||
| 119 | if (atomic_dec_and_test(&f->refcnt)) | ||
| 120 | f->need_exit = 1; | ||
| 121 | } | ||
| 122 | |||
| 123 | void w1_family_get(struct w1_family *f) | 124 | void w1_family_get(struct w1_family *f) |
| 124 | { | 125 | { |
| 125 | spin_lock(&w1_flock); | 126 | spin_lock(&w1_flock); |
| 126 | __w1_family_get(f); | 127 | __w1_family_get(f); |
| 127 | spin_unlock(&w1_flock); | 128 | spin_unlock(&w1_flock); |
| 128 | |||
| 129 | } | 129 | } |
| 130 | #endif /* 0 */ | ||
| 130 | 131 | ||
| 131 | void __w1_family_get(struct w1_family *f) | 132 | void __w1_family_get(struct w1_family *f) |
| 132 | { | 133 | { |
| @@ -135,8 +136,5 @@ void __w1_family_get(struct w1_family *f) | |||
| 135 | smp_mb__after_atomic_inc(); | 136 | smp_mb__after_atomic_inc(); |
| 136 | } | 137 | } |
| 137 | 138 | ||
| 138 | EXPORT_SYMBOL(w1_family_get); | ||
| 139 | EXPORT_SYMBOL(w1_family_put); | ||
| 140 | EXPORT_SYMBOL(w1_family_registered); | ||
| 141 | EXPORT_SYMBOL(w1_unregister_family); | 139 | EXPORT_SYMBOL(w1_unregister_family); |
| 142 | EXPORT_SYMBOL(w1_register_family); | 140 | EXPORT_SYMBOL(w1_register_family); |
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h index 2ca0489c716a..1e2ac40c2c14 100644 --- a/drivers/w1/w1_family.h +++ b/drivers/w1/w1_family.h | |||
| @@ -57,12 +57,11 @@ struct w1_family | |||
| 57 | 57 | ||
| 58 | extern spinlock_t w1_flock; | 58 | extern spinlock_t w1_flock; |
| 59 | 59 | ||
| 60 | void w1_family_get(struct w1_family *); | ||
| 61 | void w1_family_put(struct w1_family *); | 60 | void w1_family_put(struct w1_family *); |
| 62 | void __w1_family_get(struct w1_family *); | 61 | void __w1_family_get(struct w1_family *); |
| 63 | void __w1_family_put(struct w1_family *); | ||
| 64 | struct w1_family * w1_family_registered(u8); | 62 | struct w1_family * w1_family_registered(u8); |
| 65 | void w1_unregister_family(struct w1_family *); | 63 | void w1_unregister_family(struct w1_family *); |
| 66 | int w1_register_family(struct w1_family *); | 64 | int w1_register_family(struct w1_family *); |
| 65 | void w1_reconnect_slaves(struct w1_family *f); | ||
| 67 | 66 | ||
| 68 | #endif /* __W1_FAMILY_H */ | 67 | #endif /* __W1_FAMILY_H */ |
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index 68565aacec7b..357a2e0f637a 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
| @@ -65,7 +65,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
| 65 | atomic_set(&dev->refcnt, 2); | 65 | atomic_set(&dev->refcnt, 2); |
| 66 | 66 | ||
| 67 | INIT_LIST_HEAD(&dev->slist); | 67 | INIT_LIST_HEAD(&dev->slist); |
| 68 | init_MUTEX(&dev->mutex); | 68 | mutex_init(&dev->mutex); |
| 69 | 69 | ||
| 70 | memcpy(&dev->dev, device, sizeof(struct device)); | 70 | memcpy(&dev->dev, device, sizeof(struct device)); |
| 71 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), | 71 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), |
| @@ -74,16 +74,11 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
| 74 | 74 | ||
| 75 | dev->driver = driver; | 75 | dev->driver = driver; |
| 76 | 76 | ||
| 77 | dev->groups = 1; | ||
| 78 | dev->seq = 1; | 77 | dev->seq = 1; |
| 79 | dev_init_netlink(dev); | ||
| 80 | 78 | ||
| 81 | err = device_register(&dev->dev); | 79 | err = device_register(&dev->dev); |
| 82 | if (err) { | 80 | if (err) { |
| 83 | printk(KERN_ERR "Failed to register master device. err=%d\n", err); | 81 | printk(KERN_ERR "Failed to register master device. err=%d\n", err); |
| 84 | |||
| 85 | dev_fini_netlink(dev); | ||
| 86 | |||
| 87 | memset(dev, 0, sizeof(struct w1_master)); | 82 | memset(dev, 0, sizeof(struct w1_master)); |
| 88 | kfree(dev); | 83 | kfree(dev); |
| 89 | dev = NULL; | 84 | dev = NULL; |
| @@ -131,12 +126,12 @@ int w1_add_master_device(struct w1_bus_master *master) | |||
| 131 | 126 | ||
| 132 | dev->initialized = 1; | 127 | dev->initialized = 1; |
| 133 | 128 | ||
| 134 | spin_lock(&w1_mlock); | 129 | mutex_lock(&w1_mlock); |
| 135 | list_add(&dev->w1_master_entry, &w1_masters); | 130 | list_add(&dev->w1_master_entry, &w1_masters); |
| 136 | spin_unlock(&w1_mlock); | 131 | mutex_unlock(&w1_mlock); |
| 137 | 132 | ||
| 133 | memset(&msg, 0, sizeof(msg)); | ||
| 138 | msg.id.mst.id = dev->id; | 134 | msg.id.mst.id = dev->id; |
| 139 | msg.id.mst.pid = dev->thread->pid; | ||
| 140 | msg.type = W1_MASTER_ADD; | 135 | msg.type = W1_MASTER_ADD; |
| 141 | w1_netlink_send(dev, &msg); | 136 | w1_netlink_send(dev, &msg); |
| 142 | 137 | ||
| @@ -153,7 +148,6 @@ err_out_free_dev: | |||
| 153 | void __w1_remove_master_device(struct w1_master *dev) | 148 | void __w1_remove_master_device(struct w1_master *dev) |
| 154 | { | 149 | { |
| 155 | struct w1_netlink_msg msg; | 150 | struct w1_netlink_msg msg; |
| 156 | pid_t pid = dev->thread->pid; | ||
| 157 | 151 | ||
| 158 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); | 152 | set_bit(W1_MASTER_NEED_EXIT, &dev->flags); |
| 159 | kthread_stop(dev->thread); | 153 | kthread_stop(dev->thread); |
| @@ -166,8 +160,8 @@ void __w1_remove_master_device(struct w1_master *dev) | |||
| 166 | flush_signals(current); | 160 | flush_signals(current); |
| 167 | } | 161 | } |
| 168 | 162 | ||
| 163 | memset(&msg, 0, sizeof(msg)); | ||
| 169 | msg.id.mst.id = dev->id; | 164 | msg.id.mst.id = dev->id; |
| 170 | msg.id.mst.pid = pid; | ||
| 171 | msg.type = W1_MASTER_REMOVE; | 165 | msg.type = W1_MASTER_REMOVE; |
| 172 | w1_netlink_send(dev, &msg); | 166 | w1_netlink_send(dev, &msg); |
| 173 | 167 | ||
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index f7f7e8bec30e..30b6fbf83bd4 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c | |||
| @@ -23,10 +23,10 @@ | |||
| 23 | 23 | ||
| 24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
| 25 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
| 26 | #include <linux/module.h> | ||
| 26 | 27 | ||
| 27 | #include "w1.h" | 28 | #include "w1.h" |
| 28 | #include "w1_log.h" | 29 | #include "w1_log.h" |
| 29 | #include "w1_io.h" | ||
| 30 | 30 | ||
| 31 | static int w1_delay_parm = 1; | 31 | static int w1_delay_parm = 1; |
| 32 | module_param_named(delay_coef, w1_delay_parm, int, 0); | 32 | module_param_named(delay_coef, w1_delay_parm, int, 0); |
| @@ -50,7 +50,7 @@ static u8 w1_crc8_table[] = { | |||
| 50 | 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 | 50 | 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | void w1_delay(unsigned long tm) | 53 | static void w1_delay(unsigned long tm) |
| 54 | { | 54 | { |
| 55 | udelay(tm * w1_delay_parm); | 55 | udelay(tm * w1_delay_parm); |
| 56 | } | 56 | } |
| @@ -61,7 +61,7 @@ static u8 w1_read_bit(struct w1_master *dev); | |||
| 61 | /** | 61 | /** |
| 62 | * Generates a write-0 or write-1 cycle and samples the level. | 62 | * Generates a write-0 or write-1 cycle and samples the level. |
| 63 | */ | 63 | */ |
| 64 | u8 w1_touch_bit(struct w1_master *dev, int bit) | 64 | static u8 w1_touch_bit(struct w1_master *dev, int bit) |
| 65 | { | 65 | { |
| 66 | if (dev->bus_master->touch_bit) | 66 | if (dev->bus_master->touch_bit) |
| 67 | return dev->bus_master->touch_bit(dev->bus_master->data, bit); | 67 | return dev->bus_master->touch_bit(dev->bus_master->data, bit); |
| @@ -108,6 +108,7 @@ void w1_write_8(struct w1_master *dev, u8 byte) | |||
| 108 | for (i = 0; i < 8; ++i) | 108 | for (i = 0; i < 8; ++i) |
| 109 | w1_touch_bit(dev, (byte >> i) & 0x1); | 109 | w1_touch_bit(dev, (byte >> i) & 0x1); |
| 110 | } | 110 | } |
| 111 | EXPORT_SYMBOL_GPL(w1_write_8); | ||
| 111 | 112 | ||
| 112 | 113 | ||
| 113 | /** | 114 | /** |
| @@ -176,7 +177,7 @@ u8 w1_triplet(struct w1_master *dev, int bdir) | |||
| 176 | * @param dev the master device | 177 | * @param dev the master device |
| 177 | * @return the byte read | 178 | * @return the byte read |
| 178 | */ | 179 | */ |
| 179 | u8 w1_read_8(struct w1_master * dev) | 180 | static u8 w1_read_8(struct w1_master * dev) |
| 180 | { | 181 | { |
| 181 | int i; | 182 | int i; |
| 182 | u8 res = 0; | 183 | u8 res = 0; |
| @@ -208,6 +209,7 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len) | |||
| 208 | for (i = 0; i < len; ++i) | 209 | for (i = 0; i < len; ++i) |
| 209 | w1_write_8(dev, buf[i]); | 210 | w1_write_8(dev, buf[i]); |
| 210 | } | 211 | } |
| 212 | EXPORT_SYMBOL_GPL(w1_write_block); | ||
| 211 | 213 | ||
| 212 | /** | 214 | /** |
| 213 | * Reads a series of bytes. | 215 | * Reads a series of bytes. |
| @@ -232,6 +234,7 @@ u8 w1_read_block(struct w1_master *dev, u8 *buf, int len) | |||
| 232 | 234 | ||
| 233 | return ret; | 235 | return ret; |
| 234 | } | 236 | } |
| 237 | EXPORT_SYMBOL_GPL(w1_read_block); | ||
| 235 | 238 | ||
| 236 | /** | 239 | /** |
| 237 | * Issues a reset bus sequence. | 240 | * Issues a reset bus sequence. |
| @@ -257,6 +260,7 @@ int w1_reset_bus(struct w1_master *dev) | |||
| 257 | 260 | ||
| 258 | return result; | 261 | return result; |
| 259 | } | 262 | } |
| 263 | EXPORT_SYMBOL_GPL(w1_reset_bus); | ||
| 260 | 264 | ||
| 261 | u8 w1_calc_crc8(u8 * data, int len) | 265 | u8 w1_calc_crc8(u8 * data, int len) |
| 262 | { | 266 | { |
| @@ -267,14 +271,15 @@ u8 w1_calc_crc8(u8 * data, int len) | |||
| 267 | 271 | ||
| 268 | return crc; | 272 | return crc; |
| 269 | } | 273 | } |
| 274 | EXPORT_SYMBOL_GPL(w1_calc_crc8); | ||
| 270 | 275 | ||
| 271 | void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb) | 276 | void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) |
| 272 | { | 277 | { |
| 273 | dev->attempts++; | 278 | dev->attempts++; |
| 274 | if (dev->bus_master->search) | 279 | if (dev->bus_master->search) |
| 275 | dev->bus_master->search(dev->bus_master->data, cb); | 280 | dev->bus_master->search(dev->bus_master->data, search_type, cb); |
| 276 | else | 281 | else |
| 277 | w1_search(dev, cb); | 282 | w1_search(dev, search_type, cb); |
| 278 | } | 283 | } |
| 279 | 284 | ||
| 280 | /** | 285 | /** |
| @@ -299,14 +304,4 @@ int w1_reset_select_slave(struct w1_slave *sl) | |||
| 299 | } | 304 | } |
| 300 | return 0; | 305 | return 0; |
| 301 | } | 306 | } |
| 302 | 307 | EXPORT_SYMBOL_GPL(w1_reset_select_slave); | |
| 303 | EXPORT_SYMBOL(w1_touch_bit); | ||
| 304 | EXPORT_SYMBOL(w1_write_8); | ||
| 305 | EXPORT_SYMBOL(w1_read_8); | ||
| 306 | EXPORT_SYMBOL(w1_reset_bus); | ||
| 307 | EXPORT_SYMBOL(w1_calc_crc8); | ||
| 308 | EXPORT_SYMBOL(w1_delay); | ||
| 309 | EXPORT_SYMBOL(w1_read_block); | ||
| 310 | EXPORT_SYMBOL(w1_write_block); | ||
| 311 | EXPORT_SYMBOL(w1_search_devices); | ||
| 312 | EXPORT_SYMBOL(w1_reset_select_slave); | ||
diff --git a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h index 232860184a29..9a76d2ad69c5 100644 --- a/drivers/w1/w1_io.h +++ b/drivers/w1/w1_io.h | |||
| @@ -24,11 +24,8 @@ | |||
| 24 | 24 | ||
| 25 | #include "w1.h" | 25 | #include "w1.h" |
| 26 | 26 | ||
| 27 | void w1_delay(unsigned long); | ||
| 28 | u8 w1_touch_bit(struct w1_master *, int); | ||
| 29 | u8 w1_triplet(struct w1_master *dev, int bdir); | 27 | u8 w1_triplet(struct w1_master *dev, int bdir); |
| 30 | void w1_write_8(struct w1_master *, u8); | 28 | void w1_write_8(struct w1_master *, u8); |
| 31 | u8 w1_read_8(struct w1_master *); | ||
| 32 | int w1_reset_bus(struct w1_master *); | 29 | int w1_reset_bus(struct w1_master *); |
| 33 | u8 w1_calc_crc8(u8 *, int); | 30 | u8 w1_calc_crc8(u8 *, int); |
| 34 | void w1_write_block(struct w1_master *, const u8 *, int); | 31 | void w1_write_block(struct w1_master *, const u8 *, int); |
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 328645da7972..65c5ebd0787e 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
| @@ -21,72 +21,225 @@ | |||
| 21 | 21 | ||
| 22 | #include <linux/skbuff.h> | 22 | #include <linux/skbuff.h> |
| 23 | #include <linux/netlink.h> | 23 | #include <linux/netlink.h> |
| 24 | #include <linux/connector.h> | ||
| 24 | 25 | ||
| 25 | #include "w1.h" | 26 | #include "w1.h" |
| 26 | #include "w1_log.h" | 27 | #include "w1_log.h" |
| 27 | #include "w1_netlink.h" | 28 | #include "w1_netlink.h" |
| 28 | 29 | ||
| 29 | #ifndef NETLINK_DISABLED | 30 | #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE))) |
| 30 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | 31 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) |
| 31 | { | 32 | { |
| 32 | unsigned int size; | 33 | char buf[sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg)]; |
| 33 | struct sk_buff *skb; | 34 | struct cn_msg *m = (struct cn_msg *)buf; |
| 34 | struct w1_netlink_msg *data; | 35 | struct w1_netlink_msg *w = (struct w1_netlink_msg *)(m+1); |
| 35 | struct nlmsghdr *nlh; | ||
| 36 | 36 | ||
| 37 | if (!dev->nls) | 37 | memset(buf, 0, sizeof(buf)); |
| 38 | return; | ||
| 39 | 38 | ||
| 40 | size = NLMSG_SPACE(sizeof(struct w1_netlink_msg)); | 39 | m->id.idx = CN_W1_IDX; |
| 40 | m->id.val = CN_W1_VAL; | ||
| 41 | 41 | ||
| 42 | skb = alloc_skb(size, GFP_ATOMIC); | 42 | m->seq = dev->seq++; |
| 43 | if (!skb) { | 43 | m->len = sizeof(struct w1_netlink_msg); |
| 44 | dev_err(&dev->dev, "skb_alloc() failed.\n"); | 44 | |
| 45 | return; | 45 | memcpy(w, msg, sizeof(struct w1_netlink_msg)); |
| 46 | } | 46 | |
| 47 | cn_netlink_send(m, 0, GFP_KERNEL); | ||
| 48 | } | ||
| 49 | |||
| 50 | static int w1_process_command_master(struct w1_master *dev, struct cn_msg *msg, | ||
| 51 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
| 52 | { | ||
| 53 | dev_dbg(&dev->dev, "%s: %s: cmd=%02x, len=%u.\n", | ||
| 54 | __func__, dev->name, cmd->cmd, cmd->len); | ||
| 55 | |||
| 56 | if (cmd->cmd != W1_CMD_SEARCH && cmd->cmd != W1_CMD_ALARM_SEARCH) | ||
| 57 | return -EINVAL; | ||
| 58 | |||
| 59 | w1_search_process(dev, (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); | ||
| 60 | return 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, | ||
| 64 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
| 65 | { | ||
| 66 | void *data; | ||
| 67 | struct w1_netlink_msg *h; | ||
| 68 | struct w1_netlink_cmd *c; | ||
| 69 | struct cn_msg *cm; | ||
| 70 | int err; | ||
| 71 | |||
| 72 | data = kzalloc(sizeof(struct cn_msg) + | ||
| 73 | sizeof(struct w1_netlink_msg) + | ||
| 74 | sizeof(struct w1_netlink_cmd) + | ||
| 75 | cmd->len, GFP_KERNEL); | ||
| 76 | if (!data) | ||
| 77 | return -ENOMEM; | ||
| 78 | |||
| 79 | cm = (struct cn_msg *)(data); | ||
| 80 | h = (struct w1_netlink_msg *)(cm + 1); | ||
| 81 | c = (struct w1_netlink_cmd *)(h + 1); | ||
| 82 | |||
| 83 | memcpy(cm, msg, sizeof(struct cn_msg)); | ||
| 84 | memcpy(h, hdr, sizeof(struct w1_netlink_msg)); | ||
| 85 | memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); | ||
| 47 | 86 | ||
| 48 | nlh = NLMSG_PUT(skb, 0, dev->seq++, NLMSG_DONE, size - sizeof(*nlh)); | 87 | cm->ack = msg->seq+1; |
| 88 | cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; | ||
| 49 | 89 | ||
| 50 | data = (struct w1_netlink_msg *)NLMSG_DATA(nlh); | 90 | h->len = sizeof(struct w1_netlink_cmd) + cmd->len; |
| 51 | 91 | ||
| 52 | memcpy(data, msg, sizeof(struct w1_netlink_msg)); | 92 | memcpy(c->data, cmd->data, c->len); |
| 53 | 93 | ||
| 54 | NETLINK_CB(skb).dst_group = dev->groups; | 94 | err = cn_netlink_send(cm, 0, GFP_KERNEL); |
| 55 | netlink_broadcast(dev->nls, skb, 0, dev->groups, GFP_ATOMIC); | ||
| 56 | 95 | ||
| 57 | nlmsg_failure: | 96 | kfree(data); |
| 58 | return; | 97 | |
| 98 | return err; | ||
| 59 | } | 99 | } |
| 60 | 100 | ||
| 61 | int dev_init_netlink(struct w1_master *dev) | 101 | static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, |
| 102 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
| 62 | { | 103 | { |
| 63 | dev->nls = netlink_kernel_create(NETLINK_W1, 1, NULL, THIS_MODULE); | 104 | int err = 0; |
| 64 | if (!dev->nls) { | 105 | |
| 65 | printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n", | 106 | dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", |
| 66 | NETLINK_W1, dev->dev.bus_id); | 107 | __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc, |
| 108 | cmd->cmd, cmd->len); | ||
| 109 | |||
| 110 | switch (cmd->cmd) { | ||
| 111 | case W1_CMD_READ: | ||
| 112 | w1_read_block(sl->master, cmd->data, cmd->len); | ||
| 113 | w1_send_read_reply(sl, msg, hdr, cmd); | ||
| 114 | break; | ||
| 115 | case W1_CMD_WRITE: | ||
| 116 | w1_write_block(sl->master, cmd->data, cmd->len); | ||
| 117 | break; | ||
| 118 | case W1_CMD_SEARCH: | ||
| 119 | case W1_CMD_ALARM_SEARCH: | ||
| 120 | w1_search_process(sl->master, | ||
| 121 | (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); | ||
| 122 | break; | ||
| 123 | default: | ||
| 124 | err = -1; | ||
| 125 | break; | ||
| 67 | } | 126 | } |
| 68 | 127 | ||
| 69 | return 0; | 128 | return err; |
| 70 | } | 129 | } |
| 71 | 130 | ||
| 72 | void dev_fini_netlink(struct w1_master *dev) | 131 | static void w1_cn_callback(void *data) |
| 73 | { | 132 | { |
| 74 | if (dev->nls && dev->nls->sk_socket) | 133 | struct cn_msg *msg = data; |
| 75 | sock_release(dev->nls->sk_socket); | 134 | struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); |
| 135 | struct w1_netlink_cmd *cmd; | ||
| 136 | struct w1_slave *sl; | ||
| 137 | struct w1_master *dev; | ||
| 138 | int err = 0; | ||
| 139 | |||
| 140 | while (msg->len && !err) { | ||
| 141 | struct w1_reg_num id; | ||
| 142 | u16 mlen = m->len; | ||
| 143 | u8 *cmd_data = m->data; | ||
| 144 | |||
| 145 | dev = NULL; | ||
| 146 | sl = NULL; | ||
| 147 | |||
| 148 | memcpy(&id, m->id.id, sizeof(id)); | ||
| 149 | #if 0 | ||
| 150 | printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n", | ||
| 151 | __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len); | ||
| 152 | #endif | ||
| 153 | if (m->len + sizeof(struct w1_netlink_msg) > msg->len) { | ||
| 154 | err = -E2BIG; | ||
| 155 | break; | ||
| 156 | } | ||
| 157 | |||
| 158 | if (!mlen) | ||
| 159 | goto out_cont; | ||
| 160 | |||
| 161 | if (m->type == W1_MASTER_CMD) { | ||
| 162 | dev = w1_search_master_id(m->id.mst.id); | ||
| 163 | } else if (m->type == W1_SLAVE_CMD) { | ||
| 164 | sl = w1_search_slave(&id); | ||
| 165 | if (sl) | ||
| 166 | dev = sl->master; | ||
| 167 | } | ||
| 168 | |||
| 169 | if (!dev) { | ||
| 170 | err = -ENODEV; | ||
| 171 | goto out_cont; | ||
| 172 | } | ||
| 173 | |||
| 174 | mutex_lock(&dev->mutex); | ||
| 175 | |||
| 176 | if (sl && w1_reset_select_slave(sl)) { | ||
| 177 | err = -ENODEV; | ||
| 178 | goto out_up; | ||
| 179 | } | ||
| 180 | |||
| 181 | while (mlen) { | ||
| 182 | cmd = (struct w1_netlink_cmd *)cmd_data; | ||
| 183 | |||
| 184 | if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { | ||
| 185 | err = -E2BIG; | ||
| 186 | break; | ||
| 187 | } | ||
| 188 | |||
| 189 | if (sl) | ||
| 190 | w1_process_command_slave(sl, msg, m, cmd); | ||
| 191 | else | ||
| 192 | w1_process_command_master(dev, msg, m, cmd); | ||
| 193 | |||
| 194 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); | ||
| 195 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); | ||
| 196 | } | ||
| 197 | out_up: | ||
| 198 | atomic_dec(&dev->refcnt); | ||
| 199 | if (sl) | ||
| 200 | atomic_dec(&sl->refcnt); | ||
| 201 | mutex_unlock(&dev->mutex); | ||
| 202 | out_cont: | ||
| 203 | msg->len -= sizeof(struct w1_netlink_msg) + m->len; | ||
| 204 | m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); | ||
| 205 | |||
| 206 | /* | ||
| 207 | * Let's allow requests for nonexisting devices. | ||
| 208 | */ | ||
| 209 | if (err == -ENODEV) | ||
| 210 | err = 0; | ||
| 211 | } | ||
| 212 | #if 0 | ||
| 213 | if (err) { | ||
| 214 | printk("%s: malformed message. Dropping.\n", __func__); | ||
| 215 | } | ||
| 216 | #endif | ||
| 76 | } | 217 | } |
| 77 | #else | ||
| 78 | #warning Netlink support is disabled. Please compile with NET support enabled. | ||
| 79 | 218 | ||
| 219 | int w1_init_netlink(void) | ||
| 220 | { | ||
| 221 | struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; | ||
| 222 | |||
| 223 | return cn_add_callback(&w1_id, "w1", &w1_cn_callback); | ||
| 224 | } | ||
| 225 | |||
| 226 | void w1_fini_netlink(void) | ||
| 227 | { | ||
| 228 | struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; | ||
| 229 | |||
| 230 | cn_del_callback(&w1_id); | ||
| 231 | } | ||
| 232 | #else | ||
| 80 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | 233 | void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) |
| 81 | { | 234 | { |
| 82 | } | 235 | } |
| 83 | 236 | ||
| 84 | int dev_init_netlink(struct w1_master *dev) | 237 | int w1_init_netlink(void) |
| 85 | { | 238 | { |
| 86 | return 0; | 239 | return 0; |
| 87 | } | 240 | } |
| 88 | 241 | ||
| 89 | void dev_fini_netlink(struct w1_master *dev) | 242 | void w1_fini_netlink(void) |
| 90 | { | 243 | { |
| 91 | } | 244 | } |
| 92 | #endif | 245 | #endif |
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index eb0c8b3152c8..56122b9e9294 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #define __W1_NETLINK_H | 23 | #define __W1_NETLINK_H |
| 24 | 24 | ||
| 25 | #include <asm/types.h> | 25 | #include <asm/types.h> |
| 26 | #include <linux/connector.h> | ||
| 26 | 27 | ||
| 27 | #include "w1.h" | 28 | #include "w1.h" |
| 28 | 29 | ||
| @@ -31,29 +32,43 @@ enum w1_netlink_message_types { | |||
| 31 | W1_SLAVE_REMOVE, | 32 | W1_SLAVE_REMOVE, |
| 32 | W1_MASTER_ADD, | 33 | W1_MASTER_ADD, |
| 33 | W1_MASTER_REMOVE, | 34 | W1_MASTER_REMOVE, |
| 35 | W1_MASTER_CMD, | ||
| 36 | W1_SLAVE_CMD, | ||
| 34 | }; | 37 | }; |
| 35 | 38 | ||
| 36 | struct w1_netlink_msg | 39 | struct w1_netlink_msg |
| 37 | { | 40 | { |
| 38 | __u8 type; | 41 | __u8 type; |
| 39 | __u8 reserved[3]; | 42 | __u8 reserved; |
| 40 | union | 43 | __u16 len; |
| 41 | { | 44 | union { |
| 42 | struct w1_reg_num id; | 45 | __u8 id[8]; |
| 43 | __u64 w1_id; | 46 | struct w1_mst { |
| 44 | struct | ||
| 45 | { | ||
| 46 | __u32 id; | 47 | __u32 id; |
| 47 | __u32 pid; | 48 | __u32 res; |
| 48 | } mst; | 49 | } mst; |
| 49 | } id; | 50 | } id; |
| 51 | __u8 data[0]; | ||
| 52 | }; | ||
| 53 | |||
| 54 | #define W1_CMD_READ 0x0 | ||
| 55 | #define W1_CMD_WRITE 0x1 | ||
| 56 | #define W1_CMD_SEARCH 0x2 | ||
| 57 | #define W1_CMD_ALARM_SEARCH 0x3 | ||
| 58 | |||
| 59 | struct w1_netlink_cmd | ||
| 60 | { | ||
| 61 | __u8 cmd; | ||
| 62 | __u8 res; | ||
| 63 | __u16 len; | ||
| 64 | __u8 data[0]; | ||
| 50 | }; | 65 | }; |
| 51 | 66 | ||
| 52 | #ifdef __KERNEL__ | 67 | #ifdef __KERNEL__ |
| 53 | 68 | ||
| 54 | void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *); | 69 | void w1_netlink_send(struct w1_master *, struct w1_netlink_msg *); |
| 55 | int dev_init_netlink(struct w1_master *dev); | 70 | int w1_init_netlink(void); |
| 56 | void dev_fini_netlink(struct w1_master *dev); | 71 | void w1_fini_netlink(void); |
| 57 | 72 | ||
| 58 | #endif /* __KERNEL__ */ | 73 | #endif /* __KERNEL__ */ |
| 59 | #endif /* __W1_NETLINK_H */ | 74 | #endif /* __W1_NETLINK_H */ |
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/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/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/msi.h b/include/asm-i386/msi.h index f041d4495faf..b11c4b7dfaef 100644 --- a/include/asm-i386/msi.h +++ b/include/asm-i386/msi.h | |||
| @@ -9,7 +9,15 @@ | |||
| 9 | #include <asm/desc.h> | 9 | #include <asm/desc.h> |
| 10 | #include <mach_apic.h> | 10 | #include <mach_apic.h> |
| 11 | 11 | ||
| 12 | #define LAST_DEVICE_VECTOR 232 | 12 | #define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1) |
| 13 | #define MSI_TARGET_CPU_SHIFT 12 | 13 | #define MSI_TARGET_CPU_SHIFT 12 |
| 14 | 14 | ||
| 15 | extern struct msi_ops msi_apic_ops; | ||
| 16 | |||
| 17 | static inline int msi_arch_init(void) | ||
| 18 | { | ||
| 19 | msi_register(&msi_apic_ops); | ||
| 20 | return 0; | ||
| 21 | } | ||
| 22 | |||
| 15 | #endif /* ASM_MSI_H */ | 23 | #endif /* ASM_MSI_H */ |
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/hw_irq.h b/include/asm-ia64/hw_irq.h index 0cf119b42f7d..ea8b8c407ab4 100644 --- a/include/asm-ia64/hw_irq.h +++ b/include/asm-ia64/hw_irq.h | |||
| @@ -47,9 +47,19 @@ typedef u8 ia64_vector; | |||
| 47 | #define IA64_CMC_VECTOR 0x1f /* corrected machine-check interrupt vector */ | 47 | #define IA64_CMC_VECTOR 0x1f /* corrected machine-check interrupt vector */ |
| 48 | /* | 48 | /* |
| 49 | * Vectors 0x20-0x2f are reserved for legacy ISA IRQs. | 49 | * Vectors 0x20-0x2f are reserved for legacy ISA IRQs. |
| 50 | * Use vectors 0x30-0xe7 as the default device vector range for ia64. | ||
| 51 | * Platforms may choose to reduce this range in platform_irq_setup, but the | ||
| 52 | * platform range must fall within | ||
| 53 | * [IA64_DEF_FIRST_DEVICE_VECTOR..IA64_DEF_LAST_DEVICE_VECTOR] | ||
| 50 | */ | 54 | */ |
| 51 | #define IA64_FIRST_DEVICE_VECTOR 0x30 | 55 | extern int ia64_first_device_vector; |
| 52 | #define IA64_LAST_DEVICE_VECTOR 0xe7 | 56 | extern int ia64_last_device_vector; |
| 57 | |||
| 58 | #define IA64_DEF_FIRST_DEVICE_VECTOR 0x30 | ||
| 59 | #define IA64_DEF_LAST_DEVICE_VECTOR 0xe7 | ||
| 60 | #define IA64_FIRST_DEVICE_VECTOR ia64_first_device_vector | ||
| 61 | #define IA64_LAST_DEVICE_VECTOR ia64_last_device_vector | ||
| 62 | #define IA64_MAX_DEVICE_VECTORS (IA64_DEF_LAST_DEVICE_VECTOR - IA64_DEF_FIRST_DEVICE_VECTOR + 1) | ||
| 53 | #define IA64_NUM_DEVICE_VECTORS (IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1) | 63 | #define IA64_NUM_DEVICE_VECTORS (IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1) |
| 54 | 64 | ||
| 55 | #define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */ | 65 | #define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */ |
| @@ -83,6 +93,7 @@ extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt | |||
| 83 | 93 | ||
| 84 | extern int assign_irq_vector (int irq); /* allocate a free vector */ | 94 | extern int assign_irq_vector (int irq); /* allocate a free vector */ |
| 85 | extern void free_irq_vector (int vector); | 95 | extern void free_irq_vector (int vector); |
| 96 | extern int reserve_irq_vector (int vector); | ||
| 86 | extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); | 97 | extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); |
| 87 | extern void register_percpu_irq (ia64_vector vec, struct irqaction *action); | 98 | extern void register_percpu_irq (ia64_vector vec, struct irqaction *action); |
| 88 | 99 | ||
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h index 0df72a134c8b..15b545a897a4 100644 --- a/include/asm-ia64/machvec.h +++ b/include/asm-ia64/machvec.h | |||
| @@ -75,6 +75,7 @@ typedef unsigned char ia64_mv_readb_relaxed_t (const volatile void __iomem *); | |||
| 75 | typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *); | 75 | typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *); |
| 76 | typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *); | 76 | typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *); |
| 77 | typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *); | 77 | typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *); |
| 78 | typedef int ia64_mv_msi_init_t (void); | ||
| 78 | 79 | ||
| 79 | static inline void | 80 | static inline void |
| 80 | machvec_noop (void) | 81 | machvec_noop (void) |
| @@ -153,6 +154,7 @@ extern void machvec_tlb_migrate_finish (struct mm_struct *); | |||
| 153 | # define platform_readl_relaxed ia64_mv.readl_relaxed | 154 | # define platform_readl_relaxed ia64_mv.readl_relaxed |
| 154 | # define platform_readq_relaxed ia64_mv.readq_relaxed | 155 | # define platform_readq_relaxed ia64_mv.readq_relaxed |
| 155 | # define platform_migrate ia64_mv.migrate | 156 | # define platform_migrate ia64_mv.migrate |
| 157 | # define platform_msi_init ia64_mv.msi_init | ||
| 156 | # endif | 158 | # endif |
| 157 | 159 | ||
| 158 | /* __attribute__((__aligned__(16))) is required to make size of the | 160 | /* __attribute__((__aligned__(16))) is required to make size of the |
| @@ -202,6 +204,7 @@ struct ia64_machine_vector { | |||
| 202 | ia64_mv_readl_relaxed_t *readl_relaxed; | 204 | ia64_mv_readl_relaxed_t *readl_relaxed; |
| 203 | ia64_mv_readq_relaxed_t *readq_relaxed; | 205 | ia64_mv_readq_relaxed_t *readq_relaxed; |
| 204 | ia64_mv_migrate_t *migrate; | 206 | ia64_mv_migrate_t *migrate; |
| 207 | ia64_mv_msi_init_t *msi_init; | ||
| 205 | } __attribute__((__aligned__(16))); /* align attrib? see above comment */ | 208 | } __attribute__((__aligned__(16))); /* align attrib? see above comment */ |
| 206 | 209 | ||
| 207 | #define MACHVEC_INIT(name) \ | 210 | #define MACHVEC_INIT(name) \ |
| @@ -247,6 +250,7 @@ struct ia64_machine_vector { | |||
| 247 | platform_readl_relaxed, \ | 250 | platform_readl_relaxed, \ |
| 248 | platform_readq_relaxed, \ | 251 | platform_readq_relaxed, \ |
| 249 | platform_migrate, \ | 252 | platform_migrate, \ |
| 253 | platform_msi_init, \ | ||
| 250 | } | 254 | } |
| 251 | 255 | ||
| 252 | extern struct ia64_machine_vector ia64_mv; | 256 | extern struct ia64_machine_vector ia64_mv; |
| @@ -400,5 +404,8 @@ extern int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size | |||
| 400 | #ifndef platform_migrate | 404 | #ifndef platform_migrate |
| 401 | # define platform_migrate machvec_noop_task | 405 | # define platform_migrate machvec_noop_task |
| 402 | #endif | 406 | #endif |
| 407 | #ifndef platform_msi_init | ||
| 408 | # define platform_msi_init ((ia64_mv_msi_init_t*)NULL) | ||
| 409 | #endif | ||
| 403 | 410 | ||
| 404 | #endif /* _ASM_IA64_MACHVEC_H */ | 411 | #endif /* _ASM_IA64_MACHVEC_H */ |
diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h index da1d43755afe..cf724dc79d8c 100644 --- a/include/asm-ia64/machvec_sn2.h +++ b/include/asm-ia64/machvec_sn2.h | |||
| @@ -67,6 +67,8 @@ extern ia64_mv_dma_sync_sg_for_device sn_dma_sync_sg_for_device; | |||
| 67 | extern ia64_mv_dma_mapping_error sn_dma_mapping_error; | 67 | extern ia64_mv_dma_mapping_error sn_dma_mapping_error; |
| 68 | extern ia64_mv_dma_supported sn_dma_supported; | 68 | extern ia64_mv_dma_supported sn_dma_supported; |
| 69 | extern ia64_mv_migrate_t sn_migrate; | 69 | extern ia64_mv_migrate_t sn_migrate; |
| 70 | extern ia64_mv_msi_init_t sn_msi_init; | ||
| 71 | |||
| 70 | 72 | ||
| 71 | /* | 73 | /* |
| 72 | * This stuff has dual use! | 74 | * This stuff has dual use! |
| @@ -117,6 +119,11 @@ extern ia64_mv_migrate_t sn_migrate; | |||
| 117 | #define platform_dma_mapping_error sn_dma_mapping_error | 119 | #define platform_dma_mapping_error sn_dma_mapping_error |
| 118 | #define platform_dma_supported sn_dma_supported | 120 | #define platform_dma_supported sn_dma_supported |
| 119 | #define platform_migrate sn_migrate | 121 | #define platform_migrate sn_migrate |
| 122 | #ifdef CONFIG_PCI_MSI | ||
| 123 | #define platform_msi_init sn_msi_init | ||
| 124 | #else | ||
| 125 | #define platform_msi_init ((ia64_mv_msi_init_t*)NULL) | ||
| 126 | #endif | ||
| 120 | 127 | ||
| 121 | #include <asm/sn/io.h> | 128 | #include <asm/sn/io.h> |
| 122 | 129 | ||
diff --git a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h index 97890f7762b3..bb92b0dbde2f 100644 --- a/include/asm-ia64/msi.h +++ b/include/asm-ia64/msi.h | |||
| @@ -14,4 +14,16 @@ static inline void set_intr_gate (int nr, void *func) {} | |||
| 14 | #define ack_APIC_irq ia64_eoi | 14 | #define ack_APIC_irq ia64_eoi |
| 15 | #define MSI_TARGET_CPU_SHIFT 4 | 15 | #define MSI_TARGET_CPU_SHIFT 4 |
| 16 | 16 | ||
| 17 | extern struct msi_ops msi_apic_ops; | ||
| 18 | |||
| 19 | static inline int msi_arch_init(void) | ||
| 20 | { | ||
| 21 | if (platform_msi_init) | ||
| 22 | return platform_msi_init(); | ||
| 23 | |||
| 24 | /* default ops for most ia64 platforms */ | ||
| 25 | msi_register(&msi_apic_ops); | ||
| 26 | return 0; | ||
| 27 | } | ||
| 28 | |||
| 17 | #endif /* ASM_MSI_H */ | 29 | #endif /* ASM_MSI_H */ |
diff --git a/include/asm-ia64/sn/intr.h b/include/asm-ia64/sn/intr.h index 60a51a406eec..12b54ddb06be 100644 --- a/include/asm-ia64/sn/intr.h +++ b/include/asm-ia64/sn/intr.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #define _ASM_IA64_SN_INTR_H | 10 | #define _ASM_IA64_SN_INTR_H |
| 11 | 11 | ||
| 12 | #include <linux/rcupdate.h> | 12 | #include <linux/rcupdate.h> |
| 13 | #include <asm/sn/types.h> | ||
| 13 | 14 | ||
| 14 | #define SGI_UART_VECTOR 0xe9 | 15 | #define SGI_UART_VECTOR 0xe9 |
| 15 | 16 | ||
| @@ -40,6 +41,7 @@ struct sn_irq_info { | |||
| 40 | int irq_cpuid; /* kernel logical cpuid */ | 41 | int irq_cpuid; /* kernel logical cpuid */ |
| 41 | int irq_irq; /* the IRQ number */ | 42 | int irq_irq; /* the IRQ number */ |
| 42 | int irq_int_bit; /* Bridge interrupt pin */ | 43 | int irq_int_bit; /* Bridge interrupt pin */ |
| 44 | /* <0 means MSI */ | ||
| 43 | u64 irq_xtalkaddr; /* xtalkaddr IRQ is sent to */ | 45 | u64 irq_xtalkaddr; /* xtalkaddr IRQ is sent to */ |
| 44 | int irq_bridge_type;/* pciio asic type (pciio.h) */ | 46 | int irq_bridge_type;/* pciio asic type (pciio.h) */ |
| 45 | void *irq_bridge; /* bridge generating irq */ | 47 | void *irq_bridge; /* bridge generating irq */ |
| @@ -53,6 +55,12 @@ struct sn_irq_info { | |||
| 53 | }; | 55 | }; |
| 54 | 56 | ||
| 55 | extern void sn_send_IPI_phys(int, long, int, int); | 57 | extern void sn_send_IPI_phys(int, long, int, int); |
| 58 | extern u64 sn_intr_alloc(nasid_t, int, | ||
| 59 | struct sn_irq_info *, | ||
| 60 | int, nasid_t, int); | ||
| 61 | extern void sn_intr_free(nasid_t, int, struct sn_irq_info *); | ||
| 62 | extern struct sn_irq_info *sn_retarget_vector(struct sn_irq_info *, nasid_t, int); | ||
| 63 | extern struct list_head **sn_irq_lh; | ||
| 56 | 64 | ||
| 57 | #define CPU_VECTOR_TO_IRQ(cpuid,vector) (vector) | 65 | #define CPU_VECTOR_TO_IRQ(cpuid,vector) (vector) |
| 58 | 66 | ||
diff --git a/include/asm-ia64/sn/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h index 51260ab70d91..e3b0c3fe5eed 100644 --- a/include/asm-ia64/sn/pcibr_provider.h +++ b/include/asm-ia64/sn/pcibr_provider.h | |||
| @@ -55,6 +55,7 @@ | |||
| 55 | #define PCI32_ATE_V (0x1 << 0) | 55 | #define PCI32_ATE_V (0x1 << 0) |
| 56 | #define PCI32_ATE_CO (0x1 << 1) | 56 | #define PCI32_ATE_CO (0x1 << 1) |
| 57 | #define PCI32_ATE_PREC (0x1 << 2) | 57 | #define PCI32_ATE_PREC (0x1 << 2) |
| 58 | #define PCI32_ATE_MSI (0x1 << 2) | ||
| 58 | #define PCI32_ATE_PREF (0x1 << 3) | 59 | #define PCI32_ATE_PREF (0x1 << 3) |
| 59 | #define PCI32_ATE_BAR (0x1 << 4) | 60 | #define PCI32_ATE_BAR (0x1 << 4) |
| 60 | #define PCI32_ATE_ADDR_SHFT 12 | 61 | #define PCI32_ATE_ADDR_SHFT 12 |
| @@ -117,8 +118,8 @@ struct pcibus_info { | |||
| 117 | 118 | ||
| 118 | extern int pcibr_init_provider(void); | 119 | extern int pcibr_init_provider(void); |
| 119 | extern void *pcibr_bus_fixup(struct pcibus_bussoft *, struct pci_controller *); | 120 | extern void *pcibr_bus_fixup(struct pcibus_bussoft *, struct pci_controller *); |
| 120 | extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t); | 121 | extern dma_addr_t pcibr_dma_map(struct pci_dev *, unsigned long, size_t, int type); |
| 121 | extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t); | 122 | extern dma_addr_t pcibr_dma_map_consistent(struct pci_dev *, unsigned long, size_t, int type); |
| 122 | extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int); | 123 | extern void pcibr_dma_unmap(struct pci_dev *, dma_addr_t, int); |
| 123 | 124 | ||
| 124 | /* | 125 | /* |
diff --git a/include/asm-ia64/sn/pcibus_provider_defs.h b/include/asm-ia64/sn/pcibus_provider_defs.h index ce3f6c328241..8f7c83d0f6d3 100644 --- a/include/asm-ia64/sn/pcibus_provider_defs.h +++ b/include/asm-ia64/sn/pcibus_provider_defs.h | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
| 4 | * for more details. | 4 | * for more details. |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 1992 - 1997, 2000-2004 Silicon Graphics, Inc. All rights reserved. | 6 | * Copyright (C) 1992 - 1997, 2000-2005 Silicon Graphics, Inc. All rights reserved. |
| 7 | */ | 7 | */ |
| 8 | #ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H | 8 | #ifndef _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H |
| 9 | #define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H | 9 | #define _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H |
| @@ -45,13 +45,24 @@ struct pci_controller; | |||
| 45 | */ | 45 | */ |
| 46 | 46 | ||
| 47 | struct sn_pcibus_provider { | 47 | struct sn_pcibus_provider { |
| 48 | dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t); | 48 | dma_addr_t (*dma_map)(struct pci_dev *, unsigned long, size_t, int flags); |
| 49 | dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t); | 49 | dma_addr_t (*dma_map_consistent)(struct pci_dev *, unsigned long, size_t, int flags); |
| 50 | void (*dma_unmap)(struct pci_dev *, dma_addr_t, int); | 50 | void (*dma_unmap)(struct pci_dev *, dma_addr_t, int); |
| 51 | void * (*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *); | 51 | void * (*bus_fixup)(struct pcibus_bussoft *, struct pci_controller *); |
| 52 | void (*force_interrupt)(struct sn_irq_info *); | 52 | void (*force_interrupt)(struct sn_irq_info *); |
| 53 | void (*target_interrupt)(struct sn_irq_info *); | 53 | void (*target_interrupt)(struct sn_irq_info *); |
| 54 | }; | 54 | }; |
| 55 | 55 | ||
| 56 | /* | ||
| 57 | * Flags used by the map interfaces | ||
| 58 | * bits 3:0 specifies format of passed in address | ||
| 59 | * bit 4 specifies that address is to be used for MSI | ||
| 60 | */ | ||
| 61 | |||
| 62 | #define SN_DMA_ADDRTYPE(x) ((x) & 0xf) | ||
| 63 | #define SN_DMA_ADDR_PHYS 1 /* address is an xio address. */ | ||
| 64 | #define SN_DMA_ADDR_XIO 2 /* address is phys memory */ | ||
| 65 | #define SN_DMA_MSI 0x10 /* Bus address is to be used for MSI */ | ||
| 66 | |||
| 56 | extern struct sn_pcibus_provider *sn_pci_provider[]; | 67 | extern struct sn_pcibus_provider *sn_pci_provider[]; |
| 57 | #endif /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */ | 68 | #endif /* _ASM_IA64_SN_PCI_PCIBUS_PROVIDER_H */ |
diff --git a/include/asm-ia64/sn/tiocp.h b/include/asm-ia64/sn/tiocp.h index f47c08ab483c..e8ad0bb5b6c5 100644 --- a/include/asm-ia64/sn/tiocp.h +++ b/include/asm-ia64/sn/tiocp.h | |||
| @@ -3,13 +3,14 @@ | |||
| 3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
| 4 | * for more details. | 4 | * for more details. |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 2003-2004 Silicon Graphics, Inc. All rights reserved. | 6 | * Copyright (C) 2003-2005 Silicon Graphics, Inc. All rights reserved. |
| 7 | */ | 7 | */ |
| 8 | #ifndef _ASM_IA64_SN_PCI_TIOCP_H | 8 | #ifndef _ASM_IA64_SN_PCI_TIOCP_H |
| 9 | #define _ASM_IA64_SN_PCI_TIOCP_H | 9 | #define _ASM_IA64_SN_PCI_TIOCP_H |
| 10 | 10 | ||
| 11 | #define TIOCP_HOST_INTR_ADDR 0x003FFFFFFFFFFFFFUL | 11 | #define TIOCP_HOST_INTR_ADDR 0x003FFFFFFFFFFFFFUL |
| 12 | #define TIOCP_PCI64_CMDTYPE_MEM (0x1ull << 60) | 12 | #define TIOCP_PCI64_CMDTYPE_MEM (0x1ull << 60) |
| 13 | #define TIOCP_PCI64_CMDTYPE_MSI (0x3ull << 60) | ||
| 13 | 14 | ||
| 14 | 15 | ||
| 15 | /***************************************************************************** | 16 | /***************************************************************************** |
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/msi.h b/include/asm-x86_64/msi.h index 356e0e82f50b..3ad2346624b2 100644 --- a/include/asm-x86_64/msi.h +++ b/include/asm-x86_64/msi.h | |||
| @@ -10,7 +10,15 @@ | |||
| 10 | #include <asm/mach_apic.h> | 10 | #include <asm/mach_apic.h> |
| 11 | #include <asm/smp.h> | 11 | #include <asm/smp.h> |
| 12 | 12 | ||
| 13 | #define LAST_DEVICE_VECTOR 232 | 13 | #define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1) |
| 14 | #define MSI_TARGET_CPU_SHIFT 12 | 14 | #define MSI_TARGET_CPU_SHIFT 12 |
| 15 | 15 | ||
| 16 | extern struct msi_ops msi_apic_ops; | ||
| 17 | |||
| 18 | static inline int msi_arch_init(void) | ||
| 19 | { | ||
| 20 | msi_register(&msi_apic_ops); | ||
| 21 | return 0; | ||
| 22 | } | ||
| 23 | |||
| 16 | #endif /* ASM_MSI_H */ | 24 | #endif /* ASM_MSI_H */ |
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/connector.h b/include/linux/connector.h index ad1a22c1c42e..4c02119c6ab9 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h | |||
| @@ -34,8 +34,11 @@ | |||
| 34 | #define CN_VAL_PROC 0x1 | 34 | #define CN_VAL_PROC 0x1 |
| 35 | #define CN_IDX_CIFS 0x2 | 35 | #define CN_IDX_CIFS 0x2 |
| 36 | #define CN_VAL_CIFS 0x1 | 36 | #define CN_VAL_CIFS 0x1 |
| 37 | #define CN_W1_IDX 0x3 /* w1 communication */ | ||
| 38 | #define CN_W1_VAL 0x1 | ||
| 37 | 39 | ||
| 38 | #define CN_NETLINK_USERS 1 | 40 | |
| 41 | #define CN_NETLINK_USERS 4 | ||
| 39 | 42 | ||
| 40 | /* | 43 | /* |
| 41 | * Maximum connector's message size. | 44 | * Maximum connector's message size. |
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/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/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/netlink.h b/include/linux/netlink.h index 87b8a5703ebc..855b44668caa 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
| 6 | 6 | ||
| 7 | #define NETLINK_ROUTE 0 /* Routing/device hook */ | 7 | #define NETLINK_ROUTE 0 /* Routing/device hook */ |
| 8 | #define NETLINK_W1 1 /* 1-wire subsystem */ | 8 | #define NETLINK_UNUSED 1 /* Unused number */ |
| 9 | #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ | 9 | #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ |
| 10 | #define NETLINK_FIREWALL 3 /* Firewalling hook */ | 10 | #define NETLINK_FIREWALL 3 /* Firewalling hook */ |
| 11 | #define NETLINK_INET_DIAG 4 /* INET socket monitoring */ | 11 | #define NETLINK_INET_DIAG 4 /* INET socket monitoring */ |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 6c4bc773f7b7..62a8c22f5f60 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
| @@ -162,6 +162,9 @@ struct pci_dev { | |||
| 162 | unsigned int is_busmaster:1; /* device is busmaster */ | 162 | unsigned int is_busmaster:1; /* device is busmaster */ |
| 163 | unsigned int no_msi:1; /* device may not use msi */ | 163 | unsigned int no_msi:1; /* device may not use msi */ |
| 164 | unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ | 164 | unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ |
| 165 | unsigned int broken_parity_status:1; /* Device generates false positive parity */ | ||
| 166 | unsigned int msi_enabled:1; | ||
| 167 | unsigned int msix_enabled:1; | ||
| 165 | 168 | ||
| 166 | u32 saved_config_space[16]; /* config space saved at suspend time */ | 169 | u32 saved_config_space[16]; /* config space saved at suspend time */ |
| 167 | struct hlist_head saved_cap_space; | 170 | struct hlist_head saved_cap_space; |
| @@ -496,6 +499,7 @@ int pci_set_dma_mask(struct pci_dev *dev, u64 mask); | |||
| 496 | int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); | 499 | int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); |
| 497 | void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); | 500 | void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); |
| 498 | int pci_assign_resource(struct pci_dev *dev, int i); | 501 | int pci_assign_resource(struct pci_dev *dev, int i); |
| 502 | int pci_assign_resource_fixed(struct pci_dev *dev, int i); | ||
| 499 | void pci_restore_bars(struct pci_dev *dev); | 503 | void pci_restore_bars(struct pci_dev *dev); |
| 500 | 504 | ||
| 501 | /* ROM control related routines */ | 505 | /* ROM control related routines */ |
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index d33436097e1d..cde701c13c77 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h | |||
| @@ -851,7 +851,12 @@ | |||
| 851 | 851 | ||
| 852 | 852 | ||
| 853 | #define PCI_VENDOR_ID_QLOGIC 0x1077 | 853 | #define PCI_VENDOR_ID_QLOGIC 0x1077 |
| 854 | #define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016 | ||
| 854 | #define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020 | 855 | #define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020 |
| 856 | #define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080 | ||
| 857 | #define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216 | ||
| 858 | #define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240 | ||
| 859 | #define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280 | ||
| 855 | #define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100 | 860 | #define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100 |
| 856 | #define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200 | 861 | #define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200 |
| 857 | #define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300 | 862 | #define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300 |
| @@ -1021,6 +1026,7 @@ | |||
| 1021 | #define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056 | 1026 | #define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056 |
| 1022 | #define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057 | 1027 | #define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057 |
| 1023 | #define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059 | 1028 | #define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059 |
| 1029 | #define PCI_DEVICE_ID_NVIDIA_CK804_PCIE 0x005d | ||
| 1024 | #define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064 | 1030 | #define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064 |
| 1025 | #define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 | 1031 | #define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 |
| 1026 | #define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066 | 1032 | #define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066 |
| @@ -1951,6 +1957,7 @@ | |||
| 1951 | 1957 | ||
| 1952 | #define PCI_VENDOR_ID_MELLANOX 0x15b3 | 1958 | #define PCI_VENDOR_ID_MELLANOX 0x15b3 |
| 1953 | #define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 | 1959 | #define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 |
| 1960 | #define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46 | ||
| 1954 | #define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 | 1961 | #define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 |
| 1955 | #define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 | 1962 | #define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 |
| 1956 | #define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c | 1963 | #define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c |
| @@ -1974,6 +1981,9 @@ | |||
| 1974 | #define PCI_VENDOR_ID_NETCELL 0x169c | 1981 | #define PCI_VENDOR_ID_NETCELL 0x169c |
| 1975 | #define PCI_DEVICE_ID_REVOLUTION 0x0044 | 1982 | #define PCI_DEVICE_ID_REVOLUTION 0x0044 |
| 1976 | 1983 | ||
| 1984 | #define PCI_VENDOR_ID_VITESSE 0x1725 | ||
| 1985 | #define PCI_DEVICE_ID_VITESSE_VSC7174 0x7174 | ||
| 1986 | |||
| 1977 | #define PCI_VENDOR_ID_LINKSYS 0x1737 | 1987 | #define PCI_VENDOR_ID_LINKSYS 0x1737 |
| 1978 | #define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064 | 1988 | #define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064 |
| 1979 | 1989 | ||
| @@ -2153,6 +2163,7 @@ | |||
| 2153 | #define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 | 2163 | #define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 |
| 2154 | #define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e | 2164 | #define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e |
| 2155 | #define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 | 2165 | #define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 |
| 2166 | #define PCI_DEVICE_ID_INTEL_GD31244 0x3200 | ||
| 2156 | #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 | 2167 | #define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 |
| 2157 | #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 | 2168 | #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 |
| 2158 | #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 | 2169 | #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 |
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index d27a78b71297..6bce4a240364 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h | |||
| @@ -197,6 +197,7 @@ | |||
| 197 | #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ | 197 | #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ |
| 198 | #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ | 198 | #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ |
| 199 | #define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */ | 199 | #define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */ |
| 200 | #define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */ | ||
| 200 | #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ | 201 | #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ |
| 201 | #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ | 202 | #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ |
| 202 | #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ | 203 | #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ |
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/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/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 | } |
