Blame view
sound/core/sound.c
9.9 KB
1a59d1b8e treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c Linux-2.6.12-rc2 |
2 3 |
/* * Advanced Linux Sound Architecture |
c1017a4cd [ALSA] Changed Ja... |
4 |
* Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
1da177e4c Linux-2.6.12-rc2 |
5 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
6 7 8 |
#include <linux/init.h> #include <linux/slab.h> #include <linux/time.h> |
9a1a2a1d4 [ALSA] Fix a miss... |
9 |
#include <linux/device.h> |
65a772172 sound: fix driver... |
10 |
#include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
11 12 13 |
#include <sound/core.h> #include <sound/minors.h> #include <sound/info.h> |
1da177e4c Linux-2.6.12-rc2 |
14 15 16 |
#include <sound/control.h> #include <sound/initval.h> #include <linux/kmod.h> |
1a60d4c5a [ALSA] semaphore ... |
17 |
#include <linux/mutex.h> |
1da177e4c Linux-2.6.12-rc2 |
18 |
|
1da177e4c Linux-2.6.12-rc2 |
19 20 |
static int major = CONFIG_SND_MAJOR; int snd_major; |
c0d3fb39e [ALSA] Clean up E... |
21 |
EXPORT_SYMBOL(snd_major); |
1da177e4c Linux-2.6.12-rc2 |
22 |
static int cards_limit = 1; |
1da177e4c Linux-2.6.12-rc2 |
23 |
|
c1017a4cd [ALSA] Changed Ja... |
24 |
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
1da177e4c Linux-2.6.12-rc2 |
25 26 27 28 29 30 |
MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); MODULE_LICENSE("GPL"); module_param(major, int, 0444); MODULE_PARM_DESC(major, "Major # for sound driver."); module_param(cards_limit, int, 0444); MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards."); |
1da177e4c Linux-2.6.12-rc2 |
31 32 33 34 35 36 37 |
MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); /* this one holds the actual max. card number currently available. * as default, it's identical with cards_limit option. when more * modules are loaded manually, this limit number increases, too. */ int snd_ecards_limit; |
c0d3fb39e [ALSA] Clean up E... |
38 |
EXPORT_SYMBOL(snd_ecards_limit); |
1da177e4c Linux-2.6.12-rc2 |
39 |
|
6983b7240 [ALSA] dynamic mi... |
40 |
static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; |
1a60d4c5a [ALSA] semaphore ... |
41 |
static DEFINE_MUTEX(sound_mutex); |
1da177e4c Linux-2.6.12-rc2 |
42 |
|
ee2da9978 ALSA: remove CONF... |
43 |
#ifdef CONFIG_MODULES |
1da177e4c Linux-2.6.12-rc2 |
44 45 46 47 48 49 |
/** * snd_request_card - try to load the card module * @card: the card number * * Tries to load the module "snd-card-X" for the given card number |
ee2da9978 ALSA: remove CONF... |
50 |
* via request_module. Returns immediately if already loaded. |
1da177e4c Linux-2.6.12-rc2 |
51 52 53 |
*/ void snd_request_card(int card) { |
746df9489 [ALSA] Fix rwlock... |
54 |
if (snd_card_locked(card)) |
1da177e4c Linux-2.6.12-rc2 |
55 56 57 58 59 |
return; if (card < 0 || card >= cards_limit) return; request_module("snd-card-%i", card); } |
c0d3fb39e [ALSA] Clean up E... |
60 |
EXPORT_SYMBOL(snd_request_card); |
1da177e4c Linux-2.6.12-rc2 |
61 62 63 |
static void snd_request_other(int minor) { char *str; |
1da177e4c Linux-2.6.12-rc2 |
64 65 66 67 68 69 70 |
switch (minor) { case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break; case SNDRV_MINOR_TIMER: str = "snd-timer"; break; default: return; } request_module(str); } |
ee2da9978 ALSA: remove CONF... |
71 |
#endif /* modular kernel */ |
1da177e4c Linux-2.6.12-rc2 |
72 |
|
f87135f56 [ALSA] dynamic mi... |
73 74 75 76 77 78 79 |
/** * snd_lookup_minor_data - get user data of a registered device * @minor: the minor number * @type: device type (SNDRV_DEVICE_TYPE_XXX) * * Checks that a minor device with the specified type is registered, and returns * its user data pointer. |
a0830dbd4 ALSA: Add a refer... |
80 81 82 83 |
* * This function increments the reference counter of the card instance * if an associated instance with the given minor number and type is found. * The caller must call snd_card_unref() appropriately later. |
eb7c06e8e ALSA: add/change ... |
84 85 86 |
* * Return: The user data pointer if the specified device is found. %NULL * otherwise. |
f87135f56 [ALSA] dynamic mi... |
87 88 89 90 91 |
*/ void *snd_lookup_minor_data(unsigned int minor, int type) { struct snd_minor *mreg; void *private_data; |
3a63e4442 [ALSA] sound/core... |
92 |
if (minor >= ARRAY_SIZE(snd_minors)) |
f87135f56 [ALSA] dynamic mi... |
93 |
return NULL; |
1a60d4c5a [ALSA] semaphore ... |
94 |
mutex_lock(&sound_mutex); |
f87135f56 [ALSA] dynamic mi... |
95 |
mreg = snd_minors[minor]; |
a0830dbd4 ALSA: Add a refer... |
96 |
if (mreg && mreg->type == type) { |
f87135f56 [ALSA] dynamic mi... |
97 |
private_data = mreg->private_data; |
8bb4d9ce0 ALSA: Fix card re... |
98 |
if (private_data && mreg->card_ptr) |
f24640648 ALSA: Use standar... |
99 |
get_device(&mreg->card_ptr->card_dev); |
a0830dbd4 ALSA: Add a refer... |
100 |
} else |
f87135f56 [ALSA] dynamic mi... |
101 |
private_data = NULL; |
1a60d4c5a [ALSA] semaphore ... |
102 |
mutex_unlock(&sound_mutex); |
f87135f56 [ALSA] dynamic mi... |
103 104 |
return private_data; } |
c0d3fb39e [ALSA] Clean up E... |
105 |
EXPORT_SYMBOL(snd_lookup_minor_data); |
4cf19b848 ALSA: Remove BKL ... |
106 107 108 109 110 111 112 113 114 |
#ifdef CONFIG_MODULES static struct snd_minor *autoload_device(unsigned int minor) { int dev; mutex_unlock(&sound_mutex); /* release lock temporarily */ dev = SNDRV_MINOR_DEVICE(minor); if (dev == SNDRV_MINOR_CONTROL) { /* /dev/aloadC? */ int card = SNDRV_MINOR_CARD(minor); |
f4fa96895 ALSA: core: Don't... |
115 116 |
struct snd_card *ref = snd_card_ref(card); if (!ref) |
4cf19b848 ALSA: Remove BKL ... |
117 |
snd_request_card(card); |
f4fa96895 ALSA: core: Don't... |
118 119 |
else snd_card_unref(ref); |
4cf19b848 ALSA: Remove BKL ... |
120 121 122 123 124 125 126 127 128 129 130 131 |
} else if (dev == SNDRV_MINOR_GLOBAL) { /* /dev/aloadSEQ */ snd_request_other(minor); } mutex_lock(&sound_mutex); /* reacuire lock */ return snd_minors[minor]; } #else /* !CONFIG_MODULES */ #define autoload_device(minor) NULL #endif /* CONFIG_MODULES */ static int snd_open(struct inode *inode, struct file *file) |
1da177e4c Linux-2.6.12-rc2 |
132 |
{ |
332682b1c [ALSA] dynamic mi... |
133 |
unsigned int minor = iminor(inode); |
512bbd6a8 [ALSA] Remove xxx... |
134 |
struct snd_minor *mptr = NULL; |
e84f9e57b consolidate the r... |
135 |
const struct file_operations *new_fops; |
1da177e4c Linux-2.6.12-rc2 |
136 |
int err = 0; |
3a63e4442 [ALSA] sound/core... |
137 |
if (minor >= ARRAY_SIZE(snd_minors)) |
332682b1c [ALSA] dynamic mi... |
138 |
return -ENODEV; |
4cf19b848 ALSA: Remove BKL ... |
139 |
mutex_lock(&sound_mutex); |
332682b1c [ALSA] dynamic mi... |
140 141 |
mptr = snd_minors[minor]; if (mptr == NULL) { |
4cf19b848 ALSA: Remove BKL ... |
142 143 144 |
mptr = autoload_device(minor); if (!mptr) { mutex_unlock(&sound_mutex); |
332682b1c [ALSA] dynamic mi... |
145 |
return -ENODEV; |
4cf19b848 ALSA: Remove BKL ... |
146 |
} |
1da177e4c Linux-2.6.12-rc2 |
147 |
} |
e84f9e57b consolidate the r... |
148 |
new_fops = fops_get(mptr->f_ops); |
4cf19b848 ALSA: Remove BKL ... |
149 |
mutex_unlock(&sound_mutex); |
e84f9e57b consolidate the r... |
150 151 152 |
if (!new_fops) return -ENODEV; replace_fops(file, new_fops); |
4cf19b848 ALSA: Remove BKL ... |
153 |
|
e84f9e57b consolidate the r... |
154 |
if (file->f_op->open) |
1da177e4c Linux-2.6.12-rc2 |
155 |
err = file->f_op->open(inode, file); |
1da177e4c Linux-2.6.12-rc2 |
156 157 |
return err; } |
9c2e08c59 [PATCH] mark stru... |
158 |
static const struct file_operations snd_fops = |
1da177e4c Linux-2.6.12-rc2 |
159 160 |
{ .owner = THIS_MODULE, |
6038f373a llseek: automatic... |
161 162 |
.open = snd_open, .llseek = noop_llseek, |
1da177e4c Linux-2.6.12-rc2 |
163 |
}; |
332682b1c [ALSA] dynamic mi... |
164 |
#ifdef CONFIG_SND_DYNAMIC_MINORS |
38ebb7034 ALSA: Consolidate... |
165 |
static int snd_find_free_minor(int type, struct snd_card *card, int dev) |
332682b1c [ALSA] dynamic mi... |
166 167 |
{ int minor; |
03cfe6f57 ALSA: support mod... |
168 169 170 171 172 |
/* static minors for module auto loading */ if (type == SNDRV_DEVICE_TYPE_SEQUENCER) return SNDRV_MINOR_SEQUENCER; if (type == SNDRV_DEVICE_TYPE_TIMER) return SNDRV_MINOR_TIMER; |
332682b1c [ALSA] dynamic mi... |
173 |
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { |
03cfe6f57 ALSA: support mod... |
174 175 176 177 178 |
/* skip static minors still used for module auto loading */ if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL) continue; if (minor == SNDRV_MINOR_SEQUENCER || minor == SNDRV_MINOR_TIMER) |
332682b1c [ALSA] dynamic mi... |
179 180 181 182 183 184 185 |
continue; if (!snd_minors[minor]) return minor; } return -EBUSY; } #else |
38ebb7034 ALSA: Consolidate... |
186 |
static int snd_find_free_minor(int type, struct snd_card *card, int dev) |
1da177e4c Linux-2.6.12-rc2 |
187 188 189 190 191 192 193 194 195 |
{ int minor; switch (type) { case SNDRV_DEVICE_TYPE_SEQUENCER: case SNDRV_DEVICE_TYPE_TIMER: minor = type; break; case SNDRV_DEVICE_TYPE_CONTROL: |
7eaa943c8 ALSA: Kill snd_as... |
196 197 |
if (snd_BUG_ON(!card)) return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
198 199 200 201 202 203 |
minor = SNDRV_MINOR(card->number, type); break; case SNDRV_DEVICE_TYPE_HWDEP: case SNDRV_DEVICE_TYPE_RAWMIDI: case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: case SNDRV_DEVICE_TYPE_PCM_CAPTURE: |
3eafc959b ALSA: core: add s... |
204 |
case SNDRV_DEVICE_TYPE_COMPRESS: |
7eaa943c8 ALSA: Kill snd_as... |
205 206 |
if (snd_BUG_ON(!card)) return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
207 208 209 210 211 |
minor = SNDRV_MINOR(card->number, type + dev); break; default: return -EINVAL; } |
7eaa943c8 ALSA: Kill snd_as... |
212 213 |
if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS)) return -EINVAL; |
38ebb7034 ALSA: Consolidate... |
214 215 |
if (snd_minors[minor]) return -EBUSY; |
1da177e4c Linux-2.6.12-rc2 |
216 217 |
return minor; } |
332682b1c [ALSA] dynamic mi... |
218 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
219 220 |
/** |
40a4b2638 ALSA: Simplify sn... |
221 |
* snd_register_device - Register the ALSA device file for the card |
1da177e4c Linux-2.6.12-rc2 |
222 223 224 |
* @type: the device type, SNDRV_DEVICE_TYPE_XXX * @card: the card instance * @dev: the device index |
2af677fc8 [ALSA] dynamic mi... |
225 |
* @f_ops: the file operations |
f87135f56 [ALSA] dynamic mi... |
226 |
* @private_data: user pointer for f_ops->open() |
40a4b2638 ALSA: Simplify sn... |
227 |
* @device: the device to register |
1da177e4c Linux-2.6.12-rc2 |
228 229 230 231 |
* * Registers an ALSA device file for the given card. * The operators have to be set in reg parameter. * |
eb7c06e8e ALSA: add/change ... |
232 |
* Return: Zero if successful, or a negative error code on failure. |
1da177e4c Linux-2.6.12-rc2 |
233 |
*/ |
40a4b2638 ALSA: Simplify sn... |
234 235 236 |
int snd_register_device(int type, struct snd_card *card, int dev, const struct file_operations *f_ops, void *private_data, struct device *device) |
1da177e4c Linux-2.6.12-rc2 |
237 |
{ |
332682b1c [ALSA] dynamic mi... |
238 |
int minor; |
92b7952da ALSA: Allow to pa... |
239 |
int err = 0; |
512bbd6a8 [ALSA] Remove xxx... |
240 |
struct snd_minor *preg; |
1da177e4c Linux-2.6.12-rc2 |
241 |
|
40a4b2638 ALSA: Simplify sn... |
242 243 |
if (snd_BUG_ON(!device)) return -EINVAL; |
562b590d4 [ALSA] remove unu... |
244 |
preg = kmalloc(sizeof *preg, GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
245 246 |
if (preg == NULL) return -ENOMEM; |
2af677fc8 [ALSA] dynamic mi... |
247 |
preg->type = type; |
6983b7240 [ALSA] dynamic mi... |
248 |
preg->card = card ? card->number : -1; |
1da177e4c Linux-2.6.12-rc2 |
249 |
preg->device = dev; |
2af677fc8 [ALSA] dynamic mi... |
250 |
preg->f_ops = f_ops; |
f87135f56 [ALSA] dynamic mi... |
251 |
preg->private_data = private_data; |
a0830dbd4 ALSA: Add a refer... |
252 |
preg->card_ptr = card; |
1a60d4c5a [ALSA] semaphore ... |
253 |
mutex_lock(&sound_mutex); |
38ebb7034 ALSA: Consolidate... |
254 |
minor = snd_find_free_minor(type, card, dev); |
332682b1c [ALSA] dynamic mi... |
255 |
if (minor < 0) { |
92b7952da ALSA: Allow to pa... |
256 257 |
err = minor; goto error; |
1da177e4c Linux-2.6.12-rc2 |
258 |
} |
92b7952da ALSA: Allow to pa... |
259 |
|
40a4b2638 ALSA: Simplify sn... |
260 261 262 |
preg->dev = device; device->devt = MKDEV(major, minor); err = device_add(device); |
92b7952da ALSA: Allow to pa... |
263 264 |
if (err < 0) goto error; |
2469049e7 [ALSA] sound: snd... |
265 |
|
92b7952da ALSA: Allow to pa... |
266 267 |
snd_minors[minor] = preg; error: |
1a60d4c5a [ALSA] semaphore ... |
268 |
mutex_unlock(&sound_mutex); |
92b7952da ALSA: Allow to pa... |
269 270 271 |
if (err < 0) kfree(preg); return err; |
1da177e4c Linux-2.6.12-rc2 |
272 |
} |
40a4b2638 ALSA: Simplify sn... |
273 |
EXPORT_SYMBOL(snd_register_device); |
c0d3fb39e [ALSA] Clean up E... |
274 |
|
1da177e4c Linux-2.6.12-rc2 |
275 276 |
/** * snd_unregister_device - unregister the device on the given card |
40a4b2638 ALSA: Simplify sn... |
277 |
* @dev: the device instance |
1da177e4c Linux-2.6.12-rc2 |
278 279 280 281 |
* * Unregisters the device file already registered via * snd_register_device(). * |
eb7c06e8e ALSA: add/change ... |
282 |
* Return: Zero if successful, or a negative error code on failure. |
1da177e4c Linux-2.6.12-rc2 |
283 |
*/ |
40a4b2638 ALSA: Simplify sn... |
284 |
int snd_unregister_device(struct device *dev) |
1da177e4c Linux-2.6.12-rc2 |
285 |
{ |
9d19f48cf [ALSA] Add pcm_cl... |
286 |
int minor; |
92b7952da ALSA: Allow to pa... |
287 |
struct snd_minor *preg; |
1da177e4c Linux-2.6.12-rc2 |
288 |
|
1a60d4c5a [ALSA] semaphore ... |
289 |
mutex_lock(&sound_mutex); |
40a4b2638 ALSA: Simplify sn... |
290 291 292 293 294 295 296 297 |
for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { preg = snd_minors[minor]; if (preg && preg->dev == dev) { snd_minors[minor] = NULL; device_del(dev); kfree(preg); break; } |
1da177e4c Linux-2.6.12-rc2 |
298 |
} |
1a60d4c5a [ALSA] semaphore ... |
299 |
mutex_unlock(&sound_mutex); |
40a4b2638 ALSA: Simplify sn... |
300 301 |
if (minor >= ARRAY_SIZE(snd_minors)) return -ENOENT; |
1da177e4c Linux-2.6.12-rc2 |
302 303 |
return 0; } |
c0d3fb39e [ALSA] Clean up E... |
304 |
EXPORT_SYMBOL(snd_unregister_device); |
cd6a65036 ALSA: replace CON... |
305 |
#ifdef CONFIG_SND_PROC_FS |
1da177e4c Linux-2.6.12-rc2 |
306 307 308 |
/* * INFO PART */ |
2af677fc8 [ALSA] dynamic mi... |
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
static const char *snd_device_type_name(int type) { switch (type) { case SNDRV_DEVICE_TYPE_CONTROL: return "control"; case SNDRV_DEVICE_TYPE_HWDEP: return "hardware dependent"; case SNDRV_DEVICE_TYPE_RAWMIDI: return "raw midi"; case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: return "digital audio playback"; case SNDRV_DEVICE_TYPE_PCM_CAPTURE: return "digital audio capture"; case SNDRV_DEVICE_TYPE_SEQUENCER: return "sequencer"; case SNDRV_DEVICE_TYPE_TIMER: return "timer"; default: return "?"; } } |
512bbd6a8 [ALSA] Remove xxx... |
330 |
static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) |
1da177e4c Linux-2.6.12-rc2 |
331 |
{ |
6983b7240 [ALSA] dynamic mi... |
332 |
int minor; |
512bbd6a8 [ALSA] Remove xxx... |
333 |
struct snd_minor *mptr; |
1da177e4c Linux-2.6.12-rc2 |
334 |
|
1a60d4c5a [ALSA] semaphore ... |
335 |
mutex_lock(&sound_mutex); |
6983b7240 [ALSA] dynamic mi... |
336 337 338 339 340 |
for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) { if (!(mptr = snd_minors[minor])) continue; if (mptr->card >= 0) { if (mptr->device >= 0) |
d001544de [ALSA] dynamic mi... |
341 342 |
snd_iprintf(buffer, "%3i: [%2i-%2i]: %s ", |
6983b7240 [ALSA] dynamic mi... |
343 344 345 |
minor, mptr->card, mptr->device, snd_device_type_name(mptr->type)); else |
d001544de [ALSA] dynamic mi... |
346 347 |
snd_iprintf(buffer, "%3i: [%2i] : %s ", |
6983b7240 [ALSA] dynamic mi... |
348 349 350 |
minor, mptr->card, snd_device_type_name(mptr->type)); } else |
d001544de [ALSA] dynamic mi... |
351 352 |
snd_iprintf(buffer, "%3i: : %s ", minor, |
6983b7240 [ALSA] dynamic mi... |
353 |
snd_device_type_name(mptr->type)); |
1da177e4c Linux-2.6.12-rc2 |
354 |
} |
1a60d4c5a [ALSA] semaphore ... |
355 |
mutex_unlock(&sound_mutex); |
1da177e4c Linux-2.6.12-rc2 |
356 357 358 359 |
} int __init snd_minor_info_init(void) { |
512bbd6a8 [ALSA] Remove xxx... |
360 |
struct snd_info_entry *entry; |
1da177e4c Linux-2.6.12-rc2 |
361 362 |
entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); |
b591b6e9e ALSA: core: Don't... |
363 364 365 366 |
if (!entry) return -ENOMEM; entry->c.text.read = snd_minor_info_read; return snd_info_register(entry); /* freed in error path */ |
1da177e4c Linux-2.6.12-rc2 |
367 |
} |
cd6a65036 ALSA: replace CON... |
368 |
#endif /* CONFIG_SND_PROC_FS */ |
1da177e4c Linux-2.6.12-rc2 |
369 370 371 372 373 374 375 |
/* * INIT PART */ static int __init alsa_sound_init(void) { |
1da177e4c Linux-2.6.12-rc2 |
376 377 |
snd_major = major; snd_ecards_limit = cards_limit; |
1da177e4c Linux-2.6.12-rc2 |
378 |
if (register_chrdev(major, "alsa", &snd_fops)) { |
f2f9307a4 ALSA: core: Use s... |
379 380 |
pr_err("ALSA core: unable to register native major device number %d ", major); |
1da177e4c Linux-2.6.12-rc2 |
381 382 |
return -EIO; } |
1da177e4c Linux-2.6.12-rc2 |
383 |
if (snd_info_init() < 0) { |
1da177e4c Linux-2.6.12-rc2 |
384 |
unregister_chrdev(major, "alsa"); |
1da177e4c Linux-2.6.12-rc2 |
385 386 |
return -ENOMEM; } |
1da177e4c Linux-2.6.12-rc2 |
387 |
#ifndef MODULE |
f2f9307a4 ALSA: core: Use s... |
388 389 |
pr_info("Advanced Linux Sound Architecture Driver Initialized. "); |
1da177e4c Linux-2.6.12-rc2 |
390 391 392 393 394 395 |
#endif return 0; } static void __exit alsa_sound_exit(void) { |
1da177e4c Linux-2.6.12-rc2 |
396 |
snd_info_done(); |
68fc4fabc unregister_chrdev... |
397 |
unregister_chrdev(major, "alsa"); |
1da177e4c Linux-2.6.12-rc2 |
398 |
} |
c181a13a4 ALSA: use subsys_... |
399 400 |
subsys_initcall(alsa_sound_init); module_exit(alsa_sound_exit); |