diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-06-22 22:11:56 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-06-22 22:11:56 -0400 |
commit | 71d530cd1b6d97094481002a04c77fea1c8e1c22 (patch) | |
tree | e786da7145d83c19a594adf76ed90d52c51058b1 /sound | |
parent | d7a80dad2fe19a2b8c119c8e9cba605474a75a2b (diff) | |
parent | d588fcbe5a7ba8bba2cebf7799ab2d573717a806 (diff) |
Merge branch 'master' into upstream
Conflicts:
drivers/scsi/libata-core.c
drivers/scsi/libata-scsi.c
include/linux/pci_ids.h
Diffstat (limited to 'sound')
202 files changed, 10031 insertions, 2156 deletions
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/oss/Kconfig b/sound/oss/Kconfig index 558c6ed443be..080ab036b67a 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig | |||
@@ -98,8 +98,8 @@ config SOUND_HAL2 | |||
98 | tristate "SGI HAL2 sound (EXPERIMENTAL)" | 98 | tristate "SGI HAL2 sound (EXPERIMENTAL)" |
99 | depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL | 99 | depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL |
100 | help | 100 | help |
101 | Say Y or M if you have an SGI Indy system and want to be able to | 101 | Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to |
102 | use it's on-board A2 audio system. | 102 | use its on-board A2 audio system. |
103 | 103 | ||
104 | config SOUND_IT8172 | 104 | config SOUND_IT8172 |
105 | tristate "IT8172G Sound" | 105 | tristate "IT8172G Sound" |
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/amd7930.c b/sound/sparc/amd7930.c index 55493340f467..dfe9bac7fa32 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c | |||
@@ -977,9 +977,9 @@ static int __init snd_amd7930_create(struct snd_card *card, | |||
977 | 977 | ||
978 | if (request_irq(irq_prop->pri, snd_amd7930_interrupt, | 978 | if (request_irq(irq_prop->pri, snd_amd7930_interrupt, |
979 | SA_INTERRUPT | SA_SHIRQ, "amd7930", amd)) { | 979 | SA_INTERRUPT | SA_SHIRQ, "amd7930", amd)) { |
980 | snd_printk("amd7930-%d: Unable to grab IRQ %s\n", | 980 | snd_printk("amd7930-%d: Unable to grab IRQ %d\n", |
981 | dev, | 981 | dev, |
982 | __irq_itoa(irq_prop->pri)); | 982 | irq_prop->pri); |
983 | snd_amd7930_free(amd); | 983 | snd_amd7930_free(amd); |
984 | return -EBUSY; | 984 | return -EBUSY; |
985 | } | 985 | } |
@@ -1063,11 +1063,11 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev) | |||
1063 | 1063 | ||
1064 | strcpy(card->driver, "AMD7930"); | 1064 | strcpy(card->driver, "AMD7930"); |
1065 | strcpy(card->shortname, "Sun AMD7930"); | 1065 | strcpy(card->shortname, "Sun AMD7930"); |
1066 | sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s", | 1066 | sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d", |
1067 | card->shortname, | 1067 | card->shortname, |
1068 | rp->flags & 0xffL, | 1068 | rp->flags & 0xffL, |
1069 | rp->start, | 1069 | rp->start, |
1070 | __irq_itoa(irq_prop.pri)); | 1070 | irq_prop.pri); |
1071 | 1071 | ||
1072 | if ((err = snd_amd7930_create(card, sdev, rp, reg_prop.reg_size, | 1072 | if ((err = snd_amd7930_create(card, sdev, rp, reg_prop.reg_size, |
1073 | &irq_prop, dev, &amd)) < 0) | 1073 | &irq_prop, dev, &amd)) < 0) |
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 8804f26ddb3a..b3efc9aa2916 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c | |||
@@ -2003,9 +2003,8 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card, | |||
2003 | 2003 | ||
2004 | if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, | 2004 | if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, |
2005 | SA_SHIRQ, "cs4231", chip)) { | 2005 | SA_SHIRQ, "cs4231", chip)) { |
2006 | snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n", | 2006 | snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n", |
2007 | dev, | 2007 | dev, sdev->irqs[0]); |
2008 | __irq_itoa(sdev->irqs[0])); | ||
2009 | snd_cs4231_sbus_free(chip); | 2008 | snd_cs4231_sbus_free(chip); |
2010 | return -EBUSY; | 2009 | return -EBUSY; |
2011 | } | 2010 | } |
@@ -2038,11 +2037,11 @@ static int __init cs4231_sbus_attach(struct sbus_dev *sdev) | |||
2038 | if (err) | 2037 | if (err) |
2039 | return err; | 2038 | return err; |
2040 | 2039 | ||
2041 | sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s", | 2040 | sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d", |
2042 | card->shortname, | 2041 | card->shortname, |
2043 | rp->flags & 0xffL, | 2042 | rp->flags & 0xffL, |
2044 | rp->start, | 2043 | rp->start, |
2045 | __irq_itoa(sdev->irqs[0])); | 2044 | sdev->irqs[0]); |
2046 | 2045 | ||
2047 | if ((err = snd_cs4231_sbus_create(card, sdev, dev, &cp)) < 0) { | 2046 | if ((err = snd_cs4231_sbus_create(card, sdev, dev, &cp)) < 0) { |
2048 | snd_card_free(card); | 2047 | snd_card_free(card); |
@@ -2244,10 +2243,10 @@ static int __init cs4231_ebus_attach(struct linux_ebus_device *edev) | |||
2244 | if (err) | 2243 | if (err) |
2245 | return err; | 2244 | return err; |
2246 | 2245 | ||
2247 | sprintf(card->longname, "%s at 0x%lx, irq %s", | 2246 | sprintf(card->longname, "%s at 0x%lx, irq %d", |
2248 | card->shortname, | 2247 | card->shortname, |
2249 | edev->resource[0].start, | 2248 | edev->resource[0].start, |
2250 | __irq_itoa(edev->irqs[0])); | 2249 | edev->irqs[0]); |
2251 | 2250 | ||
2252 | if ((err = snd_cs4231_ebus_create(card, edev, dev, &chip)) < 0) { | 2251 | if ((err = snd_cs4231_ebus_create(card, edev, dev, &chip)) < 0) { |
2253 | snd_card_free(card); | 2252 | snd_card_free(card); |
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 2164b7d290c7..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 |
@@ -2645,9 +2645,9 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) | |||
2645 | strcpy(card->driver, "DBRI"); | 2645 | strcpy(card->driver, "DBRI"); |
2646 | strcpy(card->shortname, "Sun DBRI"); | 2646 | strcpy(card->shortname, "Sun DBRI"); |
2647 | rp = &sdev->resource[0]; | 2647 | rp = &sdev->resource[0]; |
2648 | sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %s", | 2648 | sprintf(card->longname, "%s at 0x%02lx:0x%08lx, irq %d", |
2649 | card->shortname, | 2649 | card->shortname, |
2650 | rp->flags & 0xffL, rp->start, __irq_itoa(irq.pri)); | 2650 | rp->flags & 0xffL, rp->start, irq.pri); |
2651 | 2651 | ||
2652 | if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) { | 2652 | if ((err = snd_dbri_create(card, sdev, &irq, dev)) < 0) { |
2653 | snd_card_free(card); | 2653 | snd_card_free(card); |
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 | } |