Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pci/aw2/aw2-alsa.c
29269 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*****************************************************************************
3
*
4
* Copyright (C) 2008 Cedric Bregardis <[email protected]> and
5
* Jean-Christian Hassler <[email protected]>
6
*
7
* This file is part of the Audiowerk2 ALSA driver
8
*
9
*****************************************************************************/
10
#include <linux/init.h>
11
#include <linux/pci.h>
12
#include <linux/dma-mapping.h>
13
#include <linux/slab.h>
14
#include <linux/interrupt.h>
15
#include <linux/delay.h>
16
#include <linux/io.h>
17
#include <linux/module.h>
18
#include <sound/core.h>
19
#include <sound/initval.h>
20
#include <sound/pcm.h>
21
#include <sound/pcm_params.h>
22
#include <sound/control.h>
23
24
#include "saa7146.h"
25
#include "aw2-saa7146.h"
26
27
MODULE_AUTHOR("Cedric Bregardis <[email protected]>, "
28
"Jean-Christian Hassler <[email protected]>");
29
MODULE_DESCRIPTION("Emagic Audiowerk 2 sound driver");
30
MODULE_LICENSE("GPL");
31
32
/*********************************
33
* DEFINES
34
********************************/
35
#define CTL_ROUTE_ANALOG 0
36
#define CTL_ROUTE_DIGITAL 1
37
38
/*********************************
39
* TYPEDEFS
40
********************************/
41
/* hardware definition */
42
static const struct snd_pcm_hardware snd_aw2_playback_hw = {
43
.info = (SNDRV_PCM_INFO_MMAP |
44
SNDRV_PCM_INFO_INTERLEAVED |
45
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
46
.formats = SNDRV_PCM_FMTBIT_S16_LE,
47
.rates = SNDRV_PCM_RATE_44100,
48
.rate_min = 44100,
49
.rate_max = 44100,
50
.channels_min = 2,
51
.channels_max = 4,
52
.buffer_bytes_max = 32768,
53
.period_bytes_min = 4096,
54
.period_bytes_max = 32768,
55
.periods_min = 1,
56
.periods_max = 1024,
57
};
58
59
static const struct snd_pcm_hardware snd_aw2_capture_hw = {
60
.info = (SNDRV_PCM_INFO_MMAP |
61
SNDRV_PCM_INFO_INTERLEAVED |
62
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
63
.formats = SNDRV_PCM_FMTBIT_S16_LE,
64
.rates = SNDRV_PCM_RATE_44100,
65
.rate_min = 44100,
66
.rate_max = 44100,
67
.channels_min = 2,
68
.channels_max = 2,
69
.buffer_bytes_max = 32768,
70
.period_bytes_min = 4096,
71
.period_bytes_max = 32768,
72
.periods_min = 1,
73
.periods_max = 1024,
74
};
75
76
struct aw2_pcm_device {
77
struct snd_pcm *pcm;
78
unsigned int stream_number;
79
struct aw2 *chip;
80
};
81
82
struct aw2 {
83
struct snd_aw2_saa7146 saa7146;
84
85
struct pci_dev *pci;
86
int irq;
87
spinlock_t reg_lock;
88
struct mutex mtx;
89
90
unsigned long iobase_phys;
91
void __iomem *iobase_virt;
92
93
struct snd_card *card;
94
95
struct aw2_pcm_device device_playback[NB_STREAM_PLAYBACK];
96
struct aw2_pcm_device device_capture[NB_STREAM_CAPTURE];
97
};
98
99
/*********************************
100
* FUNCTION DECLARATIONS
101
********************************/
102
static int snd_aw2_create(struct snd_card *card, struct pci_dev *pci);
103
static int snd_aw2_probe(struct pci_dev *pci,
104
const struct pci_device_id *pci_id);
105
static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream);
106
static int snd_aw2_pcm_playback_close(struct snd_pcm_substream *substream);
107
static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream);
108
static int snd_aw2_pcm_capture_close(struct snd_pcm_substream *substream);
109
static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream);
110
static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream);
111
static int snd_aw2_pcm_trigger_playback(struct snd_pcm_substream *substream,
112
int cmd);
113
static int snd_aw2_pcm_trigger_capture(struct snd_pcm_substream *substream,
114
int cmd);
115
static snd_pcm_uframes_t snd_aw2_pcm_pointer_playback(struct snd_pcm_substream
116
*substream);
117
static snd_pcm_uframes_t snd_aw2_pcm_pointer_capture(struct snd_pcm_substream
118
*substream);
119
static int snd_aw2_new_pcm(struct aw2 *chip);
120
121
static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol,
122
struct snd_ctl_elem_info *uinfo);
123
static int snd_aw2_control_switch_capture_get(struct snd_kcontrol *kcontrol,
124
struct snd_ctl_elem_value
125
*ucontrol);
126
static int snd_aw2_control_switch_capture_put(struct snd_kcontrol *kcontrol,
127
struct snd_ctl_elem_value
128
*ucontrol);
129
130
/*********************************
131
* VARIABLES
132
********************************/
133
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
134
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
135
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
136
137
module_param_array(index, int, NULL, 0444);
138
MODULE_PARM_DESC(index, "Index value for Audiowerk2 soundcard.");
139
module_param_array(id, charp, NULL, 0444);
140
MODULE_PARM_DESC(id, "ID string for the Audiowerk2 soundcard.");
141
module_param_array(enable, bool, NULL, 0444);
142
MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
143
144
static const struct pci_device_id snd_aw2_ids[] = {
145
{PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0, 0,
146
0, 0, 0},
147
{0}
148
};
149
150
MODULE_DEVICE_TABLE(pci, snd_aw2_ids);
151
152
/* pci_driver definition */
153
static struct pci_driver aw2_driver = {
154
.name = KBUILD_MODNAME,
155
.id_table = snd_aw2_ids,
156
.probe = snd_aw2_probe,
157
};
158
159
module_pci_driver(aw2_driver);
160
161
/* operators for playback PCM alsa interface */
162
static const struct snd_pcm_ops snd_aw2_playback_ops = {
163
.open = snd_aw2_pcm_playback_open,
164
.close = snd_aw2_pcm_playback_close,
165
.prepare = snd_aw2_pcm_prepare_playback,
166
.trigger = snd_aw2_pcm_trigger_playback,
167
.pointer = snd_aw2_pcm_pointer_playback,
168
};
169
170
/* operators for capture PCM alsa interface */
171
static const struct snd_pcm_ops snd_aw2_capture_ops = {
172
.open = snd_aw2_pcm_capture_open,
173
.close = snd_aw2_pcm_capture_close,
174
.prepare = snd_aw2_pcm_prepare_capture,
175
.trigger = snd_aw2_pcm_trigger_capture,
176
.pointer = snd_aw2_pcm_pointer_capture,
177
};
178
179
static const struct snd_kcontrol_new aw2_control = {
180
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
181
.name = "PCM Capture Route",
182
.index = 0,
183
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
184
.private_value = 0xffff,
185
.info = snd_aw2_control_switch_capture_info,
186
.get = snd_aw2_control_switch_capture_get,
187
.put = snd_aw2_control_switch_capture_put
188
};
189
190
/*********************************
191
* FUNCTION IMPLEMENTATIONS
192
********************************/
193
194
/* component-destructor */
195
static void snd_aw2_free(struct snd_card *card)
196
{
197
struct aw2 *chip = card->private_data;
198
199
/* Free hardware */
200
snd_aw2_saa7146_free(&chip->saa7146);
201
}
202
203
/* chip-specific constructor */
204
static int snd_aw2_create(struct snd_card *card,
205
struct pci_dev *pci)
206
{
207
struct aw2 *chip = card->private_data;
208
int err;
209
210
/* initialize the PCI entry */
211
err = pcim_enable_device(pci);
212
if (err < 0)
213
return err;
214
pci_set_master(pci);
215
216
/* check PCI availability (32bit DMA) */
217
if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32))) {
218
dev_err(card->dev, "Impossible to set 32bit mask DMA\n");
219
return -ENXIO;
220
}
221
222
/* initialize the stuff */
223
chip->card = card;
224
chip->pci = pci;
225
chip->irq = -1;
226
227
/* (1) PCI resource allocation */
228
chip->iobase_virt = pcim_iomap_region(pci, 0, "Audiowerk2");
229
if (IS_ERR(chip->iobase_virt))
230
return PTR_ERR(chip->iobase_virt);
231
chip->iobase_phys = pci_resource_start(pci, 0);
232
233
/* (2) initialization of the chip hardware */
234
snd_aw2_saa7146_setup(&chip->saa7146, chip->iobase_virt);
235
236
if (devm_request_irq(&pci->dev, pci->irq, snd_aw2_saa7146_interrupt,
237
IRQF_SHARED, KBUILD_MODNAME, chip)) {
238
dev_err(card->dev, "Cannot grab irq %d\n", pci->irq);
239
return -EBUSY;
240
}
241
chip->irq = pci->irq;
242
card->sync_irq = chip->irq;
243
card->private_free = snd_aw2_free;
244
245
dev_info(card->dev,
246
"Audiowerk 2 sound card (saa7146 chipset) detected and managed\n");
247
return 0;
248
}
249
250
/* constructor */
251
static int snd_aw2_probe(struct pci_dev *pci,
252
const struct pci_device_id *pci_id)
253
{
254
static int dev;
255
struct snd_card *card;
256
struct aw2 *chip;
257
int err;
258
259
/* (1) Continue if device is not enabled, else inc dev */
260
if (dev >= SNDRV_CARDS)
261
return -ENODEV;
262
if (!enable[dev]) {
263
dev++;
264
return -ENOENT;
265
}
266
267
/* (2) Create card instance */
268
err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
269
sizeof(*chip), &card);
270
if (err < 0)
271
return err;
272
chip = card->private_data;
273
274
/* (3) Create main component */
275
err = snd_aw2_create(card, pci);
276
if (err < 0)
277
goto error;
278
279
/* initialize mutex */
280
mutex_init(&chip->mtx);
281
/* init spinlock */
282
spin_lock_init(&chip->reg_lock);
283
/* (4) Define driver ID and name string */
284
strscpy(card->driver, "aw2");
285
strscpy(card->shortname, "Audiowerk2");
286
287
sprintf(card->longname, "%s with SAA7146 irq %i",
288
card->shortname, chip->irq);
289
290
/* (5) Create other components */
291
snd_aw2_new_pcm(chip);
292
293
/* (6) Register card instance */
294
err = snd_card_register(card);
295
if (err < 0)
296
goto error;
297
298
/* (7) Set PCI driver data */
299
pci_set_drvdata(pci, card);
300
301
dev++;
302
return 0;
303
304
error:
305
snd_card_free(card);
306
return err;
307
}
308
309
/* open callback */
310
static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream)
311
{
312
struct snd_pcm_runtime *runtime = substream->runtime;
313
314
dev_dbg(substream->pcm->card->dev, "Playback_open\n");
315
runtime->hw = snd_aw2_playback_hw;
316
return 0;
317
}
318
319
/* close callback */
320
static int snd_aw2_pcm_playback_close(struct snd_pcm_substream *substream)
321
{
322
return 0;
323
324
}
325
326
static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream)
327
{
328
struct snd_pcm_runtime *runtime = substream->runtime;
329
330
dev_dbg(substream->pcm->card->dev, "Capture_open\n");
331
runtime->hw = snd_aw2_capture_hw;
332
return 0;
333
}
334
335
/* close callback */
336
static int snd_aw2_pcm_capture_close(struct snd_pcm_substream *substream)
337
{
338
/* TODO: something to do ? */
339
return 0;
340
}
341
342
/* prepare callback for playback */
343
static int snd_aw2_pcm_prepare_playback(struct snd_pcm_substream *substream)
344
{
345
struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
346
struct aw2 *chip = pcm_device->chip;
347
struct snd_pcm_runtime *runtime = substream->runtime;
348
unsigned long period_size, buffer_size;
349
350
guard(mutex)(&chip->mtx);
351
352
period_size = snd_pcm_lib_period_bytes(substream);
353
buffer_size = snd_pcm_lib_buffer_bytes(substream);
354
355
snd_aw2_saa7146_pcm_init_playback(&chip->saa7146,
356
pcm_device->stream_number,
357
runtime->dma_addr, period_size,
358
buffer_size);
359
360
/* Define Interrupt callback */
361
snd_aw2_saa7146_define_it_playback_callback(pcm_device->stream_number,
362
(snd_aw2_saa7146_it_cb)
363
snd_pcm_period_elapsed,
364
(void *)substream);
365
366
return 0;
367
}
368
369
/* prepare callback for capture */
370
static int snd_aw2_pcm_prepare_capture(struct snd_pcm_substream *substream)
371
{
372
struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
373
struct aw2 *chip = pcm_device->chip;
374
struct snd_pcm_runtime *runtime = substream->runtime;
375
unsigned long period_size, buffer_size;
376
377
guard(mutex)(&chip->mtx);
378
379
period_size = snd_pcm_lib_period_bytes(substream);
380
buffer_size = snd_pcm_lib_buffer_bytes(substream);
381
382
snd_aw2_saa7146_pcm_init_capture(&chip->saa7146,
383
pcm_device->stream_number,
384
runtime->dma_addr, period_size,
385
buffer_size);
386
387
/* Define Interrupt callback */
388
snd_aw2_saa7146_define_it_capture_callback(pcm_device->stream_number,
389
(snd_aw2_saa7146_it_cb)
390
snd_pcm_period_elapsed,
391
(void *)substream);
392
393
return 0;
394
}
395
396
/* playback trigger callback */
397
static int snd_aw2_pcm_trigger_playback(struct snd_pcm_substream *substream,
398
int cmd)
399
{
400
struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
401
struct aw2 *chip = pcm_device->chip;
402
403
guard(spinlock)(&chip->reg_lock);
404
switch (cmd) {
405
case SNDRV_PCM_TRIGGER_START:
406
snd_aw2_saa7146_pcm_trigger_start_playback(&chip->saa7146,
407
pcm_device->
408
stream_number);
409
break;
410
case SNDRV_PCM_TRIGGER_STOP:
411
snd_aw2_saa7146_pcm_trigger_stop_playback(&chip->saa7146,
412
pcm_device->
413
stream_number);
414
break;
415
default:
416
return -EINVAL;
417
}
418
return 0;
419
}
420
421
/* capture trigger callback */
422
static int snd_aw2_pcm_trigger_capture(struct snd_pcm_substream *substream,
423
int cmd)
424
{
425
struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
426
struct aw2 *chip = pcm_device->chip;
427
428
guard(spinlock)(&chip->reg_lock);
429
switch (cmd) {
430
case SNDRV_PCM_TRIGGER_START:
431
snd_aw2_saa7146_pcm_trigger_start_capture(&chip->saa7146,
432
pcm_device->
433
stream_number);
434
break;
435
case SNDRV_PCM_TRIGGER_STOP:
436
snd_aw2_saa7146_pcm_trigger_stop_capture(&chip->saa7146,
437
pcm_device->
438
stream_number);
439
break;
440
default:
441
return -EINVAL;
442
}
443
return 0;
444
}
445
446
/* playback pointer callback */
447
static snd_pcm_uframes_t snd_aw2_pcm_pointer_playback(struct snd_pcm_substream
448
*substream)
449
{
450
struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
451
struct aw2 *chip = pcm_device->chip;
452
unsigned int current_ptr;
453
454
/* get the current hardware pointer */
455
struct snd_pcm_runtime *runtime = substream->runtime;
456
current_ptr =
457
snd_aw2_saa7146_get_hw_ptr_playback(&chip->saa7146,
458
pcm_device->stream_number,
459
runtime->dma_area,
460
runtime->buffer_size);
461
462
return bytes_to_frames(substream->runtime, current_ptr);
463
}
464
465
/* capture pointer callback */
466
static snd_pcm_uframes_t snd_aw2_pcm_pointer_capture(struct snd_pcm_substream
467
*substream)
468
{
469
struct aw2_pcm_device *pcm_device = snd_pcm_substream_chip(substream);
470
struct aw2 *chip = pcm_device->chip;
471
unsigned int current_ptr;
472
473
/* get the current hardware pointer */
474
struct snd_pcm_runtime *runtime = substream->runtime;
475
current_ptr =
476
snd_aw2_saa7146_get_hw_ptr_capture(&chip->saa7146,
477
pcm_device->stream_number,
478
runtime->dma_area,
479
runtime->buffer_size);
480
481
return bytes_to_frames(substream->runtime, current_ptr);
482
}
483
484
/* create a pcm device */
485
static int snd_aw2_new_pcm(struct aw2 *chip)
486
{
487
struct snd_pcm *pcm_playback_ana;
488
struct snd_pcm *pcm_playback_num;
489
struct snd_pcm *pcm_capture;
490
struct aw2_pcm_device *pcm_device;
491
int err = 0;
492
493
/* Create new Alsa PCM device */
494
495
err = snd_pcm_new(chip->card, "Audiowerk2 analog playback", 0, 1, 0,
496
&pcm_playback_ana);
497
if (err < 0) {
498
dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
499
return err;
500
}
501
502
/* Creation ok */
503
pcm_device = &chip->device_playback[NUM_STREAM_PLAYBACK_ANA];
504
505
/* Set PCM device name */
506
strscpy(pcm_playback_ana->name, "Analog playback");
507
/* Associate private data to PCM device */
508
pcm_playback_ana->private_data = pcm_device;
509
/* set operators of PCM device */
510
snd_pcm_set_ops(pcm_playback_ana, SNDRV_PCM_STREAM_PLAYBACK,
511
&snd_aw2_playback_ops);
512
/* store PCM device */
513
pcm_device->pcm = pcm_playback_ana;
514
/* give base chip pointer to our internal pcm device
515
structure */
516
pcm_device->chip = chip;
517
/* Give stream number to PCM device */
518
pcm_device->stream_number = NUM_STREAM_PLAYBACK_ANA;
519
520
/* pre-allocation of buffers */
521
/* Preallocate continuous pages. */
522
snd_pcm_set_managed_buffer_all(pcm_playback_ana,
523
SNDRV_DMA_TYPE_DEV,
524
&chip->pci->dev,
525
64 * 1024, 64 * 1024);
526
527
err = snd_pcm_new(chip->card, "Audiowerk2 digital playback", 1, 1, 0,
528
&pcm_playback_num);
529
530
if (err < 0) {
531
dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
532
return err;
533
}
534
/* Creation ok */
535
pcm_device = &chip->device_playback[NUM_STREAM_PLAYBACK_DIG];
536
537
/* Set PCM device name */
538
strscpy(pcm_playback_num->name, "Digital playback");
539
/* Associate private data to PCM device */
540
pcm_playback_num->private_data = pcm_device;
541
/* set operators of PCM device */
542
snd_pcm_set_ops(pcm_playback_num, SNDRV_PCM_STREAM_PLAYBACK,
543
&snd_aw2_playback_ops);
544
/* store PCM device */
545
pcm_device->pcm = pcm_playback_num;
546
/* give base chip pointer to our internal pcm device
547
structure */
548
pcm_device->chip = chip;
549
/* Give stream number to PCM device */
550
pcm_device->stream_number = NUM_STREAM_PLAYBACK_DIG;
551
552
/* pre-allocation of buffers */
553
/* Preallocate continuous pages. */
554
snd_pcm_set_managed_buffer_all(pcm_playback_num,
555
SNDRV_DMA_TYPE_DEV,
556
&chip->pci->dev,
557
64 * 1024, 64 * 1024);
558
559
err = snd_pcm_new(chip->card, "Audiowerk2 capture", 2, 0, 1,
560
&pcm_capture);
561
562
if (err < 0) {
563
dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err);
564
return err;
565
}
566
567
/* Creation ok */
568
pcm_device = &chip->device_capture[NUM_STREAM_CAPTURE_ANA];
569
570
/* Set PCM device name */
571
strscpy(pcm_capture->name, "Capture");
572
/* Associate private data to PCM device */
573
pcm_capture->private_data = pcm_device;
574
/* set operators of PCM device */
575
snd_pcm_set_ops(pcm_capture, SNDRV_PCM_STREAM_CAPTURE,
576
&snd_aw2_capture_ops);
577
/* store PCM device */
578
pcm_device->pcm = pcm_capture;
579
/* give base chip pointer to our internal pcm device
580
structure */
581
pcm_device->chip = chip;
582
/* Give stream number to PCM device */
583
pcm_device->stream_number = NUM_STREAM_CAPTURE_ANA;
584
585
/* pre-allocation of buffers */
586
/* Preallocate continuous pages. */
587
snd_pcm_set_managed_buffer_all(pcm_capture,
588
SNDRV_DMA_TYPE_DEV,
589
&chip->pci->dev,
590
64 * 1024, 64 * 1024);
591
592
/* Create control */
593
err = snd_ctl_add(chip->card, snd_ctl_new1(&aw2_control, chip));
594
if (err < 0) {
595
dev_err(chip->card->dev, "snd_ctl_add error (0x%X)\n", err);
596
return err;
597
}
598
599
return 0;
600
}
601
602
static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol,
603
struct snd_ctl_elem_info *uinfo)
604
{
605
static const char * const texts[2] = {
606
"Analog", "Digital"
607
};
608
return snd_ctl_enum_info(uinfo, 1, 2, texts);
609
}
610
611
static int snd_aw2_control_switch_capture_get(struct snd_kcontrol *kcontrol,
612
struct snd_ctl_elem_value
613
*ucontrol)
614
{
615
struct aw2 *chip = snd_kcontrol_chip(kcontrol);
616
if (snd_aw2_saa7146_is_using_digital_input(&chip->saa7146))
617
ucontrol->value.enumerated.item[0] = CTL_ROUTE_DIGITAL;
618
else
619
ucontrol->value.enumerated.item[0] = CTL_ROUTE_ANALOG;
620
return 0;
621
}
622
623
static int snd_aw2_control_switch_capture_put(struct snd_kcontrol *kcontrol,
624
struct snd_ctl_elem_value
625
*ucontrol)
626
{
627
struct aw2 *chip = snd_kcontrol_chip(kcontrol);
628
int changed = 0;
629
int is_disgital =
630
snd_aw2_saa7146_is_using_digital_input(&chip->saa7146);
631
632
if (((ucontrol->value.integer.value[0] == CTL_ROUTE_DIGITAL)
633
&& !is_disgital)
634
|| ((ucontrol->value.integer.value[0] == CTL_ROUTE_ANALOG)
635
&& is_disgital)) {
636
snd_aw2_saa7146_use_digital_input(&chip->saa7146, !is_disgital);
637
changed = 1;
638
}
639
return changed;
640
}
641
642