blob: 147c8a951137a4452fb059a66dab5cbfbc381c7d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Crystal SoundFusion CS46xx driver
3 *
4 * Copyright 1998-2001 Cirrus Logic Corporation <pcaudio@crystal.cirrus.com>
5 * <twoller@crystal.cirrus.com>
6 * Copyright 1999-2000 Jaroslav Kysela <perex@suse.cz>
7 * Copyright 2000 Alan Cox <alan@redhat.com>
8 *
9 * The core of this code is taken from the ALSA project driver by
10 * Jaroslav. Please send Jaroslav the credit for the driver and
11 * report bugs in this port to <alan@redhat.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * Current maintainers:
27 * Cirrus Logic Corporation, Thomas Woller (tw)
28 * <twoller@crystal.cirrus.com>
29 * Nils Faerber (nf)
30 * <nils@kernelconcepts.de>
31 * Thanks to David Pollard for testing.
32 *
33 * Changes:
34 * 20000909-nf Changed cs_read, cs_write and drain_dac
35 * 20001025-tw Separate Playback/Capture structs and buffers.
36 * Added Scatter/Gather support for Playback.
37 * Added Capture.
38 * 20001027-nf Port to kernel 2.4.0-test9, some clean-ups
39 * Start of powermanagement support (CS46XX_PM).
40 * 20001128-tw Add module parm for default buffer order.
41 * added DMA_GFP flag to kmalloc dma buffer allocs.
42 * backfill silence to eliminate stuttering on
43 * underruns.
44 * 20001201-tw add resyncing of swptr on underruns.
45 * 20001205-tw-nf fixed GETOSPACE ioctl() after open()
46 * 20010113-tw patch from Hans Grobler general cleanup.
47 * 20010117-tw 2.4.0 pci cleanup, wrapper code for 2.2.16-2.4.0
48 * 20010118-tw basic PM support for 2.2.16+ and 2.4.0/2.4.2.
49 * 20010228-dh patch from David Huggins - cs_update_ptr recursion.
50 * 20010409-tw add hercules game theatre XP amp code.
51 * 20010420-tw cleanup powerdown/up code.
52 * 20010521-tw eliminate pops, and fixes for powerdown.
53 * 20010525-tw added fixes for thinkpads with powerdown logic.
54 * 20010723-sh patch from Horms (Simon Horman) -
55 * SOUND_PCM_READ_BITS returns bits as set in driver
56 * rather than a logical or of the possible values.
57 * Various ioctls handle the case where the device
58 * is open for reading or writing but not both better.
59 *
60 * Status:
61 * Playback/Capture supported from 8k-48k.
62 * 16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported.
63 *
64 * APM/PM - 2.2.x APM is enabled and functioning fine. APM can also
65 * be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro
66 * definition.
67 *
68 * Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp,
69 * so, use the drain/polarity to enable.
70 * hercules_egpio_disable set to 1, will force a 0 to EGPIODR.
71 *
72 * VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control
73 * the external amplifier for the "back" speakers, since we do not
74 * support the secondary codec then this external amp is also not
75 * turned on.
76 */
77
78#include <linux/interrupt.h>
79#include <linux/list.h>
80#include <linux/module.h>
81#include <linux/string.h>
82#include <linux/ioport.h>
83#include <linux/sched.h>
84#include <linux/delay.h>
85#include <linux/sound.h>
86#include <linux/slab.h>
87#include <linux/soundcard.h>
88#include <linux/pci.h>
89#include <linux/bitops.h>
90#include <linux/init.h>
91#include <linux/poll.h>
92#include <linux/ac97_codec.h>
Ingo Molnar910f5d22006-03-23 03:00:39 -080093#include <linux/mutex.h>
Al Virof23f6e02006-10-20 15:17:02 -040094#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96#include <asm/io.h>
97#include <asm/dma.h>
98#include <asm/uaccess.h>
99
Alexey Dobriyan99f932f2006-09-29 02:00:18 -0700100#include "cs46xxpm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101#include "cs46xx_wrapper-24.h"
102#include "cs461x.h"
103
104/* MIDI buffer sizes */
105#define CS_MIDIINBUF 500
106#define CS_MIDIOUTBUF 500
107
108#define ADC_RUNNING 1
109#define DAC_RUNNING 2
110
111#define CS_FMT_16BIT 1 /* These are fixed in fact */
112#define CS_FMT_STEREO 2
113#define CS_FMT_MASK 3
114
115#define CS_TYPE_ADC 1
116#define CS_TYPE_DAC 2
117
118#define CS_TRUE 1
119#define CS_FALSE 0
120
121#define CS_INC_USE_COUNT(m) (atomic_inc(m))
122#define CS_DEC_USE_COUNT(m) (atomic_dec(m))
123#define CS_DEC_AND_TEST(m) (atomic_dec_and_test(m))
124#define CS_IN_USE(m) (atomic_read(m) != 0)
125
126#define CS_DBGBREAKPOINT {__asm__("INT $3");}
127/*
128 * CS461x definitions
129 */
130
131#define CS461X_BA0_SIZE 0x2000
132#define CS461X_BA1_DATA0_SIZE 0x3000
133#define CS461X_BA1_DATA1_SIZE 0x3800
134#define CS461X_BA1_PRG_SIZE 0x7000
135#define CS461X_BA1_REG_SIZE 0x0100
136
137#define GOF_PER_SEC 200
138
139#define CSDEBUG_INTERFACE 1
140#define CSDEBUG 1
141/*
142 * Turn on/off debugging compilation by using 1/0 respectively for CSDEBUG
143 *
144 *
145 * CSDEBUG is usual mode is set to 1, then use the
146 * cs_debuglevel and cs_debugmask to turn on or off debugging.
147 * Debug level of 1 has been defined to be kernel errors and info
148 * that should be printed on any released driver.
149 */
150#if CSDEBUG
Jesper Juhl2eebb192006-06-23 02:05:26 -0700151#define CS_DBGOUT(mask,level,x) if ((cs_debuglevel >= (level)) && ((mask) & cs_debugmask)) {x;}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152#else
153#define CS_DBGOUT(mask,level,x)
154#endif
155/*
156 * cs_debugmask areas
157 */
158#define CS_INIT 0x00000001 /* initialization and probe functions */
159#define CS_ERROR 0x00000002 /* tmp debugging bit placeholder */
160#define CS_INTERRUPT 0x00000004 /* interrupt handler (separate from all other) */
161#define CS_FUNCTION 0x00000008 /* enter/leave functions */
162#define CS_WAVE_WRITE 0x00000010 /* write information for wave */
163#define CS_WAVE_READ 0x00000020 /* read information for wave */
164#define CS_MIDI_WRITE 0x00000040 /* write information for midi */
165#define CS_MIDI_READ 0x00000080 /* read information for midi */
166#define CS_MPU401_WRITE 0x00000100 /* write information for mpu401 */
167#define CS_MPU401_READ 0x00000200 /* read information for mpu401 */
168#define CS_OPEN 0x00000400 /* all open functions in the driver */
169#define CS_RELEASE 0x00000800 /* all release functions in the driver */
170#define CS_PARMS 0x00001000 /* functional and operational parameters */
171#define CS_IOCTL 0x00002000 /* ioctl (non-mixer) */
172#define CS_PM 0x00004000 /* PM */
173#define CS_TMP 0x10000000 /* tmp debug mask bit */
174
175#define CS_IOCTL_CMD_SUSPEND 0x1 // suspend
176#define CS_IOCTL_CMD_RESUME 0x2 // resume
177
178#if CSDEBUG
Jesper Juhl2eebb192006-06-23 02:05:26 -0700179static unsigned long cs_debuglevel = 1; /* levels range from 1-9 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180module_param(cs_debuglevel, ulong, 0644);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700181static unsigned long cs_debugmask = CS_INIT | CS_ERROR; /* use CS_DBGOUT with various mask values */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182module_param(cs_debugmask, ulong, 0644);
183#endif
184static unsigned long hercules_egpio_disable; /* if non-zero set all EGPIO to 0 */
185module_param(hercules_egpio_disable, ulong, 0);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700186static unsigned long initdelay = 700; /* PM delay in millisecs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187module_param(initdelay, ulong, 0);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700188static unsigned long powerdown = -1; /* turn on/off powerdown processing in driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189module_param(powerdown, ulong, 0);
190#define DMABUF_DEFAULTORDER 3
Jesper Juhl2eebb192006-06-23 02:05:26 -0700191static unsigned long defaultorder = DMABUF_DEFAULTORDER;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192module_param(defaultorder, ulong, 0);
193
194static int external_amp;
195module_param(external_amp, bool, 0);
196static int thinkpad;
197module_param(thinkpad, bool, 0);
198
199/*
200* set the powerdown module parm to 0 to disable all
201* powerdown. also set thinkpad to 1 to disable powerdown,
202* but also to enable the clkrun functionality.
203*/
Jesper Juhl2eebb192006-06-23 02:05:26 -0700204static unsigned cs_powerdown = 1;
205static unsigned cs_laptop_wait = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207/* An instance of the 4610 channel */
208struct cs_channel
209{
210 int used;
211 int num;
212 void *state;
213};
214
215#define CS46XX_MAJOR_VERSION "1"
216#define CS46XX_MINOR_VERSION "28"
217
218#ifdef __ia64__
219#define CS46XX_ARCH "64" //architecture key
220#else
221#define CS46XX_ARCH "32" //architecture key
222#endif
223
224static struct list_head cs46xx_devs = { &cs46xx_devs, &cs46xx_devs };
225
226/* magic numbers to protect our data structures */
227#define CS_CARD_MAGIC 0x43525553 /* "CRUS" */
228#define CS_STATE_MAGIC 0x4c4f4749 /* "LOGI" */
229#define NR_HW_CH 3
230
231/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
232#define NR_AC97 2
233
234static const unsigned sample_size[] = { 1, 2, 2, 4 };
235static const unsigned sample_shift[] = { 0, 1, 1, 2 };
236
237/* "software" or virtual channel, an instance of opened /dev/dsp */
238struct cs_state {
239 unsigned int magic;
240 struct cs_card *card; /* Card info */
241
242 /* single open lock mechanism, only used for recording */
Ingo Molnar910f5d22006-03-23 03:00:39 -0800243 struct mutex open_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 wait_queue_head_t open_wait;
245
246 /* file mode */
247 mode_t open_mode;
248
249 /* virtual channel number */
250 int virt;
251
252 struct dmabuf {
253 /* wave sample stuff */
254 unsigned int rate;
255 unsigned char fmt, enable;
256
257 /* hardware channel */
258 struct cs_channel *channel;
259 int pringbuf; /* Software ring slot */
260 void *pbuf; /* 4K hardware DMA buffer */
261
262 /* OSS buffer management stuff */
263 void *rawbuf;
264 dma_addr_t dma_handle;
265 unsigned buforder;
266 unsigned numfrag;
267 unsigned fragshift;
268 unsigned divisor;
269 unsigned type;
270 void *tmpbuff; /* tmp buffer for sample conversions */
271 dma_addr_t dmaaddr;
272 dma_addr_t dmaaddr_tmpbuff;
273 unsigned buforder_tmpbuff; /* Log base 2 of size in bytes.. */
274
275 /* our buffer acts like a circular ring */
276 unsigned hwptr; /* where dma last started, updated by update_ptr */
277 unsigned swptr; /* where driver last clear/filled, updated by read/write */
278 int count; /* bytes to be comsumed or been generated by dma machine */
279 unsigned total_bytes; /* total bytes dmaed by hardware */
280 unsigned blocks; /* total blocks */
281
282 unsigned error; /* number of over/underruns */
283 unsigned underrun; /* underrun pending before next write has occurred */
284 wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
285
286 /* redundant, but makes calculations easier */
287 unsigned fragsize;
288 unsigned dmasize;
289 unsigned fragsamples;
290
291 /* OSS stuff */
292 unsigned mapped:1;
293 unsigned ready:1;
294 unsigned endcleared:1;
295 unsigned SGok:1;
296 unsigned update_flag;
297 unsigned ossfragshift;
298 int ossmaxfrags;
299 unsigned subdivision;
300 } dmabuf;
301 /* Guard against mmap/write/read races */
Ingo Molnar910f5d22006-03-23 03:00:39 -0800302 struct mutex sem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303};
304
305struct cs_card {
306 struct cs_channel channel[2];
307 unsigned int magic;
308
309 /* We keep cs461x cards in a linked list */
310 struct cs_card *next;
311
312 /* The cs461x has a certain amount of cross channel interaction
313 so we use a single per card lock */
314 spinlock_t lock;
315
316 /* Keep AC97 sane */
317 spinlock_t ac97_lock;
318
319 /* mixer use count */
320 atomic_t mixer_use_cnt;
321
322 /* PCI device stuff */
Jesper Juhl2eebb192006-06-23 02:05:26 -0700323 struct pci_dev *pci_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 struct list_head list;
325
326 unsigned int pctl, cctl; /* Hardware DMA flag sets */
327
328 /* soundcore stuff */
329 int dev_audio;
330 int dev_midi;
331
332 /* structures for abstraction of hardware facilities, codecs, banks and channels*/
333 struct ac97_codec *ac97_codec[NR_AC97];
334 struct cs_state *states[2];
335
336 u16 ac97_features;
337
338 int amplifier; /* Amplifier control */
339 void (*amplifier_ctrl)(struct cs_card *, int);
340 void (*amp_init)(struct cs_card *);
341
342 int active; /* Active clocking */
343 void (*active_ctrl)(struct cs_card *, int);
344
345 /* hardware resources */
346 unsigned long ba0_addr;
347 unsigned long ba1_addr;
348 u32 irq;
349
350 /* mappings */
351 void __iomem *ba0;
352 union
353 {
354 struct
355 {
356 u8 __iomem *data0;
357 u8 __iomem *data1;
358 u8 __iomem *pmem;
359 u8 __iomem *reg;
360 } name;
361 u8 __iomem *idx[4];
362 } ba1;
363
364 /* Function support */
365 struct cs_channel *(*alloc_pcm_channel)(struct cs_card *);
366 struct cs_channel *(*alloc_rec_pcm_channel)(struct cs_card *);
367 void (*free_pcm_channel)(struct cs_card *, int chan);
368
369 /* /dev/midi stuff */
370 struct {
371 unsigned ird, iwr, icnt;
372 unsigned ord, owr, ocnt;
373 wait_queue_head_t open_wait;
374 wait_queue_head_t iwait;
375 wait_queue_head_t owait;
376 spinlock_t lock;
377 unsigned char ibuf[CS_MIDIINBUF];
378 unsigned char obuf[CS_MIDIOUTBUF];
379 mode_t open_mode;
Ingo Molnar910f5d22006-03-23 03:00:39 -0800380 struct mutex open_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 } midi;
382 struct cs46xx_pm pm;
383};
384
385static int cs_open_mixdev(struct inode *inode, struct file *file);
386static int cs_release_mixdev(struct inode *inode, struct file *file);
387static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
Jesper Juhl2eebb192006-06-23 02:05:26 -0700388 unsigned long arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389static int cs_hardware_init(struct cs_card *card);
390static int cs46xx_powerup(struct cs_card *card, unsigned int type);
391static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag);
392static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type);
Alexey Dobriyan99f932f2006-09-29 02:00:18 -0700393#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state);
395static int cs46xx_resume_tbl(struct pci_dev *pcidev);
Alexey Dobriyan99f932f2006-09-29 02:00:18 -0700396#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398#if CSDEBUG
399
400/* DEBUG ROUTINES */
401
402#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int)
403#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int)
404#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int)
405#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int)
406#define SOUND_MIXER_CS_APM _SIOWR('M',124, int)
407
408static void printioctl(unsigned int x)
409{
410 unsigned int i;
411 unsigned char vidx;
412 /* these values are incorrect for the ac97 driver, fix.
413 * Index of mixtable1[] member is Device ID
414 * and must be <= SOUND_MIXER_NRDEVICES.
415 * Value of array member is index into s->mix.vol[]
416 */
417 static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
418 [SOUND_MIXER_PCM] = 1, /* voice */
419 [SOUND_MIXER_LINE1] = 2, /* AUX */
420 [SOUND_MIXER_CD] = 3, /* CD */
421 [SOUND_MIXER_LINE] = 4, /* Line */
422 [SOUND_MIXER_SYNTH] = 5, /* FM */
423 [SOUND_MIXER_MIC] = 6, /* Mic */
424 [SOUND_MIXER_SPEAKER] = 7, /* Speaker */
425 [SOUND_MIXER_RECLEV] = 8, /* Recording level */
426 [SOUND_MIXER_VOLUME] = 9 /* Master Volume */
427 };
428
Jesper Juhl2eebb192006-06-23 02:05:26 -0700429 switch (x) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 case SOUND_MIXER_CS_GETDBGMASK:
431 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGMASK: ") );
432 break;
433 case SOUND_MIXER_CS_GETDBGLEVEL:
434 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGLEVEL: ") );
435 break;
436 case SOUND_MIXER_CS_SETDBGMASK:
437 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGMASK: ") );
438 break;
439 case SOUND_MIXER_CS_SETDBGLEVEL:
440 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGLEVEL: ") );
441 break;
442 case OSS_GETVERSION:
443 CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION: ") );
444 break;
445 case SNDCTL_DSP_SYNC:
446 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC: ") );
447 break;
448 case SNDCTL_DSP_SETDUPLEX:
449 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX: ") );
450 break;
451 case SNDCTL_DSP_GETCAPS:
452 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS: ") );
453 break;
454 case SNDCTL_DSP_RESET:
455 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET: ") );
456 break;
457 case SNDCTL_DSP_SPEED:
458 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED: ") );
459 break;
460 case SNDCTL_DSP_STEREO:
461 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO: ") );
462 break;
463 case SNDCTL_DSP_CHANNELS:
464 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS: ") );
465 break;
466 case SNDCTL_DSP_GETFMTS:
467 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS: ") );
468 break;
469 case SNDCTL_DSP_SETFMT:
470 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT: ") );
471 break;
472 case SNDCTL_DSP_POST:
473 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST: ") );
474 break;
475 case SNDCTL_DSP_GETTRIGGER:
476 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER: ") );
477 break;
478 case SNDCTL_DSP_SETTRIGGER:
479 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER: ") );
480 break;
481 case SNDCTL_DSP_GETOSPACE:
482 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE: ") );
483 break;
484 case SNDCTL_DSP_GETISPACE:
485 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE: ") );
486 break;
487 case SNDCTL_DSP_NONBLOCK:
488 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK: ") );
489 break;
490 case SNDCTL_DSP_GETODELAY:
491 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY: ") );
492 break;
493 case SNDCTL_DSP_GETIPTR:
494 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR: ") );
495 break;
496 case SNDCTL_DSP_GETOPTR:
497 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR: ") );
498 break;
499 case SNDCTL_DSP_GETBLKSIZE:
500 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE: ") );
501 break;
502 case SNDCTL_DSP_SETFRAGMENT:
503 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFRAGMENT: ") );
504 break;
505 case SNDCTL_DSP_SUBDIVIDE:
506 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE: ") );
507 break;
508 case SOUND_PCM_READ_RATE:
509 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE: ") );
510 break;
511 case SOUND_PCM_READ_CHANNELS:
512 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_CHANNELS: ") );
513 break;
514 case SOUND_PCM_READ_BITS:
515 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS: ") );
516 break;
517 case SOUND_PCM_WRITE_FILTER:
518 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_WRITE_FILTER: ") );
519 break;
520 case SNDCTL_DSP_SETSYNCRO:
521 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO: ") );
522 break;
523 case SOUND_PCM_READ_FILTER:
524 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER: ") );
525 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 case SOUND_MIXER_PRIVATE1:
527 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1: ") );
528 break;
529 case SOUND_MIXER_PRIVATE2:
530 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2: ") );
531 break;
532 case SOUND_MIXER_PRIVATE3:
533 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3: ") );
534 break;
535 case SOUND_MIXER_PRIVATE4:
536 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4: ") );
537 break;
538 case SOUND_MIXER_PRIVATE5:
539 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5: ") );
540 break;
541 case SOUND_MIXER_INFO:
542 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO: ") );
543 break;
544 case SOUND_OLD_MIXER_INFO:
545 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO: ") );
546 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 default:
Jesper Juhl2eebb192006-06-23 02:05:26 -0700548 switch (_IOC_NR(x)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 case SOUND_MIXER_VOLUME:
550 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_VOLUME: ") );
551 break;
552 case SOUND_MIXER_SPEAKER:
553 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SPEAKER: ") );
554 break;
555 case SOUND_MIXER_RECLEV:
556 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECLEV: ") );
557 break;
558 case SOUND_MIXER_MIC:
559 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_MIC: ") );
560 break;
561 case SOUND_MIXER_SYNTH:
562 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SYNTH: ") );
563 break;
564 case SOUND_MIXER_RECSRC:
565 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECSRC: ") );
566 break;
567 case SOUND_MIXER_DEVMASK:
568 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_DEVMASK: ") );
569 break;
570 case SOUND_MIXER_RECMASK:
571 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECMASK: ") );
572 break;
573 case SOUND_MIXER_STEREODEVS:
574 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_STEREODEVS: ") );
575 break;
576 case SOUND_MIXER_CAPS:
577 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:") );
578 break;
579 default:
580 i = _IOC_NR(x);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700581 if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 CS_DBGOUT(CS_IOCTL, 4, printk("UNKNOWN IOCTL: 0x%.8x NR=%d ",x,i) );
Jesper Juhl2eebb192006-06-23 02:05:26 -0700583 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d ",
Jesper Juhl2eebb192006-06-23 02:05:26 -0700585 x,i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 }
587 break;
588 }
589 }
590 CS_DBGOUT(CS_IOCTL, 4, printk("command = 0x%x IOC_NR=%d\n",x, _IOC_NR(x)) );
591}
592#endif
593
594/*
595 * common I/O routines
596 */
597
598static void cs461x_poke(struct cs_card *codec, unsigned long reg, unsigned int val)
599{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700600 writel(val, codec->ba1.idx[(reg >> 16) & 3] + (reg & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
603static unsigned int cs461x_peek(struct cs_card *codec, unsigned long reg)
604{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700605 return readl(codec->ba1.idx[(reg >> 16) & 3] + (reg & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
607
608static void cs461x_pokeBA0(struct cs_card *codec, unsigned long reg, unsigned int val)
609{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700610 writel(val, codec->ba0 + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611}
612
613static unsigned int cs461x_peekBA0(struct cs_card *codec, unsigned long reg)
614{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700615 return readl(codec->ba0 + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616}
617
618
619static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg);
620static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
621
622static struct cs_channel *cs_alloc_pcm_channel(struct cs_card *card)
623{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700624 if (card->channel[1].used == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return NULL;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700626 card->channel[1].used = 1;
627 card->channel[1].num = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 return &card->channel[1];
629}
630
631static struct cs_channel *cs_alloc_rec_pcm_channel(struct cs_card *card)
632{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700633 if (card->channel[0].used == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 return NULL;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700635 card->channel[0].used = 1;
636 card->channel[0].num = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 return &card->channel[0];
638}
639
640static void cs_free_pcm_channel(struct cs_card *card, int channel)
641{
642 card->channel[channel].state = NULL;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700643 card->channel[channel].used = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644}
645
646/*
647 * setup a divisor value to help with conversion from
648 * 16bit Stereo, down to 8bit stereo/mono or 16bit mono.
649 * assign a divisor of 1 if using 16bit Stereo as that is
650 * the only format that the static image will capture.
651 */
652static void cs_set_divisor(struct dmabuf *dmabuf)
653{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700654 if (dmabuf->type == CS_TYPE_DAC)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 dmabuf->divisor = 1;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700656 else if (!(dmabuf->fmt & CS_FMT_STEREO) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 (dmabuf->fmt & CS_FMT_16BIT))
658 dmabuf->divisor = 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700659 else if ((dmabuf->fmt & CS_FMT_STEREO) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 !(dmabuf->fmt & CS_FMT_16BIT))
661 dmabuf->divisor = 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700662 else if (!(dmabuf->fmt & CS_FMT_STEREO) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 !(dmabuf->fmt & CS_FMT_16BIT))
664 dmabuf->divisor = 4;
665 else
666 dmabuf->divisor = 1;
667
668 CS_DBGOUT(CS_PARMS | CS_FUNCTION, 8, printk(
669 "cs46xx: cs_set_divisor()- %s %d\n",
670 (dmabuf->type == CS_TYPE_ADC) ? "ADC" : "DAC",
671 dmabuf->divisor) );
672}
673
674/*
675* mute some of the more prevalent registers to avoid popping.
676*/
677static void cs_mute(struct cs_card *card, int state)
678{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700679 struct ac97_codec *dev = card->ac97_codec[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()+ %s\n",
Jesper Juhl2eebb192006-06-23 02:05:26 -0700682 (state == CS_TRUE) ? "Muting" : "UnMuting"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Jesper Juhl2eebb192006-06-23 02:05:26 -0700684 if (state == CS_TRUE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 /*
686 * fix pops when powering up on thinkpads
687 */
688 card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev,
689 (u8)BA0_AC97_MASTER_VOLUME);
690 card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev,
691 (u8)BA0_AC97_HEADPHONE_VOLUME);
692 card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev,
693 (u8)BA0_AC97_MASTER_VOLUME_MONO);
694 card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev,
695 (u8)BA0_AC97_PCM_OUT_VOLUME);
696
697 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
698 cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
699 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
700 cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700701 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, card->pm.u32AC97_master_volume);
703 cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, card->pm.u32AC97_headphone_volume);
704 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, card->pm.u32AC97_master_volume_mono);
705 cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, card->pm.u32AC97_pcm_out_volume);
706 }
707 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()-\n"));
708}
709
710/* set playback sample rate */
711static unsigned int cs_set_dac_rate(struct cs_state * state, unsigned int rate)
712{
713 struct dmabuf *dmabuf = &state->dmabuf;
714 unsigned int tmp1, tmp2;
715 unsigned int phiIncr;
716 unsigned int correctionPerGOF, correctionPerSec;
717 unsigned long flags;
718
719 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()+ %d\n",rate) );
720
721 /*
722 * Compute the values used to drive the actual sample rate conversion.
723 * The following formulas are being computed, using inline assembly
724 * since we need to use 64 bit arithmetic to compute the values:
725 *
726 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
727 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
728 * GOF_PER_SEC)
729 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
730 * GOF_PER_SEC * correctionPerGOF
731 *
732 * i.e.
733 *
734 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
735 * correctionPerGOF:correctionPerSec =
736 * dividend:remainder(ulOther / GOF_PER_SEC)
737 */
738 tmp1 = rate << 16;
739 phiIncr = tmp1 / 48000;
740 tmp1 -= phiIncr * 48000;
741 tmp1 <<= 10;
742 phiIncr <<= 10;
743 tmp2 = tmp1 / 48000;
744 phiIncr += tmp2;
745 tmp1 -= tmp2 * 48000;
746 correctionPerGOF = tmp1 / GOF_PER_SEC;
747 tmp1 -= correctionPerGOF * GOF_PER_SEC;
748 correctionPerSec = tmp1;
749
750 /*
751 * Fill in the SampleRateConverter control block.
752 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 spin_lock_irqsave(&state->card->lock, flags);
754 cs461x_poke(state->card, BA1_PSRC,
755 ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
756 cs461x_poke(state->card, BA1_PPI, phiIncr);
757 spin_unlock_irqrestore(&state->card->lock, flags);
758 dmabuf->rate = rate;
759
760 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()- %d\n",rate) );
761 return rate;
762}
763
764/* set recording sample rate */
Jesper Juhl2eebb192006-06-23 02:05:26 -0700765static unsigned int cs_set_adc_rate(struct cs_state *state, unsigned int rate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766{
767 struct dmabuf *dmabuf = &state->dmabuf;
768 struct cs_card *card = state->card;
769 unsigned int phiIncr, coeffIncr, tmp1, tmp2;
770 unsigned int correctionPerGOF, correctionPerSec, initialDelay;
771 unsigned int frameGroupLength, cnt;
772 unsigned long flags;
773 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()+ %d\n",rate) );
774
775 /*
776 * We can only decimate by up to a factor of 1/9th the hardware rate.
777 * Correct the value if an attempt is made to stray outside that limit.
778 */
779 if ((rate * 9) < 48000)
780 rate = 48000 / 9;
781
782 /*
Matt LaPlante0779bf22006-11-30 05:24:39 +0100783 * We cannot capture at at rate greater than the Input Rate (48000).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 * Return an error if an attempt is made to stray outside that limit.
785 */
786 if (rate > 48000)
787 rate = 48000;
788
789 /*
790 * Compute the values used to drive the actual sample rate conversion.
791 * The following formulas are being computed, using inline assembly
792 * since we need to use 64 bit arithmetic to compute the values:
793 *
794 * coeffIncr = -floor((Fs,out * 2^23) / Fs,in)
795 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
796 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
797 * GOF_PER_SEC)
798 * correctionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -
799 * GOF_PER_SEC * correctionPerGOF
800 * initialDelay = ceil((24 * Fs,in) / Fs,out)
801 *
802 * i.e.
803 *
804 * coeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in))
805 * phiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out)
806 * correctionPerGOF:correctionPerSec =
807 * dividend:remainder(ulOther / GOF_PER_SEC)
808 * initialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out)
809 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 tmp1 = rate << 16;
811 coeffIncr = tmp1 / 48000;
812 tmp1 -= coeffIncr * 48000;
813 tmp1 <<= 7;
814 coeffIncr <<= 7;
815 coeffIncr += tmp1 / 48000;
816 coeffIncr ^= 0xFFFFFFFF;
817 coeffIncr++;
818 tmp1 = 48000 << 16;
819 phiIncr = tmp1 / rate;
820 tmp1 -= phiIncr * rate;
821 tmp1 <<= 10;
822 phiIncr <<= 10;
823 tmp2 = tmp1 / rate;
824 phiIncr += tmp2;
825 tmp1 -= tmp2 * rate;
826 correctionPerGOF = tmp1 / GOF_PER_SEC;
827 tmp1 -= correctionPerGOF * GOF_PER_SEC;
828 correctionPerSec = tmp1;
829 initialDelay = ((48000 * 24) + rate - 1) / rate;
830
831 /*
832 * Fill in the VariDecimate control block.
833 */
834 spin_lock_irqsave(&card->lock, flags);
835 cs461x_poke(card, BA1_CSRC,
836 ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
837 cs461x_poke(card, BA1_CCI, coeffIncr);
838 cs461x_poke(card, BA1_CD,
839 (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80);
840 cs461x_poke(card, BA1_CPI, phiIncr);
841 spin_unlock_irqrestore(&card->lock, flags);
842
843 /*
844 * Figure out the frame group length for the write back task. Basically,
845 * this is just the factors of 24000 (2^6*3*5^3) that are not present in
846 * the output sample rate.
847 */
848 frameGroupLength = 1;
849 for (cnt = 2; cnt <= 64; cnt *= 2) {
850 if (((rate / cnt) * cnt) != rate)
851 frameGroupLength *= 2;
852 }
853 if (((rate / 3) * 3) != rate) {
854 frameGroupLength *= 3;
855 }
856 for (cnt = 5; cnt <= 125; cnt *= 5) {
857 if (((rate / cnt) * cnt) != rate)
858 frameGroupLength *= 5;
859 }
860
861 /*
862 * Fill in the WriteBack control block.
863 */
864 spin_lock_irqsave(&card->lock, flags);
865 cs461x_poke(card, BA1_CFG1, frameGroupLength);
866 cs461x_poke(card, BA1_CFG2, (0x00800000 | frameGroupLength));
867 cs461x_poke(card, BA1_CCST, 0x0000FFFF);
868 cs461x_poke(card, BA1_CSPB, ((65536 * rate) / 24000));
869 cs461x_poke(card, (BA1_CSPB + 4), 0x0000FFFF);
870 spin_unlock_irqrestore(&card->lock, flags);
871 dmabuf->rate = rate;
872 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()- %d\n",rate) );
873 return rate;
874}
875
876/* prepare channel attributes for playback */
877static void cs_play_setup(struct cs_state *state)
878{
879 struct dmabuf *dmabuf = &state->dmabuf;
880 struct cs_card *card = state->card;
881 unsigned int tmp, Count, playFormat;
882
883 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()+\n") );
884 cs461x_poke(card, BA1_PVOL, 0x80008000);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700885 if (!dmabuf->SGok)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 cs461x_poke(card, BA1_PBA, virt_to_bus(dmabuf->pbuf));
887
888 Count = 4;
889 playFormat=cs461x_peek(card, BA1_PFIE);
890 if ((dmabuf->fmt & CS_FMT_STEREO)) {
891 playFormat &= ~DMA_RQ_C2_AC_MONO_TO_STEREO;
892 Count *= 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700893 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 playFormat |= DMA_RQ_C2_AC_MONO_TO_STEREO;
895
896 if ((dmabuf->fmt & CS_FMT_16BIT)) {
897 playFormat &= ~(DMA_RQ_C2_AC_8_TO_16_BIT
898 | DMA_RQ_C2_AC_SIGNED_CONVERT);
899 Count *= 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700900 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 playFormat |= (DMA_RQ_C2_AC_8_TO_16_BIT
902 | DMA_RQ_C2_AC_SIGNED_CONVERT);
903
904 cs461x_poke(card, BA1_PFIE, playFormat);
905
906 tmp = cs461x_peek(card, BA1_PDTC);
907 tmp &= 0xfffffe00;
908 cs461x_poke(card, BA1_PDTC, tmp | --Count);
909
910 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()-\n") );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911}
912
913static struct InitStruct
914{
915 u32 off;
916 u32 val;
917} InitArray[] = { {0x00000040, 0x3fc0000f},
918 {0x0000004c, 0x04800000},
919
920 {0x000000b3, 0x00000780},
921 {0x000000b7, 0x00000000},
922 {0x000000bc, 0x07800000},
923
924 {0x000000cd, 0x00800000},
925 };
926
927/*
928 * "SetCaptureSPValues()" -- Initialize record task values before each
929 * capture startup.
930 */
931static void SetCaptureSPValues(struct cs_card *card)
932{
933 unsigned i, offset;
934 CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()+\n") );
Jesper Juhl2eebb192006-06-23 02:05:26 -0700935 for (i = 0; i < sizeof(InitArray) / sizeof(struct InitStruct); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 offset = InitArray[i].off*4; /* 8bit to 32bit offset value */
937 cs461x_poke(card, offset, InitArray[i].val );
938 }
939 CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()-\n") );
940}
941
942/* prepare channel attributes for recording */
943static void cs_rec_setup(struct cs_state *state)
944{
945 struct cs_card *card = state->card;
946 struct dmabuf *dmabuf = &state->dmabuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Jesper Juhl2eebb192006-06-23 02:05:26 -0700948 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()+\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 SetCaptureSPValues(card);
950
951 /*
952 * set the attenuation to 0dB
953 */
954 cs461x_poke(card, BA1_CVOL, 0x80008000);
955
956 /*
957 * set the physical address of the capture buffer into the SP
958 */
959 cs461x_poke(card, BA1_CBA, virt_to_bus(dmabuf->rawbuf));
960
961 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()-\n") );
962}
963
964
965/* get current playback/recording dma buffer pointer (byte offset from LBA),
966 called with spinlock held! */
967
968static inline unsigned cs_get_dma_addr(struct cs_state *state)
969{
970 struct dmabuf *dmabuf = &state->dmabuf;
971 u32 offset;
972
973 if ( (!(dmabuf->enable & DAC_RUNNING)) &&
974 (!(dmabuf->enable & ADC_RUNNING) ) )
975 {
976 CS_DBGOUT(CS_ERROR, 2, printk(
977 "cs46xx: ERROR cs_get_dma_addr(): not enabled \n") );
978 return 0;
979 }
980
981 /*
982 * granularity is byte boundary, good part.
983 */
Jesper Juhl2eebb192006-06-23 02:05:26 -0700984 if (dmabuf->enable & DAC_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 offset = cs461x_peek(state->card, BA1_PBA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 else /* ADC_RUNNING must be set */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 offset = cs461x_peek(state->card, BA1_CBA);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 CS_DBGOUT(CS_PARMS | CS_FUNCTION, 9,
990 printk("cs46xx: cs_get_dma_addr() %d\n",offset) );
991 offset = (u32)bus_to_virt((unsigned long)offset) - (u32)dmabuf->rawbuf;
992 CS_DBGOUT(CS_PARMS | CS_FUNCTION, 8,
993 printk("cs46xx: cs_get_dma_addr()- %d\n",offset) );
994 return offset;
995}
996
997static void resync_dma_ptrs(struct cs_state *state)
998{
999 struct dmabuf *dmabuf;
1000
1001 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()+ \n") );
Jesper Juhl2eebb192006-06-23 02:05:26 -07001002 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 dmabuf = &state->dmabuf;
1004 dmabuf->hwptr=dmabuf->swptr = 0;
1005 dmabuf->pringbuf = 0;
1006 }
1007 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()- \n") );
1008}
1009
1010/* Stop recording (lock held) */
1011static inline void __stop_adc(struct cs_state *state)
1012{
1013 struct dmabuf *dmabuf = &state->dmabuf;
1014 struct cs_card *card = state->card;
1015 unsigned int tmp;
1016
1017 dmabuf->enable &= ~ADC_RUNNING;
1018
1019 tmp = cs461x_peek(card, BA1_CCTL);
1020 tmp &= 0xFFFF0000;
1021 cs461x_poke(card, BA1_CCTL, tmp );
1022}
1023
1024static void stop_adc(struct cs_state *state)
1025{
1026 unsigned long flags;
1027
1028 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_adc()+ \n") );
1029 spin_lock_irqsave(&state->card->lock, flags);
1030 __stop_adc(state);
1031 spin_unlock_irqrestore(&state->card->lock, flags);
1032 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_adc()- \n") );
1033}
1034
1035static void start_adc(struct cs_state *state)
1036{
1037 struct dmabuf *dmabuf = &state->dmabuf;
1038 struct cs_card *card = state->card;
1039 unsigned long flags;
1040 unsigned int tmp;
1041
1042 spin_lock_irqsave(&card->lock, flags);
1043 if (!(dmabuf->enable & ADC_RUNNING) &&
1044 ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize)
1045 && dmabuf->ready) &&
1046 ((card->pm.flags & CS46XX_PM_IDLE) ||
1047 (card->pm.flags & CS46XX_PM_RESUMED)) )
1048 {
1049 dmabuf->enable |= ADC_RUNNING;
1050 cs_set_divisor(dmabuf);
1051 tmp = cs461x_peek(card, BA1_CCTL);
1052 tmp &= 0xFFFF0000;
1053 tmp |= card->cctl;
1054 CS_DBGOUT(CS_FUNCTION, 2, printk(
1055 "cs46xx: start_adc() poke 0x%x \n",tmp) );
1056 cs461x_poke(card, BA1_CCTL, tmp);
1057 }
1058 spin_unlock_irqrestore(&card->lock, flags);
1059}
1060
1061/* stop playback (lock held) */
1062static inline void __stop_dac(struct cs_state *state)
1063{
1064 struct dmabuf *dmabuf = &state->dmabuf;
1065 struct cs_card *card = state->card;
1066 unsigned int tmp;
1067
1068 dmabuf->enable &= ~DAC_RUNNING;
1069
1070 tmp=cs461x_peek(card, BA1_PCTL);
1071 tmp&=0xFFFF;
1072 cs461x_poke(card, BA1_PCTL, tmp);
1073}
1074
1075static void stop_dac(struct cs_state *state)
1076{
1077 unsigned long flags;
1078
1079 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_dac()+ \n") );
1080 spin_lock_irqsave(&state->card->lock, flags);
1081 __stop_dac(state);
1082 spin_unlock_irqrestore(&state->card->lock, flags);
1083 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_dac()- \n") );
1084}
1085
1086static void start_dac(struct cs_state *state)
1087{
1088 struct dmabuf *dmabuf = &state->dmabuf;
1089 struct cs_card *card = state->card;
1090 unsigned long flags;
1091 int tmp;
1092
1093 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()+ \n") );
1094 spin_lock_irqsave(&card->lock, flags);
1095 if (!(dmabuf->enable & DAC_RUNNING) &&
1096 ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) &&
1097 ((card->pm.flags & CS46XX_PM_IDLE) ||
1098 (card->pm.flags & CS46XX_PM_RESUMED)) )
1099 {
1100 dmabuf->enable |= DAC_RUNNING;
1101 tmp = cs461x_peek(card, BA1_PCTL);
1102 tmp &= 0xFFFF;
1103 tmp |= card->pctl;
1104 CS_DBGOUT(CS_PARMS, 6, printk(
1105 "cs46xx: start_dac() poke card=%p tmp=0x%.08x addr=%p \n",
1106 card, (unsigned)tmp,
1107 card->ba1.idx[(BA1_PCTL >> 16) & 3]+(BA1_PCTL&0xffff) ) );
1108 cs461x_poke(card, BA1_PCTL, tmp);
1109 }
1110 spin_unlock_irqrestore(&card->lock, flags);
1111 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()- \n") );
1112}
1113
1114#define DMABUF_MINORDER 1
1115
1116/*
1117 * allocate DMA buffer, playback and recording buffers are separate.
1118 */
1119static int alloc_dmabuf(struct cs_state *state)
1120{
1121
1122 struct cs_card *card=state->card;
1123 struct dmabuf *dmabuf = &state->dmabuf;
1124 void *rawbuf = NULL;
1125 void *tmpbuff = NULL;
1126 int order;
1127 struct page *map, *mapend;
1128 unsigned long df;
1129
1130 dmabuf->ready = dmabuf->mapped = 0;
1131 dmabuf->SGok = 0;
1132/*
1133* check for order within limits, but do not overwrite value.
1134*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07001135 if ((defaultorder > 1) && (defaultorder < 12))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 df = defaultorder;
1137 else
1138 df = 2;
1139
1140 for (order = df; order >= DMABUF_MINORDER; order--)
Jesper Juhl2eebb192006-06-23 02:05:26 -07001141 if ((rawbuf = (void *)pci_alloc_consistent(
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr)))
1143 break;
1144 if (!rawbuf) {
1145 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
1146 "cs46xx: alloc_dmabuf(): unable to allocate rawbuf\n"));
1147 return -ENOMEM;
1148 }
1149 dmabuf->buforder = order;
1150 dmabuf->rawbuf = rawbuf;
1151 // Now mark the pages as reserved; otherwise the
1152 // remap_pfn_range() in cs46xx_mmap doesn't work.
1153 // 1. get index to last page in mem_map array for rawbuf.
1154 mapend = virt_to_page(dmabuf->rawbuf +
1155 (PAGE_SIZE << dmabuf->buforder) - 1);
1156
1157 // 2. mark each physical page in range as 'reserved'.
1158 for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
1159 cs4x_mem_map_reserve(map);
1160
1161 CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: alloc_dmabuf(): allocated %ld (order = %d) bytes at %p\n",
1162 PAGE_SIZE << order, order, rawbuf) );
1163
1164/*
1165* only allocate the conversion buffer for the ADC
1166*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07001167 if (dmabuf->type == CS_TYPE_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 dmabuf->tmpbuff = NULL;
1169 dmabuf->buforder_tmpbuff = 0;
1170 return 0;
1171 }
1172/*
1173 * now the temp buffer for 16/8 conversions
1174 */
1175
1176 tmpbuff = (void *) pci_alloc_consistent(
1177 card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr_tmpbuff);
1178
1179 if (!tmpbuff)
1180 return -ENOMEM;
1181 CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: allocated %ld (order = %d) bytes at %p\n",
1182 PAGE_SIZE << order, order, tmpbuff) );
1183
1184 dmabuf->tmpbuff = tmpbuff;
1185 dmabuf->buforder_tmpbuff = order;
1186
1187 // Now mark the pages as reserved; otherwise the
1188 // remap_pfn_range() in cs46xx_mmap doesn't work.
1189 // 1. get index to last page in mem_map array for rawbuf.
1190 mapend = virt_to_page(dmabuf->tmpbuff +
1191 (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
1192
1193 // 2. mark each physical page in range as 'reserved'.
1194 for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++)
1195 cs4x_mem_map_reserve(map);
1196 return 0;
1197}
1198
1199/* free DMA buffer */
1200static void dealloc_dmabuf(struct cs_state *state)
1201{
1202 struct dmabuf *dmabuf = &state->dmabuf;
1203 struct page *map, *mapend;
1204
1205 if (dmabuf->rawbuf) {
1206 // Undo prog_dmabuf()'s marking the pages as reserved
1207 mapend = virt_to_page(dmabuf->rawbuf +
1208 (PAGE_SIZE << dmabuf->buforder) - 1);
1209 for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
1210 cs4x_mem_map_unreserve(map);
1211 free_dmabuf(state->card, dmabuf);
1212 }
1213
1214 if (dmabuf->tmpbuff) {
1215 // Undo prog_dmabuf()'s marking the pages as reserved
1216 mapend = virt_to_page(dmabuf->tmpbuff +
1217 (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
1218 for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++)
1219 cs4x_mem_map_unreserve(map);
1220 free_dmabuf2(state->card, dmabuf);
1221 }
1222
1223 dmabuf->rawbuf = NULL;
1224 dmabuf->tmpbuff = NULL;
1225 dmabuf->mapped = dmabuf->ready = 0;
1226 dmabuf->SGok = 0;
1227}
1228
1229static int __prog_dmabuf(struct cs_state *state)
1230{
1231 struct dmabuf *dmabuf = &state->dmabuf;
1232 unsigned long flags;
1233 unsigned long allocated_pages, allocated_bytes;
1234 unsigned long tmp1, tmp2, fmt=0;
1235 unsigned long *ptmp = (unsigned long *) dmabuf->pbuf;
1236 unsigned long SGarray[9], nSGpages=0;
1237 int ret;
1238
1239 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()+ \n"));
1240/*
1241 * check for CAPTURE and use only non-sg for initial release
1242 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001243 if (dmabuf->type == CS_TYPE_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf() ADC\n"));
1245 /*
1246 * add in non-sg support for capture.
1247 */
1248 spin_lock_irqsave(&state->card->lock, flags);
1249 /* add code to reset the rawbuf memory. TRW */
1250 resync_dma_ptrs(state);
1251 dmabuf->total_bytes = dmabuf->blocks = 0;
1252 dmabuf->count = dmabuf->error = dmabuf->underrun = 0;
1253
1254 dmabuf->SGok = 0;
1255
1256 spin_unlock_irqrestore(&state->card->lock, flags);
1257
1258 /* allocate DMA buffer if not allocated yet */
1259 if (!dmabuf->rawbuf || !dmabuf->tmpbuff)
1260 if ((ret = alloc_dmabuf(state)))
1261 return ret;
1262 /*
1263 * static image only supports 16Bit signed, stereo - hard code fmt
1264 */
1265 fmt = CS_FMT_16BIT | CS_FMT_STEREO;
1266
1267 dmabuf->numfrag = 2;
1268 dmabuf->fragsize = 2048;
1269 dmabuf->fragsamples = 2048 >> sample_shift[fmt];
1270 dmabuf->dmasize = 4096;
1271 dmabuf->fragshift = 11;
1272
1273 memset(dmabuf->rawbuf, (fmt & CS_FMT_16BIT) ? 0 : 0x80,
1274 dmabuf->dmasize);
1275 memset(dmabuf->tmpbuff, (fmt & CS_FMT_16BIT) ? 0 : 0x80,
1276 PAGE_SIZE<<dmabuf->buforder_tmpbuff);
1277
1278 /*
1279 * Now set up the ring
1280 */
1281
1282 spin_lock_irqsave(&state->card->lock, flags);
1283 cs_rec_setup(state);
1284 spin_unlock_irqrestore(&state->card->lock, flags);
1285
1286 /* set the ready flag for the dma buffer */
1287 dmabuf->ready = 1;
1288
1289 CS_DBGOUT(CS_PARMS, 4, printk(
1290 "cs46xx: prog_dmabuf(): CAPTURE rate=%d fmt=0x%x numfrag=%d "
1291 "fragsize=%d dmasize=%d\n",
1292 dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
1293 dmabuf->fragsize, dmabuf->dmasize) );
1294
1295 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- 0 \n"));
1296 return 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001297 } else if (dmabuf->type == CS_TYPE_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 /*
1299 * Must be DAC
1300 */
1301 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf() DAC\n"));
1302 spin_lock_irqsave(&state->card->lock, flags);
1303 resync_dma_ptrs(state);
1304 dmabuf->total_bytes = dmabuf->blocks = 0;
1305 dmabuf->count = dmabuf->error = dmabuf->underrun = 0;
1306
1307 dmabuf->SGok = 0;
1308
1309 spin_unlock_irqrestore(&state->card->lock, flags);
1310
1311 /* allocate DMA buffer if not allocated yet */
1312 if (!dmabuf->rawbuf)
1313 if ((ret = alloc_dmabuf(state)))
1314 return ret;
1315
1316 allocated_pages = 1 << dmabuf->buforder;
1317 allocated_bytes = allocated_pages*PAGE_SIZE;
1318
Jesper Juhl2eebb192006-06-23 02:05:26 -07001319 if (allocated_pages < 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 CS_DBGOUT(CS_FUNCTION, 4, printk(
1321 "cs46xx: prog_dmabuf() Error: allocated_pages too small (%d)\n",
1322 (unsigned)allocated_pages));
1323 return -ENOMEM;
1324 }
1325
1326 /* Use all the pages allocated, fragsize 4k. */
1327 /* Use 'pbuf' for S/G page map table. */
1328 dmabuf->SGok = 1; /* Use S/G. */
1329
1330 nSGpages = allocated_bytes/4096; /* S/G pages always 4k. */
1331
1332 /* Set up S/G variables. */
1333 *ptmp = virt_to_bus(dmabuf->rawbuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001334 *(ptmp + 1) = 0x00000008;
1335 for (tmp1 = 1; tmp1 < nSGpages; tmp1++) {
1336 *(ptmp + 2 * tmp1) = virt_to_bus((dmabuf->rawbuf) + 4096 * tmp1);
1337 if (tmp1 == nSGpages - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 tmp2 = 0xbfff0000;
1339 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07001340 tmp2 = 0x80000000 + 8 * (tmp1 + 1);
1341 *(ptmp + 2 * tmp1 + 1) = tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 }
1343 SGarray[0] = 0x82c0200d;
1344 SGarray[1] = 0xffff0000;
1345 SGarray[2] = *ptmp;
1346 SGarray[3] = 0x00010600;
1347 SGarray[4] = *(ptmp+2);
1348 SGarray[5] = 0x80000010;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001349 SGarray[6] = *ptmp;
1350 SGarray[7] = *(ptmp+2);
1351 SGarray[8] = (virt_to_bus(dmabuf->pbuf) & 0xffff000) | 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
Jesper Juhl2eebb192006-06-23 02:05:26 -07001353 if (dmabuf->SGok) {
1354 dmabuf->numfrag = nSGpages;
1355 dmabuf->fragsize = 4096;
1356 dmabuf->fragsamples = 4096 >> sample_shift[dmabuf->fmt];
1357 dmabuf->fragshift = 12;
1358 dmabuf->dmasize = dmabuf->numfrag * 4096;
1359 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 SGarray[0] = 0xf2c0000f;
1361 SGarray[1] = 0x00000200;
1362 SGarray[2] = 0;
1363 SGarray[3] = 0x00010600;
1364 SGarray[4]=SGarray[5]=SGarray[6]=SGarray[7]=SGarray[8] = 0;
1365 dmabuf->numfrag = 2;
1366 dmabuf->fragsize = 2048;
1367 dmabuf->fragsamples = 2048 >> sample_shift[dmabuf->fmt];
1368 dmabuf->dmasize = 4096;
1369 dmabuf->fragshift = 11;
1370 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001371 for (tmp1 = 0; tmp1 < sizeof(SGarray) / 4; tmp1++)
1372 cs461x_poke(state->card, BA1_PDTC+tmp1 * 4, SGarray[tmp1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
1374 memset(dmabuf->rawbuf, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
1375 dmabuf->dmasize);
1376
1377 /*
1378 * Now set up the ring
1379 */
1380
1381 spin_lock_irqsave(&state->card->lock, flags);
1382 cs_play_setup(state);
1383 spin_unlock_irqrestore(&state->card->lock, flags);
1384
1385 /* set the ready flag for the dma buffer */
1386 dmabuf->ready = 1;
1387
1388 CS_DBGOUT(CS_PARMS, 4, printk(
1389 "cs46xx: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d "
1390 "fragsize=%d dmasize=%d\n",
1391 dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
1392 dmabuf->fragsize, dmabuf->dmasize) );
1393
1394 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- \n"));
1395 return 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001396 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- Invalid Type %d\n",
1398 dmabuf->type));
1399 }
1400 return 1;
1401}
1402
1403static int prog_dmabuf(struct cs_state *state)
1404{
1405 int ret;
1406
Ingo Molnar910f5d22006-03-23 03:00:39 -08001407 mutex_lock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 ret = __prog_dmabuf(state);
Ingo Molnar910f5d22006-03-23 03:00:39 -08001409 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
1411 return ret;
1412}
1413
1414static void cs_clear_tail(struct cs_state *state)
1415{
1416}
1417
1418static int drain_dac(struct cs_state *state, int nonblock)
1419{
1420 DECLARE_WAITQUEUE(wait, current);
1421 struct dmabuf *dmabuf = &state->dmabuf;
1422 struct cs_card *card=state->card;
1423 unsigned long flags;
1424 unsigned long tmo;
1425 int count;
1426
1427 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()+ \n"));
1428 if (dmabuf->mapped || !dmabuf->ready)
1429 {
1430 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0, not ready\n"));
1431 return 0;
1432 }
1433
1434 add_wait_queue(&dmabuf->wait, &wait);
1435 for (;;) {
1436 /* It seems that we have to set the current state to TASK_INTERRUPTIBLE
1437 every time to make the process really go to sleep */
1438 current->state = TASK_INTERRUPTIBLE;
1439
1440 spin_lock_irqsave(&state->card->lock, flags);
1441 count = dmabuf->count;
1442 spin_unlock_irqrestore(&state->card->lock, flags);
1443
1444 if (count <= 0)
1445 break;
1446
1447 if (signal_pending(current))
1448 break;
1449
1450 if (nonblock) {
1451 remove_wait_queue(&dmabuf->wait, &wait);
1452 current->state = TASK_RUNNING;
1453 return -EBUSY;
1454 }
1455
1456 tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
1457 tmo >>= sample_shift[dmabuf->fmt];
1458 tmo += (2048*HZ)/dmabuf->rate;
1459
1460 if (!schedule_timeout(tmo ? tmo : 1) && tmo){
1461 printk(KERN_ERR "cs46xx: drain_dac, dma timeout? %d\n", count);
1462 break;
1463 }
1464 }
1465 remove_wait_queue(&dmabuf->wait, &wait);
1466 current->state = TASK_RUNNING;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001467 if (signal_pending(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- -ERESTARTSYS\n"));
1469 /*
1470 * set to silence and let that clear the fifos.
1471 */
1472 cs461x_clear_serial_FIFOs(card, CS_TYPE_DAC);
1473 return -ERESTARTSYS;
1474 }
1475
1476 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0\n"));
1477 return 0;
1478}
1479
1480
1481/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
1482static void cs_update_ptr(struct cs_card *card, int wake)
1483{
1484 struct cs_state *state;
1485 struct dmabuf *dmabuf;
1486 unsigned hwptr;
1487 int diff;
1488
1489 /* error handling and process wake up for ADC */
1490 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07001491 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 dmabuf = &state->dmabuf;
1493 if (dmabuf->enable & ADC_RUNNING) {
1494 /* update hardware pointer */
1495 hwptr = cs_get_dma_addr(state);
1496
1497 diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
1498 CS_DBGOUT(CS_PARMS, 9, printk(
1499 "cs46xx: cs_update_ptr()+ ADC hwptr=%d diff=%d\n",
1500 hwptr,diff) );
1501 dmabuf->hwptr = hwptr;
1502 dmabuf->total_bytes += diff;
1503 dmabuf->count += diff;
1504 if (dmabuf->count > dmabuf->dmasize)
1505 dmabuf->count = dmabuf->dmasize;
1506
Jesper Juhl2eebb192006-06-23 02:05:26 -07001507 if (dmabuf->mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
1509 wake_up(&dmabuf->wait);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001510 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 if (wake && dmabuf->count > 0)
1512 wake_up(&dmabuf->wait);
1513 }
1514 }
1515 }
1516
1517/*
1518 * Now the DAC
1519 */
1520 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07001521 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 dmabuf = &state->dmabuf;
1523 /* error handling and process wake up for DAC */
1524 if (dmabuf->enable & DAC_RUNNING) {
1525 /* update hardware pointer */
1526 hwptr = cs_get_dma_addr(state);
1527
1528 diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
1529 CS_DBGOUT(CS_PARMS, 9, printk(
1530 "cs46xx: cs_update_ptr()+ DAC hwptr=%d diff=%d\n",
1531 hwptr,diff) );
1532 dmabuf->hwptr = hwptr;
1533 dmabuf->total_bytes += diff;
1534 if (dmabuf->mapped) {
1535 dmabuf->count += diff;
1536 if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
1537 wake_up(&dmabuf->wait);
1538 /*
1539 * other drivers use fragsize, but don't see any sense
1540 * in that, since dmasize is the buffer asked for
1541 * via mmap.
1542 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001543 if (dmabuf->count > dmabuf->dmasize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 dmabuf->count &= dmabuf->dmasize-1;
1545 } else {
1546 dmabuf->count -= diff;
1547 /*
1548 * backfill with silence and clear out the last
1549 * "diff" number of bytes.
1550 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001551 if (hwptr >= diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 memset(dmabuf->rawbuf + hwptr - diff,
1553 (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, diff);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001554 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 memset(dmabuf->rawbuf,
1556 (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
1557 (unsigned)hwptr);
1558 memset((char *)dmabuf->rawbuf +
1559 dmabuf->dmasize + hwptr - diff,
1560 (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
1561 diff - hwptr);
1562 }
1563
1564 if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
1565 CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
1566 "cs46xx: ERROR DAC count<0 or count > dmasize (%d)\n",
1567 dmabuf->count));
1568 /*
1569 * buffer underrun or buffer overrun, reset the
1570 * count of bytes written back to 0.
1571 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001572 if (dmabuf->count < 0)
1573 dmabuf->underrun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 dmabuf->count = 0;
1575 dmabuf->error++;
1576 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001577 if (wake && dmabuf->count < (signed)dmabuf->dmasize / 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 wake_up(&dmabuf->wait);
1579 }
1580 }
1581 }
1582}
1583
1584
1585/* hold spinlock for the following! */
1586static void cs_handle_midi(struct cs_card *card)
1587{
1588 unsigned char ch;
1589 int wake;
1590 unsigned temp1;
1591
1592 wake = 0;
1593 while (!(cs461x_peekBA0(card, BA0_MIDSR) & MIDSR_RBE)) {
1594 ch = cs461x_peekBA0(card, BA0_MIDRP);
1595 if (card->midi.icnt < CS_MIDIINBUF) {
1596 card->midi.ibuf[card->midi.iwr] = ch;
1597 card->midi.iwr = (card->midi.iwr + 1) % CS_MIDIINBUF;
1598 card->midi.icnt++;
1599 }
1600 wake = 1;
1601 }
1602 if (wake)
1603 wake_up(&card->midi.iwait);
1604 wake = 0;
1605 while (!(cs461x_peekBA0(card, BA0_MIDSR) & MIDSR_TBF) && card->midi.ocnt > 0) {
1606 temp1 = ( card->midi.obuf[card->midi.ord] ) & 0x000000ff;
1607 cs461x_pokeBA0(card, BA0_MIDWP,temp1);
1608 card->midi.ord = (card->midi.ord + 1) % CS_MIDIOUTBUF;
1609 card->midi.ocnt--;
1610 if (card->midi.ocnt < CS_MIDIOUTBUF-16)
1611 wake = 1;
1612 }
1613 if (wake)
1614 wake_up(&card->midi.owait);
1615}
1616
David Howells7d12e782006-10-05 14:55:46 +01001617static irqreturn_t cs_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618{
1619 struct cs_card *card = (struct cs_card *)dev_id;
1620 /* Single channel card */
1621 struct cs_state *recstate = card->channel[0].state;
1622 struct cs_state *playstate = card->channel[1].state;
1623 u32 status;
1624
1625 CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()+ \n"));
1626
1627 spin_lock(&card->lock);
1628
1629 status = cs461x_peekBA0(card, BA0_HISR);
1630
Jesper Juhl2eebb192006-06-23 02:05:26 -07001631 if ((status & 0x7fffffff) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV);
1633 spin_unlock(&card->lock);
1634 return IRQ_HANDLED; /* Might be IRQ_NONE.. */
1635 }
1636
1637 /*
1638 * check for playback or capture interrupt only
1639 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001640 if (((status & HISR_VC0) && playstate && playstate->dmabuf.ready) ||
1641 (((status & HISR_VC1) && recstate && recstate->dmabuf.ready))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 CS_DBGOUT(CS_INTERRUPT, 8, printk(
1643 "cs46xx: cs_interrupt() interrupt bit(s) set (0x%x)\n",status));
1644 cs_update_ptr(card, CS_TRUE);
1645 }
1646
Jesper Juhl2eebb192006-06-23 02:05:26 -07001647 if (status & HISR_MIDI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 cs_handle_midi(card);
1649
1650 /* clear 'em */
1651 cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV);
1652 spin_unlock(&card->lock);
1653 CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()- \n"));
1654 return IRQ_HANDLED;
1655}
1656
1657
1658/**********************************************************************/
1659
1660static ssize_t cs_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
1661{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001662 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 ssize_t ret;
1664 unsigned long flags;
1665 unsigned ptr;
1666 int cnt;
1667
1668 if (!access_ok(VERIFY_WRITE, buffer, count))
1669 return -EFAULT;
1670 ret = 0;
1671 while (count > 0) {
1672 spin_lock_irqsave(&card->lock, flags);
1673 ptr = card->midi.ird;
1674 cnt = CS_MIDIINBUF - ptr;
1675 if (card->midi.icnt < cnt)
1676 cnt = card->midi.icnt;
1677 spin_unlock_irqrestore(&card->lock, flags);
1678 if (cnt > count)
1679 cnt = count;
1680 if (cnt <= 0) {
1681 if (file->f_flags & O_NONBLOCK)
1682 return ret ? ret : -EAGAIN;
1683 interruptible_sleep_on(&card->midi.iwait);
1684 if (signal_pending(current))
1685 return ret ? ret : -ERESTARTSYS;
1686 continue;
1687 }
1688 if (copy_to_user(buffer, card->midi.ibuf + ptr, cnt))
1689 return ret ? ret : -EFAULT;
1690 ptr = (ptr + cnt) % CS_MIDIINBUF;
1691 spin_lock_irqsave(&card->lock, flags);
1692 card->midi.ird = ptr;
1693 card->midi.icnt -= cnt;
1694 spin_unlock_irqrestore(&card->lock, flags);
1695 count -= cnt;
1696 buffer += cnt;
1697 ret += cnt;
1698 }
1699 return ret;
1700}
1701
1702
1703static ssize_t cs_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
1704{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001705 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 ssize_t ret;
1707 unsigned long flags;
1708 unsigned ptr;
1709 int cnt;
1710
1711 if (!access_ok(VERIFY_READ, buffer, count))
1712 return -EFAULT;
1713 ret = 0;
1714 while (count > 0) {
1715 spin_lock_irqsave(&card->lock, flags);
1716 ptr = card->midi.owr;
1717 cnt = CS_MIDIOUTBUF - ptr;
1718 if (card->midi.ocnt + cnt > CS_MIDIOUTBUF)
1719 cnt = CS_MIDIOUTBUF - card->midi.ocnt;
1720 if (cnt <= 0)
1721 cs_handle_midi(card);
1722 spin_unlock_irqrestore(&card->lock, flags);
1723 if (cnt > count)
1724 cnt = count;
1725 if (cnt <= 0) {
1726 if (file->f_flags & O_NONBLOCK)
1727 return ret ? ret : -EAGAIN;
1728 interruptible_sleep_on(&card->midi.owait);
1729 if (signal_pending(current))
1730 return ret ? ret : -ERESTARTSYS;
1731 continue;
1732 }
1733 if (copy_from_user(card->midi.obuf + ptr, buffer, cnt))
1734 return ret ? ret : -EFAULT;
1735 ptr = (ptr + cnt) % CS_MIDIOUTBUF;
1736 spin_lock_irqsave(&card->lock, flags);
1737 card->midi.owr = ptr;
1738 card->midi.ocnt += cnt;
1739 spin_unlock_irqrestore(&card->lock, flags);
1740 count -= cnt;
1741 buffer += cnt;
1742 ret += cnt;
1743 spin_lock_irqsave(&card->lock, flags);
1744 cs_handle_midi(card);
1745 spin_unlock_irqrestore(&card->lock, flags);
1746 }
1747 return ret;
1748}
1749
1750
1751static unsigned int cs_midi_poll(struct file *file, struct poll_table_struct *wait)
1752{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001753 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 unsigned long flags;
1755 unsigned int mask = 0;
1756
1757 if (file->f_flags & FMODE_WRITE)
1758 poll_wait(file, &card->midi.owait, wait);
1759 if (file->f_flags & FMODE_READ)
1760 poll_wait(file, &card->midi.iwait, wait);
1761 spin_lock_irqsave(&card->lock, flags);
1762 if (file->f_flags & FMODE_READ) {
1763 if (card->midi.icnt > 0)
1764 mask |= POLLIN | POLLRDNORM;
1765 }
1766 if (file->f_flags & FMODE_WRITE) {
1767 if (card->midi.ocnt < CS_MIDIOUTBUF)
1768 mask |= POLLOUT | POLLWRNORM;
1769 }
1770 spin_unlock_irqrestore(&card->lock, flags);
1771 return mask;
1772}
1773
1774
1775static int cs_midi_open(struct inode *inode, struct file *file)
1776{
1777 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001778 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 unsigned long flags;
1780 struct list_head *entry;
1781
Jesper Juhl2eebb192006-06-23 02:05:26 -07001782 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 card = list_entry(entry, struct cs_card, list);
1784 if (card->dev_midi == minor)
1785 break;
1786 }
1787
1788 if (entry == &cs46xx_devs)
1789 return -ENODEV;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001790 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
1792 "cs46xx: cs46xx_midi_open(): Error - unable to find card struct\n"));
1793 return -ENODEV;
1794 }
1795
1796 file->private_data = card;
1797 /* wait for device to become free */
Ingo Molnar910f5d22006-03-23 03:00:39 -08001798 mutex_lock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 while (card->midi.open_mode & file->f_mode) {
1800 if (file->f_flags & O_NONBLOCK) {
Ingo Molnar910f5d22006-03-23 03:00:39 -08001801 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 return -EBUSY;
1803 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08001804 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 interruptible_sleep_on(&card->midi.open_wait);
1806 if (signal_pending(current))
1807 return -ERESTARTSYS;
Ingo Molnar910f5d22006-03-23 03:00:39 -08001808 mutex_lock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 }
1810 spin_lock_irqsave(&card->midi.lock, flags);
1811 if (!(card->midi.open_mode & (FMODE_READ | FMODE_WRITE))) {
1812 card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
1813 card->midi.ord = card->midi.owr = card->midi.ocnt = 0;
1814 card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
1815 cs461x_pokeBA0(card, BA0_MIDCR, 0x0000000f); /* Enable xmit, rcv. */
1816 cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM); /* Enable interrupts */
1817 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001818 if (file->f_mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001820 if (file->f_mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 card->midi.ord = card->midi.owr = card->midi.ocnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 spin_unlock_irqrestore(&card->midi.lock, flags);
1823 card->midi.open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE));
Ingo Molnar910f5d22006-03-23 03:00:39 -08001824 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 return 0;
1826}
1827
1828
1829static int cs_midi_release(struct inode *inode, struct file *file)
1830{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001831 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 DECLARE_WAITQUEUE(wait, current);
1833 unsigned long flags;
1834 unsigned count, tmo;
1835
1836 if (file->f_mode & FMODE_WRITE) {
1837 current->state = TASK_INTERRUPTIBLE;
1838 add_wait_queue(&card->midi.owait, &wait);
1839 for (;;) {
1840 spin_lock_irqsave(&card->midi.lock, flags);
1841 count = card->midi.ocnt;
1842 spin_unlock_irqrestore(&card->midi.lock, flags);
1843 if (count <= 0)
1844 break;
1845 if (signal_pending(current))
1846 break;
1847 if (file->f_flags & O_NONBLOCK)
1848 break;
1849 tmo = (count * HZ) / 3100;
1850 if (!schedule_timeout(tmo ? : 1) && tmo)
1851 printk(KERN_DEBUG "cs46xx: midi timed out??\n");
1852 }
1853 remove_wait_queue(&card->midi.owait, &wait);
1854 current->state = TASK_RUNNING;
1855 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08001856 mutex_lock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 card->midi.open_mode &= (~(file->f_mode & (FMODE_READ | FMODE_WRITE)));
Ingo Molnar910f5d22006-03-23 03:00:39 -08001858 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 wake_up(&card->midi.open_wait);
1860 return 0;
1861}
1862
1863/*
1864 * Midi file operations struct.
1865 */
1866static /*const*/ struct file_operations cs_midi_fops = {
1867 CS_OWNER CS_THIS_MODULE
1868 .llseek = no_llseek,
1869 .read = cs_midi_read,
1870 .write = cs_midi_write,
1871 .poll = cs_midi_poll,
1872 .open = cs_midi_open,
1873 .release = cs_midi_release,
1874};
1875
1876/*
1877 *
1878 * CopySamples copies 16-bit stereo signed samples from the source to the
1879 * destination, possibly converting down to unsigned 8-bit and/or mono.
1880 * count specifies the number of output bytes to write.
1881 *
1882 * Arguments:
1883 *
1884 * dst - Pointer to a destination buffer.
1885 * src - Pointer to a source buffer
1886 * count - The number of bytes to copy into the destination buffer.
1887 * fmt - CS_FMT_16BIT and/or CS_FMT_STEREO bits
1888 * dmabuf - pointer to the dma buffer structure
1889 *
1890 * NOTES: only call this routine if the output desired is not 16 Signed Stereo
1891 *
1892 *
1893 */
1894static void CopySamples(char *dst, char *src, int count, unsigned fmt,
1895 struct dmabuf *dmabuf)
1896{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 s32 s32AudioSample;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001898 s16 *psSrc = (s16 *)src;
1899 s16 *psDst = (s16 *)dst;
1900 u8 *pucDst = (u8 *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
1902 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: CopySamples()+ ") );
1903 CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
1904 " dst=%p src=%p count=%d fmt=0x%x\n",
1905 dst,src,count,fmt) );
1906
1907 /*
1908 * See if the data should be output as 8-bit unsigned stereo.
1909 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001910 if ((fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 /*
1912 * Convert each 16-bit signed stereo sample to 8-bit unsigned
1913 * stereo using rounding.
1914 */
1915 psSrc = (s16 *)src;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001916 count = count / 2;
1917 while (count--)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 *(pucDst++) = (u8)(((s16)(*psSrc++) + (s16)0x8000) >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 }
1920 /*
1921 * See if the data should be output at 8-bit unsigned mono.
1922 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001923 else if (!(fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 /*
1925 * Convert each 16-bit signed stereo sample to 8-bit unsigned
1926 * mono using averaging and rounding.
1927 */
1928 psSrc = (s16 *)src;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001929 count = count / 2;
1930 while (count--) {
1931 s32AudioSample = ((*psSrc) + (*(psSrc + 1))) / 2 + (s32)0x80;
1932 if (s32AudioSample > 0x7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 s32AudioSample = 0x7fff;
1934 *(pucDst++) = (u8)(((s16)s32AudioSample + (s16)0x8000) >> 8);
1935 psSrc += 2;
1936 }
1937 }
1938 /*
1939 * See if the data should be output at 16-bit signed mono.
1940 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001941 else if (!(fmt & CS_FMT_STEREO) && (fmt & CS_FMT_16BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 /*
1943 * Convert each 16-bit signed stereo sample to 16-bit signed
1944 * mono using averaging.
1945 */
1946 psSrc = (s16 *)src;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001947 count = count / 2;
1948 while (count--) {
1949 *(psDst++) = (s16)((*psSrc) + (*(psSrc + 1))) / 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 psSrc += 2;
1951 }
1952 }
1953}
1954
1955/*
1956 * cs_copy_to_user()
1957 * replacement for the standard copy_to_user, to allow for a conversion from
1958 * 16 bit to 8 bit and from stereo to mono, if the record conversion is active.
1959 * The current CS46xx/CS4280 static image only records in 16bit unsigned Stereo,
1960 * so we convert from any of the other format combinations.
1961 */
1962static unsigned cs_copy_to_user(
1963 struct cs_state *s,
1964 void __user *dest,
1965 void *hwsrc,
1966 unsigned cnt,
1967 unsigned *copied)
1968{
1969 struct dmabuf *dmabuf = &s->dmabuf;
1970 void *src = hwsrc; /* default to the standard destination buffer addr */
1971
1972 CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO
1973 "cs_copy_to_user()+ fmt=0x%x cnt=%d dest=%p\n",
1974 dmabuf->fmt,(unsigned)cnt,dest) );
1975
Jesper Juhl2eebb192006-06-23 02:05:26 -07001976 if (cnt > dmabuf->dmasize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 cnt = dmabuf->dmasize;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001978 if (!cnt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 *copied = 0;
1980 return 0;
1981 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001982 if (dmabuf->divisor != 1) {
1983 if (!dmabuf->tmpbuff) {
1984 *copied = cnt / dmabuf->divisor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 return 0;
1986 }
1987
1988 CopySamples((char *)dmabuf->tmpbuff, (char *)hwsrc, cnt,
1989 dmabuf->fmt, dmabuf);
1990 src = dmabuf->tmpbuff;
1991 cnt = cnt/dmabuf->divisor;
1992 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001993 if (copy_to_user(dest, src, cnt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
1995 "cs46xx: cs_copy_to_user()- fault dest=%p src=%p cnt=%d\n",
Jesper Juhl2eebb192006-06-23 02:05:26 -07001996 dest,src,cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 *copied = 0;
1998 return -EFAULT;
1999 }
2000 *copied = cnt;
2001 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07002002 "cs46xx: cs_copy_to_user()- copied bytes is %d \n",cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 return 0;
2004}
2005
2006/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to
2007 the user's buffer. it is filled by the dma machine and drained by this loop. */
2008static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2009{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002010 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 struct cs_state *state;
2012 DECLARE_WAITQUEUE(wait, current);
2013 struct dmabuf *dmabuf;
2014 ssize_t ret = 0;
2015 unsigned long flags;
2016 unsigned swptr;
2017 int cnt;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002018 unsigned copied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019
2020 CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
2021 printk("cs46xx: cs_read()+ %zd\n",count) );
Jesper Juhl2eebb192006-06-23 02:05:26 -07002022 state = card->states[0];
2023 if (!state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 return -ENODEV;
2025 dmabuf = &state->dmabuf;
2026
2027 if (dmabuf->mapped)
2028 return -ENXIO;
2029 if (!access_ok(VERIFY_WRITE, buffer, count))
2030 return -EFAULT;
2031
Ingo Molnar910f5d22006-03-23 03:00:39 -08002032 mutex_lock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
2034 goto out2;
2035
2036 add_wait_queue(&state->dmabuf.wait, &wait);
2037 while (count > 0) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002038 while (!(card->pm.flags & CS46XX_PM_IDLE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 schedule();
2040 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002041 if (!ret)
2042 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 goto out;
2044 }
2045 }
2046 spin_lock_irqsave(&state->card->lock, flags);
2047 swptr = dmabuf->swptr;
2048 cnt = dmabuf->dmasize - swptr;
2049 if (dmabuf->count < cnt)
2050 cnt = dmabuf->count;
2051 if (cnt <= 0)
2052 __set_current_state(TASK_INTERRUPTIBLE);
2053 spin_unlock_irqrestore(&state->card->lock, flags);
2054
2055 if (cnt > (count * dmabuf->divisor))
2056 cnt = count * dmabuf->divisor;
2057 if (cnt <= 0) {
2058 /* buffer is empty, start the dma machine and wait for data to be
2059 recorded */
2060 start_adc(state);
2061 if (file->f_flags & O_NONBLOCK) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002062 if (!ret)
2063 ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 goto out;
2065 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002066 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 schedule();
2068 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002069 if (!ret)
2070 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 goto out;
2072 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002073 mutex_lock(&state->sem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002074 if (dmabuf->mapped) {
2075 if (!ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 ret = -ENXIO;
2077 goto out;
2078 }
2079 continue;
2080 }
2081
2082 CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
2083 "_read() copy_to cnt=%d count=%zd ", cnt,count) );
2084 CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
2085 " .dmasize=%d .count=%d buffer=%p ret=%zd\n",
Jesper Juhl2eebb192006-06-23 02:05:26 -07002086 dmabuf->dmasize,dmabuf->count,buffer,ret));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087
2088 if (cs_copy_to_user(state, buffer,
Jesper Juhl2eebb192006-06-23 02:05:26 -07002089 (char *)dmabuf->rawbuf + swptr, cnt, &copied)) {
2090 if (!ret)
2091 ret = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 goto out;
2093 }
2094 swptr = (swptr + cnt) % dmabuf->dmasize;
2095 spin_lock_irqsave(&card->lock, flags);
2096 dmabuf->swptr = swptr;
2097 dmabuf->count -= cnt;
2098 spin_unlock_irqrestore(&card->lock, flags);
2099 count -= copied;
2100 buffer += copied;
2101 ret += copied;
2102 start_adc(state);
2103 }
2104out:
2105 remove_wait_queue(&state->dmabuf.wait, &wait);
2106out2:
Ingo Molnar910f5d22006-03-23 03:00:39 -08002107 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 set_current_state(TASK_RUNNING);
2109 CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
2110 printk("cs46xx: cs_read()- %zd\n",ret) );
2111 return ret;
2112}
2113
2114/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
2115 the soundcard. it is drained by the dma machine and filled by this loop. */
2116static ssize_t cs_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
2117{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002118 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 struct cs_state *state;
2120 DECLARE_WAITQUEUE(wait, current);
2121 struct dmabuf *dmabuf;
2122 ssize_t ret;
2123 unsigned long flags;
2124 unsigned swptr;
2125 int cnt;
2126
2127 CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 4,
2128 printk("cs46xx: cs_write called, count = %zd\n", count) );
Jesper Juhl2eebb192006-06-23 02:05:26 -07002129 state = card->states[1];
2130 if (!state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 return -ENODEV;
2132 if (!access_ok(VERIFY_READ, buffer, count))
2133 return -EFAULT;
2134 dmabuf = &state->dmabuf;
2135
Ingo Molnar910f5d22006-03-23 03:00:39 -08002136 mutex_lock(&state->sem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002137 if (dmabuf->mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 ret = -ENXIO;
2139 goto out;
2140 }
2141
2142 if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
2143 goto out;
2144 add_wait_queue(&state->dmabuf.wait, &wait);
2145 ret = 0;
2146/*
2147* Start the loop to read from the user's buffer and write to the dma buffer.
2148* check for PM events and underrun/overrun in the loop.
2149*/
2150 while (count > 0) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002151 while (!(card->pm.flags & CS46XX_PM_IDLE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 schedule();
2153 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002154 if (!ret)
2155 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 goto out;
2157 }
2158 }
2159 spin_lock_irqsave(&state->card->lock, flags);
2160 if (dmabuf->count < 0) {
2161 /* buffer underrun, we are recovering from sleep_on_timeout,
2162 resync hwptr and swptr */
2163 dmabuf->count = 0;
2164 dmabuf->swptr = dmabuf->hwptr;
2165 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002166 if (dmabuf->underrun) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 dmabuf->underrun = 0;
2168 dmabuf->hwptr = cs_get_dma_addr(state);
2169 dmabuf->swptr = dmabuf->hwptr;
2170 }
2171
2172 swptr = dmabuf->swptr;
2173 cnt = dmabuf->dmasize - swptr;
2174 if (dmabuf->count + cnt > dmabuf->dmasize)
2175 cnt = dmabuf->dmasize - dmabuf->count;
2176 if (cnt <= 0)
2177 __set_current_state(TASK_INTERRUPTIBLE);
2178 spin_unlock_irqrestore(&state->card->lock, flags);
2179
2180 if (cnt > count)
2181 cnt = count;
2182 if (cnt <= 0) {
2183 /* buffer is full, start the dma machine and wait for data to be
2184 played */
2185 start_dac(state);
2186 if (file->f_flags & O_NONBLOCK) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002187 if (!ret)
2188 ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 goto out;
2190 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002191 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 schedule();
2193 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002194 if (!ret)
2195 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 goto out;
2197 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002198 mutex_lock(&state->sem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002199 if (dmabuf->mapped) {
2200 if (!ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 ret = -ENXIO;
2202 goto out;
2203 }
2204 continue;
2205 }
2206 if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002207 if (!ret)
2208 ret = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 goto out;
2210 }
2211 spin_lock_irqsave(&state->card->lock, flags);
2212 swptr = (swptr + cnt) % dmabuf->dmasize;
2213 dmabuf->swptr = swptr;
2214 dmabuf->count += cnt;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002215 if (dmabuf->count > dmabuf->dmasize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 CS_DBGOUT(CS_WAVE_WRITE | CS_ERROR, 2, printk(
2217 "cs46xx: cs_write() d->count > dmasize - resetting\n"));
2218 dmabuf->count = dmabuf->dmasize;
2219 }
2220 dmabuf->endcleared = 0;
2221 spin_unlock_irqrestore(&state->card->lock, flags);
2222
2223 count -= cnt;
2224 buffer += cnt;
2225 ret += cnt;
2226 start_dac(state);
2227 }
2228out:
Ingo Molnar910f5d22006-03-23 03:00:39 -08002229 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 remove_wait_queue(&state->dmabuf.wait, &wait);
2231 set_current_state(TASK_RUNNING);
2232
2233 CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 2,
Jesper Juhl2eebb192006-06-23 02:05:26 -07002234 printk("cs46xx: cs_write()- ret=%zd\n", ret));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 return ret;
2236}
2237
2238static unsigned int cs_poll(struct file *file, struct poll_table_struct *wait)
2239{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002240 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 struct dmabuf *dmabuf;
2242 struct cs_state *state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 unsigned long flags;
2244 unsigned int mask = 0;
2245
2246 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()+ \n"));
Jesper Juhl2eebb192006-06-23 02:05:26 -07002247 if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 return -EINVAL;
2249 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002250 if (file->f_mode & FMODE_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002252 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 dmabuf = &state->dmabuf;
2254 poll_wait(file, &dmabuf->wait, wait);
2255 }
2256 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002257 if (file->f_mode & FMODE_READ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002259 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 dmabuf = &state->dmabuf;
2261 poll_wait(file, &dmabuf->wait, wait);
2262 }
2263 }
2264
2265 spin_lock_irqsave(&card->lock, flags);
2266 cs_update_ptr(card, CS_FALSE);
2267 if (file->f_mode & FMODE_READ) {
2268 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002269 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 dmabuf = &state->dmabuf;
2271 if (dmabuf->count >= (signed)dmabuf->fragsize)
2272 mask |= POLLIN | POLLRDNORM;
2273 }
2274 }
2275 if (file->f_mode & FMODE_WRITE) {
2276 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002277 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 dmabuf = &state->dmabuf;
2279 if (dmabuf->mapped) {
2280 if (dmabuf->count >= (signed)dmabuf->fragsize)
2281 mask |= POLLOUT | POLLWRNORM;
2282 } else {
2283 if ((signed)dmabuf->dmasize >= dmabuf->count
2284 + (signed)dmabuf->fragsize)
2285 mask |= POLLOUT | POLLWRNORM;
2286 }
2287 }
2288 }
2289 spin_unlock_irqrestore(&card->lock, flags);
2290
2291 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()- (0x%x) \n",
2292 mask));
2293 return mask;
2294}
2295
2296/*
2297 * We let users mmap the ring buffer. Its not the real DMA buffer but
2298 * that side of the code is hidden in the IRQ handling. We do a software
2299 * emulation of DMA from a 64K or so buffer into a 2K FIFO.
2300 * (the hardware probably deserves a moan here but Crystal send me nice
2301 * toys ;)).
2302 */
2303
2304static int cs_mmap(struct file *file, struct vm_area_struct *vma)
2305{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002306 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 struct cs_state *state;
2308 struct dmabuf *dmabuf;
2309 int ret = 0;
2310 unsigned long size;
2311
2312 CS_DBGOUT(CS_FUNCTION | CS_PARMS, 2, printk("cs46xx: cs_mmap()+ file=%p %s %s\n",
2313 file, vma->vm_flags & VM_WRITE ? "VM_WRITE" : "",
2314 vma->vm_flags & VM_READ ? "VM_READ" : "") );
2315
2316 if (vma->vm_flags & VM_WRITE) {
2317 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002318 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 CS_DBGOUT(CS_OPEN, 2, printk(
2320 "cs46xx: cs_mmap() VM_WRITE - state TRUE prog_dmabuf DAC\n") );
2321 if ((ret = prog_dmabuf(state)) != 0)
2322 return ret;
2323 }
2324 } else if (vma->vm_flags & VM_READ) {
2325 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002326 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 CS_DBGOUT(CS_OPEN, 2, printk(
2328 "cs46xx: cs_mmap() VM_READ - state TRUE prog_dmabuf ADC\n") );
2329 if ((ret = prog_dmabuf(state)) != 0)
2330 return ret;
2331 }
2332 } else {
2333 CS_DBGOUT(CS_ERROR, 2, printk(
2334 "cs46xx: cs_mmap() return -EINVAL\n") );
2335 return -EINVAL;
2336 }
2337
2338/*
2339 * For now ONLY support playback, but seems like the only way to use
2340 * mmap() is to open an FD with RDWR, just read or just write access
2341 * does not function, get an error back from the kernel.
2342 * Also, QuakeIII opens with RDWR! So, there must be something
2343 * to needing read/write access mapping. So, allow read/write but
2344 * use the DAC only.
2345 */
2346 state = card->states[1];
2347 if (!state) {
2348 ret = -EINVAL;
2349 goto out;
2350 }
2351
Ingo Molnar910f5d22006-03-23 03:00:39 -08002352 mutex_lock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002354 if (cs4x_pgoff(vma) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 ret = -EINVAL;
2356 goto out;
2357 }
2358 size = vma->vm_end - vma->vm_start;
2359
2360 CS_DBGOUT(CS_PARMS, 2, printk("cs46xx: cs_mmap(): size=%d\n",(unsigned)size) );
2361
Jesper Juhl2eebb192006-06-23 02:05:26 -07002362 if (size > (PAGE_SIZE << dmabuf->buforder)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 ret = -EINVAL;
2364 goto out;
2365 }
2366 if (remap_pfn_range(vma, vma->vm_start,
2367 virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
Jesper Juhl2eebb192006-06-23 02:05:26 -07002368 size, vma->vm_page_prot)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 ret = -EAGAIN;
2370 goto out;
2371 }
2372 dmabuf->mapped = 1;
2373
2374 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mmap()-\n") );
2375out:
Ingo Molnar910f5d22006-03-23 03:00:39 -08002376 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 return ret;
2378}
2379
2380static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
2381{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002382 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 struct cs_state *state;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002384 struct dmabuf *dmabuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 unsigned long flags;
2386 audio_buf_info abinfo;
2387 count_info cinfo;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002388 int val, valsave, ret;
2389 int mapped = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 void __user *argp = (void __user *)arg;
2391 int __user *p = argp;
2392
Jesper Juhl2eebb192006-06-23 02:05:26 -07002393 state = card->states[0];
2394 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 dmabuf = &state->dmabuf;
2396 mapped = (file->f_mode & FMODE_READ) && dmabuf->mapped;
2397 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002398 state = card->states[1];
2399 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 dmabuf = &state->dmabuf;
2401 mapped |= (file->f_mode & FMODE_WRITE) && dmabuf->mapped;
2402 }
2403
2404#if CSDEBUG
2405 printioctl(cmd);
2406#endif
2407
Jesper Juhl2eebb192006-06-23 02:05:26 -07002408 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 case OSS_GETVERSION:
2410 return put_user(SOUND_VERSION, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 case SNDCTL_DSP_RESET:
2412 /* FIXME: spin_lock ? */
2413 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002414 state = card->states[1];
2415 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 dmabuf = &state->dmabuf;
2417 stop_dac(state);
2418 synchronize_irq(card->irq);
2419 dmabuf->ready = 0;
2420 resync_dma_ptrs(state);
2421 dmabuf->swptr = dmabuf->hwptr = 0;
2422 dmabuf->count = dmabuf->total_bytes = 0;
2423 dmabuf->blocks = 0;
2424 dmabuf->SGok = 0;
2425 }
2426 }
2427 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002428 state = card->states[0];
2429 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 dmabuf = &state->dmabuf;
2431 stop_adc(state);
2432 synchronize_irq(card->irq);
2433 resync_dma_ptrs(state);
2434 dmabuf->ready = 0;
2435 dmabuf->swptr = dmabuf->hwptr = 0;
2436 dmabuf->count = dmabuf->total_bytes = 0;
2437 dmabuf->blocks = 0;
2438 dmabuf->SGok = 0;
2439 }
2440 }
2441 CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_RESET()-\n") );
2442 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 case SNDCTL_DSP_SYNC:
2444 if (file->f_mode & FMODE_WRITE)
2445 return drain_dac(state, file->f_flags & O_NONBLOCK);
2446 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 case SNDCTL_DSP_SPEED: /* set sample rate */
2448 if (get_user(val, p))
2449 return -EFAULT;
2450 if (val >= 0) {
2451 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002452 state = card->states[0];
2453 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 dmabuf = &state->dmabuf;
2455 stop_adc(state);
2456 dmabuf->ready = 0;
2457 dmabuf->SGok = 0;
2458 cs_set_adc_rate(state, val);
2459 cs_set_divisor(dmabuf);
2460 }
2461 }
2462 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002463 state = card->states[1];
2464 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 dmabuf = &state->dmabuf;
2466 stop_dac(state);
2467 dmabuf->ready = 0;
2468 dmabuf->SGok = 0;
2469 cs_set_dac_rate(state, val);
2470 cs_set_divisor(dmabuf);
2471 }
2472 }
2473 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2474 "cs46xx: cs_ioctl() DSP_SPEED %s %s %d\n",
2475 file->f_mode & FMODE_WRITE ? "DAC" : "",
2476 file->f_mode & FMODE_READ ? "ADC" : "",
2477 dmabuf->rate ) );
2478 return put_user(dmabuf->rate, p);
2479 }
2480 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
2482 if (get_user(val, p))
2483 return -EFAULT;
2484 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002485 state = card->states[1];
2486 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 dmabuf = &state->dmabuf;
2488 stop_dac(state);
2489 dmabuf->ready = 0;
2490 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002491 if (val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 dmabuf->fmt |= CS_FMT_STEREO;
2493 else
2494 dmabuf->fmt &= ~CS_FMT_STEREO;
2495 cs_set_divisor(dmabuf);
2496 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2497 "cs46xx: DSP_STEREO() DAC %s\n",
2498 (dmabuf->fmt & CS_FMT_STEREO) ?
2499 "STEREO":"MONO") );
2500 }
2501 }
2502 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002503 state = card->states[0];
2504 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 dmabuf = &state->dmabuf;
2506 stop_adc(state);
2507 dmabuf->ready = 0;
2508 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002509 if (val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 dmabuf->fmt |= CS_FMT_STEREO;
2511 else
2512 dmabuf->fmt &= ~CS_FMT_STEREO;
2513 cs_set_divisor(dmabuf);
2514 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2515 "cs46xx: DSP_STEREO() ADC %s\n",
2516 (dmabuf->fmt & CS_FMT_STEREO) ?
2517 "STEREO":"MONO") );
2518 }
2519 }
2520 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 case SNDCTL_DSP_GETBLKSIZE:
2522 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002523 state = card->states[1];
2524 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 dmabuf = &state->dmabuf;
2526 if ((val = prog_dmabuf(state)))
2527 return val;
2528 return put_user(dmabuf->fragsize, p);
2529 }
2530 }
2531 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002532 state = card->states[0];
2533 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 dmabuf = &state->dmabuf;
2535 if ((val = prog_dmabuf(state)))
2536 return val;
2537 return put_user(dmabuf->fragsize/dmabuf->divisor,
2538 p);
2539 }
2540 }
2541 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
2543 return put_user(AFMT_S16_LE | AFMT_U8, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 case SNDCTL_DSP_SETFMT: /* Select sample format */
2545 if (get_user(val, p))
2546 return -EFAULT;
2547 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2548 "cs46xx: cs_ioctl() DSP_SETFMT %s %s %s %s\n",
2549 file->f_mode & FMODE_WRITE ? "DAC" : "",
2550 file->f_mode & FMODE_READ ? "ADC" : "",
2551 val == AFMT_S16_LE ? "16Bit Signed" : "",
2552 val == AFMT_U8 ? "8Bit Unsigned" : "") );
2553 valsave = val;
2554 if (val != AFMT_QUERY) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002555 if (val==AFMT_S16_LE || val==AFMT_U8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002557 state = card->states[1];
2558 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 dmabuf = &state->dmabuf;
2560 stop_dac(state);
2561 dmabuf->ready = 0;
2562 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002563 if (val == AFMT_S16_LE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 dmabuf->fmt |= CS_FMT_16BIT;
2565 else
2566 dmabuf->fmt &= ~CS_FMT_16BIT;
2567 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002568 if ((ret = prog_dmabuf(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 return ret;
2570 }
2571 }
2572 if (file->f_mode & FMODE_READ) {
2573 val = valsave;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002574 state = card->states[0];
2575 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 dmabuf = &state->dmabuf;
2577 stop_adc(state);
2578 dmabuf->ready = 0;
2579 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002580 if (val == AFMT_S16_LE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 dmabuf->fmt |= CS_FMT_16BIT;
2582 else
2583 dmabuf->fmt &= ~CS_FMT_16BIT;
2584 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002585 if ((ret = prog_dmabuf(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 return ret;
2587 }
2588 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002589 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 CS_DBGOUT(CS_IOCTL | CS_ERROR, 2, printk(
2591 "cs46xx: DSP_SETFMT() Unsupported format (0x%x)\n",
2592 valsave) );
2593 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002594 } else {
2595 if (file->f_mode & FMODE_WRITE) {
2596 state = card->states[1];
2597 if (state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002599 } else if (file->f_mode & FMODE_READ) {
2600 state = card->states[0];
2601 if (state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 dmabuf = &state->dmabuf;
2603 }
2604 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002605 if (dmabuf) {
2606 if (dmabuf->fmt & CS_FMT_16BIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 return put_user(AFMT_S16_LE, p);
2608 else
2609 return put_user(AFMT_U8, p);
2610 }
2611 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 case SNDCTL_DSP_CHANNELS:
2613 if (get_user(val, p))
2614 return -EFAULT;
2615 if (val != 0) {
2616 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002617 state = card->states[1];
2618 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 dmabuf = &state->dmabuf;
2620 stop_dac(state);
2621 dmabuf->ready = 0;
2622 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002623 if (val > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 dmabuf->fmt |= CS_FMT_STEREO;
2625 else
2626 dmabuf->fmt &= ~CS_FMT_STEREO;
2627 cs_set_divisor(dmabuf);
2628 if (prog_dmabuf(state))
2629 return 0;
2630 }
2631 }
2632 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002633 state = card->states[0];
2634 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 dmabuf = &state->dmabuf;
2636 stop_adc(state);
2637 dmabuf->ready = 0;
2638 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002639 if (val > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 dmabuf->fmt |= CS_FMT_STEREO;
2641 else
2642 dmabuf->fmt &= ~CS_FMT_STEREO;
2643 cs_set_divisor(dmabuf);
2644 if (prog_dmabuf(state))
2645 return 0;
2646 }
2647 }
2648 }
2649 return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
2650 p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 case SNDCTL_DSP_POST:
2652 /*
2653 * There will be a longer than normal pause in the data.
2654 * so... do nothing, because there is nothing that we can do.
2655 */
2656 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 case SNDCTL_DSP_SUBDIVIDE:
2658 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002659 state = card->states[1];
2660 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 dmabuf = &state->dmabuf;
2662 if (dmabuf->subdivision)
2663 return -EINVAL;
2664 if (get_user(val, p))
2665 return -EFAULT;
2666 if (val != 1 && val != 2)
2667 return -EINVAL;
2668 dmabuf->subdivision = val;
2669 }
2670 }
2671 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002672 state = card->states[0];
2673 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 dmabuf = &state->dmabuf;
2675 if (dmabuf->subdivision)
2676 return -EINVAL;
2677 if (get_user(val, p))
2678 return -EFAULT;
2679 if (val != 1 && val != 2)
2680 return -EINVAL;
2681 dmabuf->subdivision = val;
2682 }
2683 }
2684 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 case SNDCTL_DSP_SETFRAGMENT:
2686 if (get_user(val, p))
2687 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002689 state = card->states[1];
2690 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 dmabuf = &state->dmabuf;
2692 dmabuf->ossfragshift = val & 0xffff;
2693 dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
2694 }
2695 }
2696 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002697 state = card->states[0];
2698 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 dmabuf = &state->dmabuf;
2700 dmabuf->ossfragshift = val & 0xffff;
2701 dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
2702 }
2703 }
2704 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 case SNDCTL_DSP_GETOSPACE:
2706 if (!(file->f_mode & FMODE_WRITE))
2707 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002708 state = card->states[1];
2709 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 dmabuf = &state->dmabuf;
2711 spin_lock_irqsave(&state->card->lock, flags);
2712 cs_update_ptr(card, CS_TRUE);
2713 abinfo.fragsize = dmabuf->fragsize;
2714 abinfo.fragstotal = dmabuf->numfrag;
2715 /*
2716 * for mmap we always have total space available
2717 */
2718 if (dmabuf->mapped)
2719 abinfo.bytes = dmabuf->dmasize;
2720 else
2721 abinfo.bytes = dmabuf->dmasize - dmabuf->count;
2722
2723 abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
2724 spin_unlock_irqrestore(&state->card->lock, flags);
2725 return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
2726 }
2727 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 case SNDCTL_DSP_GETISPACE:
2729 if (!(file->f_mode & FMODE_READ))
2730 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002731 state = card->states[0];
2732 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 dmabuf = &state->dmabuf;
2734 spin_lock_irqsave(&state->card->lock, flags);
2735 cs_update_ptr(card, CS_TRUE);
2736 abinfo.fragsize = dmabuf->fragsize/dmabuf->divisor;
2737 abinfo.bytes = dmabuf->count/dmabuf->divisor;
2738 abinfo.fragstotal = dmabuf->numfrag;
2739 abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
2740 spin_unlock_irqrestore(&state->card->lock, flags);
2741 return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
2742 }
2743 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 case SNDCTL_DSP_NONBLOCK:
2745 file->f_flags |= O_NONBLOCK;
2746 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 case SNDCTL_DSP_GETCAPS:
2748 return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
2749 p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 case SNDCTL_DSP_GETTRIGGER:
2751 val = 0;
2752 CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()+\n") );
Jesper Juhl2eebb192006-06-23 02:05:26 -07002753 if (file->f_mode & FMODE_WRITE) {
2754 state = card->states[1];
2755 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002757 if (dmabuf->enable & DAC_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 val |= PCM_ENABLE_INPUT;
2759 }
2760 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002761 if (file->f_mode & FMODE_READ) {
2762 if (state) {
2763 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002765 if (dmabuf->enable & ADC_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 val |= PCM_ENABLE_OUTPUT;
2767 }
2768 }
2769 CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()- val=0x%x\n",val) );
2770 return put_user(val, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 case SNDCTL_DSP_SETTRIGGER:
2772 if (get_user(val, p))
2773 return -EFAULT;
2774 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002775 state = card->states[0];
2776 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 dmabuf = &state->dmabuf;
2778 if (val & PCM_ENABLE_INPUT) {
2779 if (!dmabuf->ready && (ret = prog_dmabuf(state)))
2780 return ret;
2781 start_adc(state);
2782 } else
2783 stop_adc(state);
2784 }
2785 }
2786 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002787 state = card->states[1];
2788 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 dmabuf = &state->dmabuf;
2790 if (val & PCM_ENABLE_OUTPUT) {
2791 if (!dmabuf->ready && (ret = prog_dmabuf(state)))
2792 return ret;
2793 start_dac(state);
2794 } else
2795 stop_dac(state);
2796 }
2797 }
2798 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 case SNDCTL_DSP_GETIPTR:
2800 if (!(file->f_mode & FMODE_READ))
2801 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002802 state = card->states[0];
2803 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 dmabuf = &state->dmabuf;
2805 spin_lock_irqsave(&state->card->lock, flags);
2806 cs_update_ptr(card, CS_TRUE);
2807 cinfo.bytes = dmabuf->total_bytes/dmabuf->divisor;
2808 cinfo.blocks = dmabuf->count/dmabuf->divisor >> dmabuf->fragshift;
2809 cinfo.ptr = dmabuf->hwptr/dmabuf->divisor;
2810 spin_unlock_irqrestore(&state->card->lock, flags);
2811 if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
2812 return -EFAULT;
2813 return 0;
2814 }
2815 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 case SNDCTL_DSP_GETOPTR:
2817 if (!(file->f_mode & FMODE_WRITE))
2818 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002819 state = card->states[1];
2820 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 dmabuf = &state->dmabuf;
2822 spin_lock_irqsave(&state->card->lock, flags);
2823 cs_update_ptr(card, CS_TRUE);
2824 cinfo.bytes = dmabuf->total_bytes;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002825 if (dmabuf->mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 cinfo.blocks = (cinfo.bytes >> dmabuf->fragshift)
2827 - dmabuf->blocks;
2828 CS_DBGOUT(CS_PARMS, 8,
2829 printk("total_bytes=%d blocks=%d dmabuf->blocks=%d\n",
2830 cinfo.bytes,cinfo.blocks,dmabuf->blocks) );
2831 dmabuf->blocks = cinfo.bytes >> dmabuf->fragshift;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002832 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
2834 }
2835 cinfo.ptr = dmabuf->hwptr;
2836
2837 CS_DBGOUT(CS_PARMS, 4, printk(
2838 "cs46xx: GETOPTR bytes=%d blocks=%d ptr=%d\n",
2839 cinfo.bytes,cinfo.blocks,cinfo.ptr) );
2840 spin_unlock_irqrestore(&state->card->lock, flags);
2841 if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
2842 return -EFAULT;
2843 return 0;
2844 }
2845 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 case SNDCTL_DSP_SETDUPLEX:
2847 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 case SNDCTL_DSP_GETODELAY:
2849 if (!(file->f_mode & FMODE_WRITE))
2850 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002851 state = card->states[1];
2852 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 dmabuf = &state->dmabuf;
2854 spin_lock_irqsave(&state->card->lock, flags);
2855 cs_update_ptr(card, CS_TRUE);
2856 val = dmabuf->count;
2857 spin_unlock_irqrestore(&state->card->lock, flags);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002858 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 val = 0;
2860 return put_user(val, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 case SOUND_PCM_READ_RATE:
Jesper Juhl2eebb192006-06-23 02:05:26 -07002862 if (file->f_mode & FMODE_READ)
2863 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07002865 state = card->states[1];
2866 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 dmabuf = &state->dmabuf;
2868 return put_user(dmabuf->rate, p);
2869 }
2870 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 case SOUND_PCM_READ_CHANNELS:
Jesper Juhl2eebb192006-06-23 02:05:26 -07002872 if (file->f_mode & FMODE_READ)
2873 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07002875 state = card->states[1];
2876 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 dmabuf = &state->dmabuf;
2878 return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
2879 p);
2880 }
2881 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 case SOUND_PCM_READ_BITS:
Jesper Juhl2eebb192006-06-23 02:05:26 -07002883 if (file->f_mode & FMODE_READ)
2884 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07002886 state = card->states[1];
2887 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 dmabuf = &state->dmabuf;
2889 return put_user((dmabuf->fmt & CS_FMT_16BIT) ?
2890 AFMT_S16_LE : AFMT_U8, p);
2891
2892 }
2893 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 case SNDCTL_DSP_MAPINBUF:
2895 case SNDCTL_DSP_MAPOUTBUF:
2896 case SNDCTL_DSP_SETSYNCRO:
2897 case SOUND_PCM_WRITE_FILTER:
2898 case SOUND_PCM_READ_FILTER:
2899 return -EINVAL;
2900 }
2901 return -EINVAL;
2902}
2903
2904
2905/*
2906 * AMP control - null AMP
2907 */
2908
2909static void amp_none(struct cs_card *card, int change)
2910{
2911}
2912
2913/*
2914 * Crystal EAPD mode
2915 */
2916
2917static void amp_voyetra(struct cs_card *card, int change)
2918{
2919 /* Manage the EAPD bit on the Crystal 4297
2920 and the Analog AD1885 */
2921
Jesper Juhl2eebb192006-06-23 02:05:26 -07002922 int old = card->amplifier;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
2924 card->amplifier+=change;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002925 if (card->amplifier && !old) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 /* Turn the EAPD amp on */
2927 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL,
2928 cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) |
2929 0x8000);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002930 } else if(old && !card->amplifier) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 /* Turn the EAPD amp off */
2932 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL,
2933 cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
2934 ~0x8000);
2935 }
2936}
2937
2938
2939/*
2940 * Game Theatre XP card - EGPIO[2] is used to enable the external amp.
2941 */
2942
2943static void amp_hercules(struct cs_card *card, int change)
2944{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002945 int old = card->amplifier;
2946 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
2948 "cs46xx: amp_hercules() called before initialized.\n"));
2949 return;
2950 }
2951 card->amplifier+=change;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002952 if ((card->amplifier && !old) && !(hercules_egpio_disable)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO
2954 "cs46xx: amp_hercules() external amp enabled\n"));
2955 cs461x_pokeBA0(card, BA0_EGPIODR,
2956 EGPIODR_GPOE2); /* enable EGPIO2 output */
2957 cs461x_pokeBA0(card, BA0_EGPIOPTR,
2958 EGPIOPTR_GPPT2); /* open-drain on output */
Jesper Juhl2eebb192006-06-23 02:05:26 -07002959 } else if (old && !card->amplifier) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO
2961 "cs46xx: amp_hercules() external amp disabled\n"));
2962 cs461x_pokeBA0(card, BA0_EGPIODR, 0); /* disable */
2963 cs461x_pokeBA0(card, BA0_EGPIOPTR, 0); /* disable */
2964 }
2965}
2966
2967/*
2968 * Handle the CLKRUN on a thinkpad. We must disable CLKRUN support
2969 * whenever we need to beat on the chip.
2970 *
2971 * The original idea and code for this hack comes from David Kaiser at
2972 * Linuxcare. Perhaps one day Crystal will document their chips well
2973 * enough to make them useful.
2974 */
2975
2976static void clkrun_hack(struct cs_card *card, int change)
2977{
2978 struct pci_dev *acpi_dev;
2979 u16 control;
2980 u8 pp;
2981 unsigned long port;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002982 int old = card->active;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983
2984 card->active+=change;
2985
Alan Coxa78b4642006-09-30 23:27:27 -07002986 acpi_dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002987 if (acpi_dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 return; /* Not a thinkpad thats for sure */
2989
2990 /* Find the control port */
2991 pci_read_config_byte(acpi_dev, 0x41, &pp);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002992 port = pp << 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993
2994 /* Read ACPI port */
Jesper Juhl2eebb192006-06-23 02:05:26 -07002995 control = inw(port + 0x10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996
2997 /* Flip CLKRUN off while running */
Jesper Juhl2eebb192006-06-23 02:05:26 -07002998 if (!card->active && old) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
3000 "cs46xx: clkrun() enable clkrun - change=%d active=%d\n",
3001 change,card->active));
3002 outw(control|0x2000, port+0x10);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003003 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 /*
3005 * sometimes on a resume the bit is set, so always reset the bit.
3006 */
3007 CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
3008 "cs46xx: clkrun() disable clkrun - change=%d active=%d\n",
3009 change,card->active));
3010 outw(control&~0x2000, port+0x10);
3011 }
Alan Coxa78b4642006-09-30 23:27:27 -07003012 pci_dev_put(acpi_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013}
3014
3015
3016static int cs_open(struct inode *inode, struct file *file)
3017{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003018 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 struct cs_state *state = NULL;
3020 struct dmabuf *dmabuf = NULL;
3021 struct list_head *entry;
3022 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003023 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 unsigned int tmp;
3025
3026 CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()+ file=%p %s %s\n",
3027 file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
3028 file->f_mode & FMODE_READ ? "FMODE_READ" : "") );
3029
Jesper Juhl2eebb192006-06-23 02:05:26 -07003030 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 card = list_entry(entry, struct cs_card, list);
3032
3033 if (!((card->dev_audio ^ minor) & ~0xf))
3034 break;
3035 }
3036 if (entry == &cs46xx_devs)
3037 return -ENODEV;
3038 if (!card) {
3039 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
3040 "cs46xx: cs_open(): Error - unable to find audio card struct\n"));
3041 return -ENODEV;
3042 }
3043
3044 /*
3045 * hardcode state[0] for capture, [1] for playback
3046 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003047 if (file->f_mode & FMODE_READ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 CS_DBGOUT(CS_WAVE_READ, 2, printk("cs46xx: cs_open() FMODE_READ\n") );
3049 if (card->states[0] == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003050 state = card->states[0] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 kmalloc(sizeof(struct cs_state), GFP_KERNEL);
3052 if (state == NULL)
3053 return -ENOMEM;
3054 memset(state, 0, sizeof(struct cs_state));
Ingo Molnar910f5d22006-03-23 03:00:39 -08003055 mutex_init(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 dmabuf = &state->dmabuf;
3057 dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003058 if (dmabuf->pbuf == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 kfree(state);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003060 card->states[0] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 return -ENOMEM;
3062 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003063 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003065 if (state->open_mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 return -EBUSY;
3067 }
3068 dmabuf->channel = card->alloc_rec_pcm_channel(card);
3069
3070 if (dmabuf->channel == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003071 kfree(card->states[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 card->states[0] = NULL;
3073 return -ENODEV;
3074 }
3075
3076 /* Now turn on external AMP if needed */
3077 state->card = card;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003078 state->card->active_ctrl(state->card, 1);
3079 state->card->amplifier_ctrl(state->card, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
Jesper Juhl2eebb192006-06-23 02:05:26 -07003081 if ((tmp = cs46xx_powerup(card, CS_POWER_ADC))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003083 "cs46xx: cs46xx_powerup of ADC failed (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 return -EIO;
3085 }
3086
3087 dmabuf->channel->state = state;
3088 /* initialize the virtual channel */
3089 state->virt = 0;
3090 state->magic = CS_STATE_MAGIC;
3091 init_waitqueue_head(&dmabuf->wait);
Ingo Molnar910f5d22006-03-23 03:00:39 -08003092 mutex_init(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 file->private_data = card;
3094
Ingo Molnar910f5d22006-03-23 03:00:39 -08003095 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
3097 /* set default sample format. According to OSS Programmer's Guide /dev/dsp
3098 should be default to unsigned 8-bits, mono, with sample rate 8kHz and
3099 /dev/dspW will accept 16-bits sample */
3100
3101 /* Default input is 8bit mono */
3102 dmabuf->fmt &= ~CS_FMT_MASK;
3103 dmabuf->type = CS_TYPE_ADC;
3104 dmabuf->ossfragshift = 0;
3105 dmabuf->ossmaxfrags = 0;
3106 dmabuf->subdivision = 0;
3107 cs_set_adc_rate(state, 8000);
3108 cs_set_divisor(dmabuf);
3109
3110 state->open_mode |= FMODE_READ;
Ingo Molnar910f5d22006-03-23 03:00:39 -08003111 mutex_unlock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003113 if (file->f_mode & FMODE_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 CS_DBGOUT(CS_OPEN, 2, printk("cs46xx: cs_open() FMODE_WRITE\n") );
3115 if (card->states[1] == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003116 state = card->states[1] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 kmalloc(sizeof(struct cs_state), GFP_KERNEL);
3118 if (state == NULL)
3119 return -ENOMEM;
3120 memset(state, 0, sizeof(struct cs_state));
Ingo Molnar910f5d22006-03-23 03:00:39 -08003121 mutex_init(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 dmabuf = &state->dmabuf;
3123 dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003124 if (dmabuf->pbuf == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 kfree(state);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003126 card->states[1] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 return -ENOMEM;
3128 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003129 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003131 if (state->open_mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 return -EBUSY;
3133 }
3134 dmabuf->channel = card->alloc_pcm_channel(card);
3135
3136 if (dmabuf->channel == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003137 kfree(card->states[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 card->states[1] = NULL;
3139 return -ENODEV;
3140 }
3141
3142 /* Now turn on external AMP if needed */
3143 state->card = card;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003144 state->card->active_ctrl(state->card, 1);
3145 state->card->amplifier_ctrl(state->card, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146
Jesper Juhl2eebb192006-06-23 02:05:26 -07003147 if ((tmp = cs46xx_powerup(card, CS_POWER_DAC))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003149 "cs46xx: cs46xx_powerup of DAC failed (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 return -EIO;
3151 }
3152
3153 dmabuf->channel->state = state;
3154 /* initialize the virtual channel */
3155 state->virt = 1;
3156 state->magic = CS_STATE_MAGIC;
3157 init_waitqueue_head(&dmabuf->wait);
Ingo Molnar910f5d22006-03-23 03:00:39 -08003158 mutex_init(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003159 file->private_data = card;
3160
Ingo Molnar910f5d22006-03-23 03:00:39 -08003161 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
3163 /* set default sample format. According to OSS Programmer's Guide /dev/dsp
3164 should be default to unsigned 8-bits, mono, with sample rate 8kHz and
3165 /dev/dspW will accept 16-bits sample */
3166
3167 /* Default output is 8bit mono. */
3168 dmabuf->fmt &= ~CS_FMT_MASK;
3169 dmabuf->type = CS_TYPE_DAC;
3170 dmabuf->ossfragshift = 0;
3171 dmabuf->ossmaxfrags = 0;
3172 dmabuf->subdivision = 0;
3173 cs_set_dac_rate(state, 8000);
3174 cs_set_divisor(dmabuf);
3175
3176 state->open_mode |= FMODE_WRITE;
Ingo Molnar910f5d22006-03-23 03:00:39 -08003177 mutex_unlock(&state->open_mutex);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003178 if ((ret = prog_dmabuf(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 return ret;
3180 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003181 CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()- 0\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182 return nonseekable_open(inode, file);
3183}
3184
3185static int cs_release(struct inode *inode, struct file *file)
3186{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003187 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 struct dmabuf *dmabuf;
3189 struct cs_state *state;
3190 unsigned int tmp;
3191 CS_DBGOUT(CS_RELEASE | CS_FUNCTION, 2, printk("cs46xx: cs_release()+ file=%p %s %s\n",
3192 file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
Jesper Juhl2eebb192006-06-23 02:05:26 -07003193 file->f_mode & FMODE_READ ? "FMODE_READ" : ""));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
3195 if (!(file->f_mode & (FMODE_WRITE | FMODE_READ)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003198 if (state) {
3199 if ((state->open_mode & FMODE_WRITE) & (file->f_mode & FMODE_WRITE)) {
3200 CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_WRITE\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 dmabuf = &state->dmabuf;
3202 cs_clear_tail(state);
3203 drain_dac(state, file->f_flags & O_NONBLOCK);
3204 /* stop DMA state machine and free DMA buffers/channels */
Ingo Molnar910f5d22006-03-23 03:00:39 -08003205 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 stop_dac(state);
3207 dealloc_dmabuf(state);
3208 state->card->free_pcm_channel(state->card, dmabuf->channel->num);
3209 free_page((unsigned long)state->dmabuf.pbuf);
3210
Ingo Molnar910f5d22006-03-23 03:00:39 -08003211 /* we're covered by the open_mutex */
3212 mutex_unlock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 state->card->states[state->virt] = NULL;
3214 state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
3215
Jesper Juhl2eebb192006-06-23 02:05:26 -07003216 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
3218 "cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) );
3219 }
3220
3221 /* Now turn off external AMP if needed */
3222 state->card->amplifier_ctrl(state->card, -1);
3223 state->card->active_ctrl(state->card, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 kfree(state);
3225 }
3226 }
3227
3228 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003229 if (state) {
3230 if ((state->open_mode & FMODE_READ) & (file->f_mode & FMODE_READ)) {
3231 CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_READ\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 dmabuf = &state->dmabuf;
Ingo Molnar910f5d22006-03-23 03:00:39 -08003233 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 stop_adc(state);
3235 dealloc_dmabuf(state);
3236 state->card->free_pcm_channel(state->card, dmabuf->channel->num);
3237 free_page((unsigned long)state->dmabuf.pbuf);
3238
Ingo Molnar910f5d22006-03-23 03:00:39 -08003239 /* we're covered by the open_mutex */
3240 mutex_unlock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 state->card->states[state->virt] = NULL;
3242 state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
3243
Jesper Juhl2eebb192006-06-23 02:05:26 -07003244 if ((tmp = cs461x_powerdown(card, CS_POWER_ADC, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
3246 "cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) );
3247 }
3248
3249 /* Now turn off external AMP if needed */
3250 state->card->amplifier_ctrl(state->card, -1);
3251 state->card->active_ctrl(state->card, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 kfree(state);
3253 }
3254 }
3255
Jesper Juhl2eebb192006-06-23 02:05:26 -07003256 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk("cs46xx: cs_release()- 0\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 return 0;
3258}
3259
3260static void printpm(struct cs_card *s)
3261{
3262 CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
3263 CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
3264 (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue));
3265 CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n",
3266 s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue));
3267 CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n",
3268 s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue));
3269 CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n",
3270 s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue));
3271 CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n",
3272 s->pm.u32SSCR,s->pm.u32SRCSA));
3273 CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n",
3274 s->pm.u32DacASR,s->pm.u32AdcASR));
3275 CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n",
3276 s->pm.u32DacSR,s->pm.u32AdcSR));
3277 CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n",
3278 s->pm.u32MIDCR_Save));
3279 CS_DBGOUT(CS_PM, 9, printk("u32AC97_powerdown: 0x%x _general_purpose 0x%x\n",
3280 s->pm.u32AC97_powerdown,s->pm.u32AC97_general_purpose));
3281 CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume: 0x%x\n",
3282 s->pm.u32AC97_master_volume));
3283 CS_DBGOUT(CS_PM, 9, printk("u32AC97_headphone_volume: 0x%x\n",
3284 s->pm.u32AC97_headphone_volume));
3285 CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume_mono: 0x%x\n",
3286 s->pm.u32AC97_master_volume_mono));
3287 CS_DBGOUT(CS_PM, 9, printk("u32AC97_pcm_out_volume: 0x%x\n",
3288 s->pm.u32AC97_pcm_out_volume));
3289 CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_play: 0x%x dmabuf_count_play: %d\n",
3290 s->pm.dmabuf_swptr_play,s->pm.dmabuf_count_play));
3291 CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_capture: 0x%x dmabuf_count_capture: %d\n",
3292 s->pm.dmabuf_swptr_capture,s->pm.dmabuf_count_capture));
3293
3294}
3295
3296/****************************************************************************
3297*
3298* Suspend - save the ac97 regs, mute the outputs and power down the part.
3299*
3300****************************************************************************/
3301static void cs46xx_ac97_suspend(struct cs_card *card)
3302{
3303 int Count,i;
3304 struct ac97_codec *dev=card->ac97_codec[0];
3305 unsigned int tmp;
3306
3307 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n"));
3308
Jesper Juhl2eebb192006-06-23 02:05:26 -07003309 if (card->states[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 stop_dac(card->states[1]);
3311 resync_dma_ptrs(card->states[1]);
3312 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003313 if (card->states[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 stop_adc(card->states[0]);
3315 resync_dma_ptrs(card->states[0]);
3316 }
3317
Jesper Juhl2eebb192006-06-23 02:05:26 -07003318 for (Count = 0x2, i = 0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE)
3319 && (i < CS46XX_AC97_NUMBER_RESTORE_REGS);
3320 Count += 2, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 card->pm.ac97[i] = cs_ac97_get(dev, BA0_AC97_RESET + Count);
3322 }
3323/*
3324* Save the ac97 volume registers as well as the current powerdown state.
3325* Now, mute the all the outputs (master, headphone, and mono), as well
3326* as the PCM volume, in preparation for powering down the entire part.
3327 card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev,
3328 (u8)BA0_AC97_MASTER_VOLUME);
3329 card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev,
3330 (u8)BA0_AC97_HEADPHONE_VOLUME);
3331 card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev,
3332 (u8)BA0_AC97_MASTER_VOLUME_MONO);
3333 card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev,
3334 (u8)BA0_AC97_PCM_OUT_VOLUME);
3335*/
3336/*
3337* mute the outputs
3338*/
3339 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
3340 cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
3341 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
3342 cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
3343
3344/*
3345* save the registers that cause pops
3346*/
3347 card->pm.u32AC97_powerdown = (u32)cs_ac97_get(dev, (u8)AC97_POWER_CONTROL);
3348 card->pm.u32AC97_general_purpose = (u32)cs_ac97_get(dev, (u8)BA0_AC97_GENERAL_PURPOSE);
3349/*
3350* And power down everything on the AC97 codec.
3351* well, for now, only power down the DAC/ADC and MIXER VREFON components.
3352* trouble with removing VREF.
3353*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003354 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
3355 CS_POWER_MIXVON, CS_TRUE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003357 "cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 }
3359
3360 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()-\n"));
3361}
3362
3363/****************************************************************************
3364*
3365* Resume - power up the part and restore its registers..
3366*
3367****************************************************************************/
3368static void cs46xx_ac97_resume(struct cs_card *card)
3369{
3370 int Count,i;
3371 struct ac97_codec *dev=card->ac97_codec[0];
3372
3373 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()+\n"));
3374
3375/*
3376* First, we restore the state of the general purpose register. This
3377* contains the mic select (mic1 or mic2) and if we restore this after
3378* we restore the mic volume/boost state and mic2 was selected at
3379* suspend time, we will end up with a brief period of time where mic1
3380* is selected with the volume/boost settings for mic2, causing
3381* acoustic feedback. So we restore the general purpose register
3382* first, thereby getting the correct mic selected before we restore
3383* the mic volume/boost.
3384*/
3385 cs_ac97_set(dev, (u8)BA0_AC97_GENERAL_PURPOSE,
3386 (u16)card->pm.u32AC97_general_purpose);
3387/*
3388* Now, while the outputs are still muted, restore the state of power
3389* on the AC97 part.
3390*/
3391 cs_ac97_set(dev, (u8)BA0_AC97_POWERDOWN, (u16)card->pm.u32AC97_powerdown);
3392 mdelay(5 * cs_laptop_wait);
3393/*
3394* Restore just the first set of registers, from register number
3395* 0x02 to the register number that ulHighestRegToRestore specifies.
3396*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003397 for (Count = 0x2, i=0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE) &&
3398 (i < CS46XX_AC97_NUMBER_RESTORE_REGS); Count += 2, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 cs_ac97_set(dev, (u8)(BA0_AC97_RESET + Count), (u16)card->pm.ac97[i]);
3400 }
3401
3402 /* Check if we have to init the amplifier */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003403 if (card->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 card->amp_init(card);
3405
3406 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()-\n"));
3407}
3408
3409
3410static int cs46xx_restart_part(struct cs_card *card)
3411{
3412 struct dmabuf *dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003413
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3415 printk( "cs46xx: cs46xx_restart_part()+\n"));
Jesper Juhl2eebb192006-06-23 02:05:26 -07003416 if (card->states[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 dmabuf = &card->states[1]->dmabuf;
3418 dmabuf->ready = 0;
3419 resync_dma_ptrs(card->states[1]);
3420 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003421 if (__prog_dmabuf(card->states[1])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 CS_DBGOUT(CS_PM | CS_ERROR, 1,
3423 printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n"));
3424 return -1;
3425 }
3426 cs_set_dac_rate(card->states[1], dmabuf->rate);
3427 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003428 if (card->states[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 dmabuf = &card->states[0]->dmabuf;
3430 dmabuf->ready = 0;
3431 resync_dma_ptrs(card->states[0]);
3432 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003433 if (__prog_dmabuf(card->states[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 CS_DBGOUT(CS_PM | CS_ERROR, 1,
3435 printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n"));
3436 return -1;
3437 }
3438 cs_set_adc_rate(card->states[0], dmabuf->rate);
3439 }
3440 card->pm.flags |= CS46XX_PM_RESUMED;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003441 if (card->states[0])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 start_adc(card->states[0]);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003443 if (card->states[1])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 start_dac(card->states[1]);
3445
3446 card->pm.flags |= CS46XX_PM_IDLE;
3447 card->pm.flags &= ~(CS46XX_PM_SUSPENDING | CS46XX_PM_SUSPENDED
3448 | CS46XX_PM_RESUMING | CS46XX_PM_RESUMED);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003449 if (card->states[0])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 wake_up(&card->states[0]->dmabuf.wait);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003451 if (card->states[1])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003452 wake_up(&card->states[1]->dmabuf.wait);
3453
3454 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3455 printk( "cs46xx: cs46xx_restart_part()-\n"));
3456 return 0;
3457}
3458
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459static void cs461x_reset(struct cs_card *card);
3460static void cs461x_proc_stop(struct cs_card *card);
Pavel Machek3bfffd92005-04-16 15:25:37 -07003461static int cs46xx_suspend(struct cs_card *card, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462{
3463 unsigned int tmp;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003464
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3466 printk("cs46xx: cs46xx_suspend()+ flags=0x%x s=%p\n",
3467 (unsigned)card->pm.flags,card));
3468/*
3469* check the current state, only suspend if IDLE
3470*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003471 if (!(card->pm.flags & CS46XX_PM_IDLE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 CS_DBGOUT(CS_PM | CS_ERROR, 2,
3473 printk("cs46xx: cs46xx_suspend() unable to suspend, not IDLE\n"));
3474 return 1;
3475 }
3476 card->pm.flags &= ~CS46XX_PM_IDLE;
3477 card->pm.flags |= CS46XX_PM_SUSPENDING;
3478
3479 card->active_ctrl(card,1);
3480
3481 tmp = cs461x_peek(card, BA1_PFIE);
3482 tmp &= ~0x0000f03f;
3483 tmp |= 0x00000010;
3484 cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */
3485
3486 tmp = cs461x_peek(card, BA1_CIE);
3487 tmp &= ~0x0000003f;
3488 tmp |= 0x00000011;
3489 cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */
3490
3491 /*
3492 * Stop playback DMA.
3493 */
3494 tmp = cs461x_peek(card, BA1_PCTL);
3495 cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
3496
3497 /*
3498 * Stop capture DMA.
3499 */
3500 tmp = cs461x_peek(card, BA1_CCTL);
3501 cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
3502
Jesper Juhl2eebb192006-06-23 02:05:26 -07003503 if (card->states[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 card->pm.dmabuf_swptr_play = card->states[1]->dmabuf.swptr;
3505 card->pm.dmabuf_count_play = card->states[1]->dmabuf.count;
3506 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003507 if (card->states[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 card->pm.dmabuf_swptr_capture = card->states[0]->dmabuf.swptr;
3509 card->pm.dmabuf_count_capture = card->states[0]->dmabuf.count;
3510 }
3511
3512 cs46xx_ac97_suspend(card);
3513
3514 /*
3515 * Reset the processor.
3516 */
3517 cs461x_reset(card);
3518
3519 cs461x_proc_stop(card);
3520
3521 /*
3522 * Power down the DAC and ADC. For now leave the other areas on.
3523 */
3524 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x0300);
3525
3526 /*
3527 * Power down the PLL.
3528 */
3529 cs461x_pokeBA0(card, BA0_CLKCR1, 0);
3530
3531 /*
3532 * Turn off the Processor by turning off the software clock enable flag in
3533 * the clock control register.
3534 */
3535 tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE;
3536 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
3537
3538 card->active_ctrl(card,-1);
3539
3540 card->pm.flags &= ~CS46XX_PM_SUSPENDING;
3541 card->pm.flags |= CS46XX_PM_SUSPENDED;
3542
3543 printpm(card);
3544
3545 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3546 printk("cs46xx: cs46xx_suspend()- flags=0x%x\n",
3547 (unsigned)card->pm.flags));
3548 return 0;
3549}
3550
3551static int cs46xx_resume(struct cs_card *card)
3552{
3553 int i;
3554
3555 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3556 printk( "cs46xx: cs46xx_resume()+ flags=0x%x\n",
3557 (unsigned)card->pm.flags));
Jesper Juhl2eebb192006-06-23 02:05:26 -07003558 if (!(card->pm.flags & CS46XX_PM_SUSPENDED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 CS_DBGOUT(CS_PM | CS_ERROR, 2,
3560 printk("cs46xx: cs46xx_resume() unable to resume, not SUSPENDED\n"));
3561 return 1;
3562 }
3563 card->pm.flags |= CS46XX_PM_RESUMING;
3564 card->pm.flags &= ~CS46XX_PM_SUSPENDED;
3565 printpm(card);
3566 card->active_ctrl(card, 1);
3567
Jesper Juhl2eebb192006-06-23 02:05:26 -07003568 for (i = 0; i < 5; i++) {
3569 if (cs_hardware_init(card) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
3571 "cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n"));
3572 mdelay(10 * cs_laptop_wait);
3573 cs461x_reset(card);
3574 continue;
3575 }
3576 break;
3577 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003578 if (i >= 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
3580 "cs46xx: cs46xx_resume()- cs_hardware_init() failed, retried %d times.\n",i));
3581 return 0;
3582 }
3583
Jesper Juhl2eebb192006-06-23 02:05:26 -07003584 if (cs46xx_restart_part(card)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
3586 "cs46xx: cs46xx_resume(): cs46xx_restart_part() returned error\n"));
3587 }
3588
3589 card->active_ctrl(card, -1);
3590
3591 CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=0x%x\n",
3592 (unsigned)card->pm.flags));
3593 return 0;
3594}
3595
3596static /*const*/ struct file_operations cs461x_fops = {
3597 CS_OWNER CS_THIS_MODULE
3598 .llseek = no_llseek,
3599 .read = cs_read,
3600 .write = cs_write,
3601 .poll = cs_poll,
3602 .ioctl = cs_ioctl,
3603 .mmap = cs_mmap,
3604 .open = cs_open,
3605 .release = cs_release,
3606};
3607
3608/* Write AC97 codec registers */
3609
3610
3611static u16 _cs_ac97_get(struct ac97_codec *dev, u8 reg)
3612{
3613 struct cs_card *card = dev->private_data;
3614 int count,loopcnt;
3615 unsigned int tmp;
3616 u16 ret;
3617
3618 /*
3619 * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
3620 * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97
3621 * 3. Write ACCTL = Control Register = 460h for initiating the write
3622 * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
3623 * 5. if DCV not cleared, break and return error
3624 * 6. Read ACSTS = Status Register = 464h, check VSTS bit
3625 */
3626
3627 cs461x_peekBA0(card, BA0_ACSDA);
3628
3629 /*
3630 * Setup the AC97 control registers on the CS461x to send the
3631 * appropriate command to the AC97 to perform the read.
3632 * ACCAD = Command Address Register = 46Ch
3633 * ACCDA = Command Data Register = 470h
3634 * ACCTL = Control Register = 460h
3635 * set DCV - will clear when process completed
3636 * set CRW - Read command
3637 * set VFRM - valid frame enabled
3638 * set ESYN - ASYNC generation enabled
3639 * set RSTN - ARST# inactive, AC97 codec not reset
3640 */
3641
3642 cs461x_pokeBA0(card, BA0_ACCAD, reg);
3643 cs461x_pokeBA0(card, BA0_ACCDA, 0);
3644 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW |
3645 ACCTL_VFRM | ACCTL_ESYN |
3646 ACCTL_RSTN);
3647
3648
3649 /*
3650 * Wait for the read to occur.
3651 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003652 if (!(card->pm.flags & CS46XX_PM_IDLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 loopcnt = 2000;
3654 else
3655 loopcnt = 500 * cs_laptop_wait;
3656 loopcnt *= cs_laptop_wait;
3657 for (count = 0; count < loopcnt; count++) {
3658 /*
3659 * First, we want to wait for a short time.
3660 */
3661 udelay(10 * cs_laptop_wait);
3662 /*
3663 * Now, check to see if the read has completed.
3664 * ACCTL = 460h, DCV should be reset by now and 460h = 17h
3665 */
3666 if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV))
3667 break;
3668 }
3669
3670 /*
3671 * Make sure the read completed.
3672 */
3673 if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
3674 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
3675 "cs46xx: AC'97 read problem (ACCTL_DCV), reg = 0x%x returning 0xffff\n", reg));
3676 return 0xffff;
3677 }
3678
3679 /*
3680 * Wait for the valid status bit to go active.
3681 */
3682
Jesper Juhl2eebb192006-06-23 02:05:26 -07003683 if (!(card->pm.flags & CS46XX_PM_IDLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 loopcnt = 2000;
3685 else
3686 loopcnt = 1000;
3687 loopcnt *= cs_laptop_wait;
3688 for (count = 0; count < loopcnt; count++) {
3689 /*
3690 * Read the AC97 status register.
3691 * ACSTS = Status Register = 464h
3692 * VSTS - Valid Status
3693 */
3694 if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)
3695 break;
3696 udelay(10 * cs_laptop_wait);
3697 }
3698
3699 /*
3700 * Make sure we got valid status.
3701 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003702 if (!((tmp = cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 CS_DBGOUT(CS_ERROR, 2, printk(KERN_WARNING
3704 "cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x 0xffff \n",
3705 reg, tmp));
3706 return 0xffff;
3707 }
3708
3709 /*
3710 * Read the data returned from the AC97 register.
3711 * ACSDA = Status Data Register = 474h
3712 */
3713 CS_DBGOUT(CS_FUNCTION, 9, printk(KERN_INFO
3714 "cs46xx: cs_ac97_get() reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n",
3715 reg, cs461x_peekBA0(card, BA0_ACSDA),
3716 cs461x_peekBA0(card, BA0_ACCAD)));
3717 ret = cs461x_peekBA0(card, BA0_ACSDA);
3718 return ret;
3719}
3720
3721static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg)
3722{
3723 u16 ret;
3724 struct cs_card *card = dev->private_data;
3725
3726 spin_lock(&card->ac97_lock);
3727 ret = _cs_ac97_get(dev, reg);
3728 spin_unlock(&card->ac97_lock);
3729 return ret;
3730}
3731
3732static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
3733{
3734 struct cs_card *card = dev->private_data;
3735 int count;
3736 int val2 = 0;
3737
3738 spin_lock(&card->ac97_lock);
3739
Jesper Juhl2eebb192006-06-23 02:05:26 -07003740 if (reg == AC97_CD_VOL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 val2 = _cs_ac97_get(dev, AC97_CD_VOL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003742
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 /*
3744 * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
3745 * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97
3746 * 3. Write ACCTL = Control Register = 460h for initiating the write
3747 * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h
3748 * 5. if DCV not cleared, break and return error
3749 */
3750
3751 /*
3752 * Setup the AC97 control registers on the CS461x to send the
3753 * appropriate command to the AC97 to perform the read.
3754 * ACCAD = Command Address Register = 46Ch
3755 * ACCDA = Command Data Register = 470h
3756 * ACCTL = Control Register = 460h
3757 * set DCV - will clear when process completed
3758 * reset CRW - Write command
3759 * set VFRM - valid frame enabled
3760 * set ESYN - ASYNC generation enabled
3761 * set RSTN - ARST# inactive, AC97 codec not reset
3762 */
3763 cs461x_pokeBA0(card, BA0_ACCAD, reg);
3764 cs461x_pokeBA0(card, BA0_ACCDA, val);
3765 cs461x_peekBA0(card, BA0_ACCTL);
3766 cs461x_pokeBA0(card, BA0_ACCTL, 0 | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
3767 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM |
3768 ACCTL_ESYN | ACCTL_RSTN);
3769 for (count = 0; count < 1000; count++) {
3770 /*
3771 * First, we want to wait for a short time.
3772 */
3773 udelay(10 * cs_laptop_wait);
3774 /*
3775 * Now, check to see if the write has completed.
3776 * ACCTL = 460h, DCV should be reset by now and 460h = 07h
3777 */
3778 if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV))
3779 break;
3780 }
3781 /*
3782 * Make sure the write completed.
3783 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003784 if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
3786 "cs46xx: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val));
3787 }
3788
3789 spin_unlock(&card->ac97_lock);
3790
3791 /*
3792 * Adjust power if the mixer is selected/deselected according
3793 * to the CD.
3794 *
3795 * IF the CD is a valid input source (mixer or direct) AND
3796 * the CD is not muted THEN power is needed
3797 *
3798 * We do two things. When record select changes the input to
3799 * add/remove the CD we adjust the power count if the CD is
3800 * unmuted.
3801 *
3802 * When the CD mute changes we adjust the power level if the
3803 * CD was a valid input.
3804 *
3805 * We also check for CD volume != 0, as the CD mute isn't
3806 * normally tweaked from userspace.
3807 */
3808
3809 /* CD mute change ? */
3810
Jesper Juhl2eebb192006-06-23 02:05:26 -07003811 if (reg == AC97_CD_VOL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 /* Mute bit change ? */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003813 if ((val2^val) & 0x8000 ||
3814 ((val2 == 0x1f1f || val == 0x1f1f) && val2 != val)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 /* This is a hack but its cleaner than the alternatives.
3816 Right now card->ac97_codec[0] might be NULL as we are
3817 still doing codec setup. This does an early assignment
3818 to avoid the problem if it occurs */
3819
Jesper Juhl2eebb192006-06-23 02:05:26 -07003820 if (card->ac97_codec[0] == NULL)
3821 card->ac97_codec[0] = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822
3823 /* Mute on */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003824 if (val & 0x8000 || val == 0x1f1f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 card->amplifier_ctrl(card, -1);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003826 else { /* Mute off power on */
3827 if (card->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 card->amp_init(card);
3829 card->amplifier_ctrl(card, 1);
3830 }
3831 }
3832 }
3833}
3834
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835/* OSS /dev/mixer file operation methods */
3836
3837static int cs_open_mixdev(struct inode *inode, struct file *file)
3838{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003839 int i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003841 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 struct list_head *entry;
3843 unsigned int tmp;
3844
3845 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
3846 printk(KERN_INFO "cs46xx: cs_open_mixdev()+\n"));
3847
Jesper Juhl2eebb192006-06-23 02:05:26 -07003848 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 card = list_entry(entry, struct cs_card, list);
3850 for (i = 0; i < NR_AC97; i++)
3851 if (card->ac97_codec[i] != NULL &&
3852 card->ac97_codec[i]->dev_mixer == minor)
3853 goto match;
3854 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003855 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
3857 printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
3858 return -ENODEV;
3859 }
3860 match:
Jesper Juhl2eebb192006-06-23 02:05:26 -07003861 if (!card->ac97_codec[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 return -ENODEV;
3863 file->private_data = card->ac97_codec[i];
3864
3865 card->active_ctrl(card,1);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003866 if (!CS_IN_USE(&card->mixer_use_cnt)) {
3867 if ((tmp = cs46xx_powerup(card, CS_POWER_MIXVON))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003869 "cs46xx: cs_open_mixdev() powerup failure (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 return -EIO;
3871 }
3872 }
3873 card->amplifier_ctrl(card, 1);
3874 CS_INC_USE_COUNT(&card->mixer_use_cnt);
3875 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
3876 printk(KERN_INFO "cs46xx: cs_open_mixdev()- 0\n"));
3877 return nonseekable_open(inode, file);
3878}
3879
3880static int cs_release_mixdev(struct inode *inode, struct file *file)
3881{
3882 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003883 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 struct list_head *entry;
3885 int i;
3886 unsigned int tmp;
3887
3888 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
3889 printk(KERN_INFO "cs46xx: cs_release_mixdev()+\n"));
3890 list_for_each(entry, &cs46xx_devs)
3891 {
3892 card = list_entry(entry, struct cs_card, list);
3893 for (i = 0; i < NR_AC97; i++)
3894 if (card->ac97_codec[i] != NULL &&
3895 card->ac97_codec[i]->dev_mixer == minor)
3896 goto match;
3897 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003898 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
3900 printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
3901 return -ENODEV;
3902 }
3903match:
Jesper Juhl2eebb192006-06-23 02:05:26 -07003904 if (!CS_DEC_AND_TEST(&card->mixer_use_cnt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
3906 printk(KERN_INFO "cs46xx: cs_release_mixdev()- no powerdown, usecnt>0\n"));
3907 card->active_ctrl(card, -1);
3908 card->amplifier_ctrl(card, -1);
3909 return 0;
3910 }
3911/*
3912* ok, no outstanding mixer opens, so powerdown.
3913*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003914 if ((tmp = cs461x_powerdown(card, CS_POWER_MIXVON, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003916 "cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 card->active_ctrl(card, -1);
3918 card->amplifier_ctrl(card, -1);
3919 return -EIO;
3920 }
3921 card->active_ctrl(card, -1);
3922 card->amplifier_ctrl(card, -1);
3923 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
3924 printk(KERN_INFO "cs46xx: cs_release_mixdev()- 0\n"));
3925 return 0;
3926}
3927
3928static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
Jesper Juhl2eebb192006-06-23 02:05:26 -07003929 unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003931 struct ac97_codec *codec = file->private_data;
3932 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 struct list_head *entry;
3934 unsigned long __user *p = (long __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935#if CSDEBUG_INTERFACE
3936 int val;
3937
Jesper Juhl2eebb192006-06-23 02:05:26 -07003938 if ( (cmd == SOUND_MIXER_CS_GETDBGMASK) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 (cmd == SOUND_MIXER_CS_SETDBGMASK) ||
3940 (cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
3941 (cmd == SOUND_MIXER_CS_SETDBGLEVEL) ||
Jesper Juhl2eebb192006-06-23 02:05:26 -07003942 (cmd == SOUND_MIXER_CS_APM)) {
3943 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 case SOUND_MIXER_CS_GETDBGMASK:
3945 return put_user(cs_debugmask, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 case SOUND_MIXER_CS_GETDBGLEVEL:
3947 return put_user(cs_debuglevel, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 case SOUND_MIXER_CS_SETDBGMASK:
3949 if (get_user(val, p))
3950 return -EFAULT;
3951 cs_debugmask = val;
3952 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 case SOUND_MIXER_CS_SETDBGLEVEL:
3954 if (get_user(val, p))
3955 return -EFAULT;
3956 cs_debuglevel = val;
3957 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 case SOUND_MIXER_CS_APM:
3959 if (get_user(val, p))
3960 return -EFAULT;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003961 if (val == CS_IOCTL_CMD_SUSPEND) {
3962 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 card = list_entry(entry, struct cs_card, list);
Pavel Machek2a569572005-07-07 17:56:40 -07003964 cs46xx_suspend(card, PMSG_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 }
3966
Jesper Juhl2eebb192006-06-23 02:05:26 -07003967 } else if (val == CS_IOCTL_CMD_RESUME) {
3968 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 card = list_entry(entry, struct cs_card, list);
3970 cs46xx_resume(card);
3971 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003972 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
3974 "cs46xx: mixer_ioctl(): invalid APM cmd (%d)\n",
3975 val));
3976 }
3977 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 default:
3979 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003980 "cs46xx: mixer_ioctl(): ERROR unknown debug cmd\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 return 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 }
3984#endif
3985 return codec->mixer_ioctl(codec, cmd, arg);
3986}
3987
3988static /*const*/ struct file_operations cs_mixer_fops = {
3989 CS_OWNER CS_THIS_MODULE
3990 .llseek = no_llseek,
3991 .ioctl = cs_ioctl_mixdev,
3992 .open = cs_open_mixdev,
3993 .release = cs_release_mixdev,
3994};
3995
3996/* AC97 codec initialisation. */
3997static int __init cs_ac97_init(struct cs_card *card)
3998{
3999 int num_ac97 = 0;
4000 int ready_2nd = 0;
4001 struct ac97_codec *codec;
4002 u16 eid;
4003
4004 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4005 "cs46xx: cs_ac97_init()+\n") );
4006
4007 for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
4008 if ((codec = ac97_alloc_codec()) == NULL)
4009 return -ENOMEM;
4010
4011 /* initialize some basic codec information, other fields will be filled
4012 in ac97_probe_codec */
4013 codec->private_data = card;
4014 codec->id = num_ac97;
4015
4016 codec->codec_read = cs_ac97_get;
4017 codec->codec_write = cs_ac97_set;
4018
Jesper Juhl2eebb192006-06-23 02:05:26 -07004019 if (ac97_probe_codec(codec) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4021 "cs46xx: cs_ac97_init()- codec number %d not found\n",
4022 num_ac97) );
4023 card->ac97_codec[num_ac97] = NULL;
4024 break;
4025 }
4026 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07004027 "cs46xx: cs_ac97_init() found codec %d\n",num_ac97));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028
4029 eid = cs_ac97_get(codec, AC97_EXTENDED_ID);
4030
Jesper Juhl2eebb192006-06-23 02:05:26 -07004031 if (eid == 0xFFFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 printk(KERN_WARNING "cs46xx: codec %d not present\n",num_ac97);
4033 ac97_release_codec(codec);
4034 break;
4035 }
4036
4037 card->ac97_features = eid;
4038
4039 if ((codec->dev_mixer = register_sound_mixer(&cs_mixer_fops, -1)) < 0) {
4040 printk(KERN_ERR "cs46xx: couldn't register mixer!\n");
4041 ac97_release_codec(codec);
4042 break;
4043 }
4044 card->ac97_codec[num_ac97] = codec;
4045
4046 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4047 "cs46xx: cs_ac97_init() ac97_codec[%d] set to %p\n",
4048 (unsigned int)num_ac97,
4049 codec));
4050 /* if there is no secondary codec at all, don't probe any more */
4051 if (!ready_2nd)
4052 {
4053 num_ac97 += 1;
4054 break;
4055 }
4056 }
4057 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4058 "cs46xx: cs_ac97_init()- %d\n", (unsigned int)num_ac97));
4059 return num_ac97;
4060}
4061
4062/*
4063 * load the static image into the DSP
4064 */
4065#include "cs461x_image.h"
4066static void cs461x_download_image(struct cs_card *card)
4067{
4068 unsigned i, j, temp1, temp2, offset, count;
4069 unsigned char __iomem *pBA1 = ioremap(card->ba1_addr, 0x40000);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004070 for (i = 0; i < CLEAR__COUNT; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071 offset = ClrStat[i].BA1__DestByteOffset;
4072 count = ClrStat[i].BA1__SourceSize;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004073 for (temp1 = offset; temp1 < (offset + count); temp1 += 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 writel(0, pBA1+temp1);
4075 }
4076
Jesper Juhl2eebb192006-06-23 02:05:26 -07004077 for (i = 0; i < FILL__COUNT; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 temp2 = FillStat[i].Offset;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004079 for (j = 0; j < (FillStat[i].Size) / 4; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 temp1 = (FillStat[i]).pFill[j];
Jesper Juhl2eebb192006-06-23 02:05:26 -07004081 writel(temp1, pBA1+temp2 + j * 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 }
4083 }
4084 iounmap(pBA1);
4085}
4086
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087/*
4088 * Chip reset
4089 */
4090
4091static void cs461x_reset(struct cs_card *card)
4092{
4093 int idx;
4094
4095 /*
4096 * Write the reset bit of the SP control register.
4097 */
4098 cs461x_poke(card, BA1_SPCR, SPCR_RSTSP);
4099
4100 /*
4101 * Write the control register.
4102 */
4103 cs461x_poke(card, BA1_SPCR, SPCR_DRQEN);
4104
4105 /*
4106 * Clear the trap registers.
4107 */
4108 for (idx = 0; idx < 8; idx++) {
4109 cs461x_poke(card, BA1_DREG, DREG_REGID_TRAP_SELECT + idx);
4110 cs461x_poke(card, BA1_TWPR, 0xFFFF);
4111 }
4112 cs461x_poke(card, BA1_DREG, 0);
4113
4114 /*
4115 * Set the frame timer to reflect the number of cycles per frame.
4116 */
4117 cs461x_poke(card, BA1_FRMT, 0xadf);
4118}
4119
4120static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type)
4121{
4122 int idx, loop, startfifo=0, endfifo=0, powerdown1 = 0;
4123 unsigned int tmp;
4124
4125 /*
4126 * See if the devices are powered down. If so, we must power them up first
4127 * or they will not respond.
4128 */
4129 if (!((tmp = cs461x_peekBA0(card, BA0_CLKCR1)) & CLKCR1_SWCE)) {
4130 cs461x_pokeBA0(card, BA0_CLKCR1, tmp | CLKCR1_SWCE);
4131 powerdown1 = 1;
4132 }
4133
4134 /*
4135 * We want to clear out the serial port FIFOs so we don't end up playing
4136 * whatever random garbage happens to be in them. We fill the sample FIFOS
4137 * with zero (silence).
4138 */
4139 cs461x_pokeBA0(card, BA0_SERBWP, 0);
4140
4141 /*
4142 * Check for which FIFO locations to clear, if we are currently
4143 * playing or capturing then we don't want to put in 128 bytes of
4144 * "noise".
4145 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004146 if (type & CS_TYPE_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 startfifo = 128;
4148 endfifo = 256;
4149 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004150 if (type & CS_TYPE_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 startfifo = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004152 if (!endfifo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 endfifo = 128;
4154 }
4155 /*
4156 * Fill sample FIFO locations (256 locations total).
4157 */
4158 for (idx = startfifo; idx < endfifo; idx++) {
4159 /*
4160 * Make sure the previous FIFO write operation has completed.
4161 */
4162 for (loop = 0; loop < 5; loop++) {
4163 udelay(50);
4164 if (!(cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY))
4165 break;
4166 }
4167 if (cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY) {
4168 if (powerdown1)
4169 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
4170 }
4171 /*
4172 * Write the serial port FIFO index.
4173 */
4174 cs461x_pokeBA0(card, BA0_SERBAD, idx);
4175 /*
4176 * Tell the serial port to load the new value into the FIFO location.
4177 */
4178 cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC);
4179 }
4180 /*
4181 * Now, if we powered up the devices, then power them back down again.
4182 * This is kinda ugly, but should never happen.
4183 */
4184 if (powerdown1)
4185 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
4186}
4187
4188
4189static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag)
4190{
4191 int count;
4192 unsigned int tmp=0,muted=0;
4193
4194 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
4195 "cs46xx: cs461x_powerdown()+ type=0x%x\n",type));
Jesper Juhl2eebb192006-06-23 02:05:26 -07004196 if (!cs_powerdown && !suspendflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4198 "cs46xx: cs461x_powerdown() DISABLED exiting\n"));
4199 return 0;
4200 }
4201 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
4202 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4203 "cs46xx: cs461x_powerdown() powerdown reg=0x%x\n",tmp));
4204/*
4205* if powering down only the VREF, and not powering down the DAC/ADC,
4206* then do not power down the VREF, UNLESS both the DAC and ADC are not
4207* currently powered down. If powering down DAC and ADC, then
4208* it is possible to power down the VREF (ON).
4209*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07004210 if (((type & CS_POWER_MIXVON) &&
4211 (!(type & CS_POWER_ADC) || (!(type & CS_POWER_DAC))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 &&
4213 ((tmp & CS_AC97_POWER_CONTROL_ADC_ON) ||
Jesper Juhl2eebb192006-06-23 02:05:26 -07004214 (tmp & CS_AC97_POWER_CONTROL_DAC_ON))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4216 "cs46xx: cs461x_powerdown()- 0 unable to powerdown. tmp=0x%x\n",tmp));
4217 return 0;
4218 }
4219/*
4220* for now, always keep power to the mixer block.
4221* not sure why it's a problem but it seems to be if we power off.
4222*/
4223 type &= ~CS_POWER_MIXVON;
4224 type &= ~CS_POWER_MIXVOFF;
4225
4226 /*
4227 * Power down indicated areas.
4228 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004229 if (type & CS_POWER_MIXVOFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230
4231 CS_DBGOUT(CS_FUNCTION, 4,
4232 printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVOFF\n"));
4233 /*
4234 * Power down the MIXER (VREF ON) on the AC97 card.
4235 */
4236 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004237 if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON) {
4238 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004240 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 }
4242 tmp |= CS_AC97_POWER_CONTROL_MIXVOFF;
4243 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4244 /*
4245 * Now, we wait until we sample a ready state.
4246 */
4247 for (count = 0; count < 32; count++) {
4248 /*
4249 * First, lets wait a short while to let things settle out a
4250 * bit, and to prevent retrying the read too quickly.
4251 */
4252 udelay(500);
4253
4254 /*
4255 * Read the current state of the power control register.
4256 */
4257 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4258 CS_AC97_POWER_CONTROL_MIXVOFF_ON))
4259 break;
4260 }
4261
4262 /*
4263 * Check the status..
4264 */
4265 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004266 CS_AC97_POWER_CONTROL_MIXVOFF_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4268 "cs46xx: powerdown MIXVOFF failed\n"));
4269 return 1;
4270 }
4271 }
4272 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004273 if (type & CS_POWER_MIXVON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274
4275 CS_DBGOUT(CS_FUNCTION, 4,
4276 printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVON\n"));
4277 /*
4278 * Power down the MIXER (VREF ON) on the AC97 card.
4279 */
4280 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004281 if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON) {
4282 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004284 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 }
4286 tmp |= CS_AC97_POWER_CONTROL_MIXVON;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004287 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 /*
4289 * Now, we wait until we sample a ready state.
4290 */
4291 for (count = 0; count < 32; count++) {
4292 /*
4293 * First, lets wait a short while to let things settle out a
4294 * bit, and to prevent retrying the read too quickly.
4295 */
4296 udelay(500);
4297
4298 /*
4299 * Read the current state of the power control register.
4300 */
4301 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4302 CS_AC97_POWER_CONTROL_MIXVON_ON))
4303 break;
4304 }
4305
4306 /*
4307 * Check the status..
4308 */
4309 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004310 CS_AC97_POWER_CONTROL_MIXVON_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4312 "cs46xx: powerdown MIXVON failed\n"));
4313 return 1;
4314 }
4315 }
4316 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004317 if (type & CS_POWER_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 /*
4319 * Power down the ADC on the AC97 card.
4320 */
4321 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs461x_powerdown()+ ADC\n"));
4322 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004323 if (tmp & CS_AC97_POWER_CONTROL_ADC_ON) {
4324 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004326 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 }
4328 tmp |= CS_AC97_POWER_CONTROL_ADC;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004329 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330
4331 /*
4332 * Now, we wait until we sample a ready state.
4333 */
4334 for (count = 0; count < 32; count++) {
4335 /*
4336 * First, lets wait a short while to let things settle out a
4337 * bit, and to prevent retrying the read too quickly.
4338 */
4339 udelay(500);
4340
4341 /*
4342 * Read the current state of the power control register.
4343 */
4344 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4345 CS_AC97_POWER_CONTROL_ADC_ON))
4346 break;
4347 }
4348
4349 /*
4350 * Check the status..
4351 */
4352 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004353 CS_AC97_POWER_CONTROL_ADC_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4355 "cs46xx: powerdown ADC failed\n"));
4356 return 1;
4357 }
4358 }
4359 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004360 if (type & CS_POWER_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 /*
4362 * Power down the DAC on the AC97 card.
4363 */
4364
4365 CS_DBGOUT(CS_FUNCTION, 4,
4366 printk(KERN_INFO "cs46xx: cs461x_powerdown()+ DAC\n"));
4367 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004368 if (tmp & CS_AC97_POWER_CONTROL_DAC_ON) {
4369 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004371 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 }
4373 tmp |= CS_AC97_POWER_CONTROL_DAC;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004374 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 /*
4376 * Now, we wait until we sample a ready state.
4377 */
4378 for (count = 0; count < 32; count++) {
4379 /*
4380 * First, lets wait a short while to let things settle out a
4381 * bit, and to prevent retrying the read too quickly.
4382 */
4383 udelay(500);
4384
4385 /*
4386 * Read the current state of the power control register.
4387 */
4388 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4389 CS_AC97_POWER_CONTROL_DAC_ON))
4390 break;
4391 }
4392
4393 /*
4394 * Check the status..
4395 */
4396 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004397 CS_AC97_POWER_CONTROL_DAC_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4399 "cs46xx: powerdown DAC failed\n"));
4400 return 1;
4401 }
4402 }
4403 }
4404 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004405 if (muted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 cs_mute(card, CS_FALSE);
4407 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
4408 "cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp));
4409 return 0;
4410}
4411
4412static int cs46xx_powerup(struct cs_card *card, unsigned int type)
4413{
4414 int count;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004415 unsigned int tmp = 0, muted = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416
4417 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4418 "cs46xx: cs46xx_powerup()+ type=0x%x\n",type));
4419 /*
4420 * check for VREF and powerup if need to.
4421 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004422 if (type & CS_POWER_MIXVON)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 type |= CS_POWER_MIXVOFF;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004424 if (type & (CS_POWER_DAC | CS_POWER_ADC))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF;
4426
4427 /*
4428 * Power up indicated areas.
4429 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004430 if (type & CS_POWER_MIXVOFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431
4432 CS_DBGOUT(CS_FUNCTION, 4,
4433 printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVOFF\n"));
4434 /*
4435 * Power up the MIXER (VREF ON) on the AC97 card.
4436 */
4437 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004438 if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)) {
4439 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004441 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 }
4443 tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF;
4444 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4445 /*
4446 * Now, we wait until we sample a ready state.
4447 */
4448 for (count = 0; count < 32; count++) {
4449 /*
4450 * First, lets wait a short while to let things settle out a
4451 * bit, and to prevent retrying the read too quickly.
4452 */
4453 udelay(500);
4454
4455 /*
4456 * Read the current state of the power control register.
4457 */
4458 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4459 CS_AC97_POWER_CONTROL_MIXVOFF_ON)
4460 break;
4461 }
4462
4463 /*
4464 * Check the status..
4465 */
4466 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004467 CS_AC97_POWER_CONTROL_MIXVOFF_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4469 "cs46xx: powerup MIXVOFF failed\n"));
4470 return 1;
4471 }
4472 }
4473 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004474 if(type & CS_POWER_MIXVON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475
4476 CS_DBGOUT(CS_FUNCTION, 4,
4477 printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVON\n"));
4478 /*
4479 * Power up the MIXER (VREF ON) on the AC97 card.
4480 */
4481 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004482 if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)) {
4483 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004485 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 }
4487 tmp &= ~CS_AC97_POWER_CONTROL_MIXVON;
4488 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4489 /*
4490 * Now, we wait until we sample a ready state.
4491 */
4492 for (count = 0; count < 32; count++) {
4493 /*
4494 * First, lets wait a short while to let things settle out a
4495 * bit, and to prevent retrying the read too quickly.
4496 */
4497 udelay(500);
4498
4499 /*
4500 * Read the current state of the power control register.
4501 */
4502 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4503 CS_AC97_POWER_CONTROL_MIXVON_ON)
4504 break;
4505 }
4506
4507 /*
4508 * Check the status..
4509 */
4510 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004511 CS_AC97_POWER_CONTROL_MIXVON_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4513 "cs46xx: powerup MIXVON failed\n"));
4514 return 1;
4515 }
4516 }
4517 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004518 if (type & CS_POWER_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 /*
4520 * Power up the ADC on the AC97 card.
4521 */
4522 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs46xx_powerup()+ ADC\n"));
4523 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004524 if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON)) {
4525 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004527 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 }
4529 tmp &= ~CS_AC97_POWER_CONTROL_ADC;
4530 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4531
4532 /*
4533 * Now, we wait until we sample a ready state.
4534 */
4535 for (count = 0; count < 32; count++) {
4536 /*
4537 * First, lets wait a short while to let things settle out a
4538 * bit, and to prevent retrying the read too quickly.
4539 */
4540 udelay(500);
4541
4542 /*
4543 * Read the current state of the power control register.
4544 */
4545 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4546 CS_AC97_POWER_CONTROL_ADC_ON)
4547 break;
4548 }
4549
4550 /*
4551 * Check the status..
4552 */
4553 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004554 CS_AC97_POWER_CONTROL_ADC_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4556 "cs46xx: powerup ADC failed\n"));
4557 return 1;
4558 }
4559 }
4560 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004561 if (type & CS_POWER_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 /*
4563 * Power up the DAC on the AC97 card.
4564 */
4565
4566 CS_DBGOUT(CS_FUNCTION, 4,
4567 printk(KERN_INFO "cs46xx: cs46xx_powerup()+ DAC\n"));
4568 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004569 if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON)) {
4570 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004572 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 }
4574 tmp &= ~CS_AC97_POWER_CONTROL_DAC;
4575 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4576 /*
4577 * Now, we wait until we sample a ready state.
4578 */
4579 for (count = 0; count < 32; count++) {
4580 /*
4581 * First, lets wait a short while to let things settle out a
4582 * bit, and to prevent retrying the read too quickly.
4583 */
4584 udelay(500);
4585
4586 /*
4587 * Read the current state of the power control register.
4588 */
4589 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4590 CS_AC97_POWER_CONTROL_DAC_ON)
4591 break;
4592 }
4593
4594 /*
4595 * Check the status..
4596 */
4597 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004598 CS_AC97_POWER_CONTROL_DAC_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4600 "cs46xx: powerup DAC failed\n"));
4601 return 1;
4602 }
4603 }
4604 }
4605 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004606 if (muted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 cs_mute(card, CS_FALSE);
4608 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
4609 "cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp));
4610 return 0;
4611}
4612
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613static void cs461x_proc_start(struct cs_card *card)
4614{
4615 int cnt;
4616
4617 /*
4618 * Set the frame timer to reflect the number of cycles per frame.
4619 */
4620 cs461x_poke(card, BA1_FRMT, 0xadf);
4621 /*
4622 * Turn on the run, run at frame, and DMA enable bits in the local copy of
4623 * the SP control register.
4624 */
4625 cs461x_poke(card, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN);
4626 /*
4627 * Wait until the run at frame bit resets itself in the SP control
4628 * register.
4629 */
4630 for (cnt = 0; cnt < 25; cnt++) {
4631 udelay(50);
4632 if (!(cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR))
4633 break;
4634 }
4635
4636 if (cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR)
4637 printk(KERN_WARNING "cs46xx: SPCR_RUNFR never reset\n");
4638}
4639
4640static void cs461x_proc_stop(struct cs_card *card)
4641{
4642 /*
4643 * Turn off the run, run at frame, and DMA enable bits in the local copy of
4644 * the SP control register.
4645 */
4646 cs461x_poke(card, BA1_SPCR, 0);
4647}
4648
4649static int cs_hardware_init(struct cs_card *card)
4650{
4651 unsigned long end_time;
4652 unsigned int tmp,count;
4653
4654 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4655 "cs46xx: cs_hardware_init()+\n") );
4656 /*
4657 * First, blast the clock control register to zero so that the PLL starts
4658 * out in a known state, and blast the master serial port control register
4659 * to zero so that the serial ports also start out in a known state.
4660 */
4661 cs461x_pokeBA0(card, BA0_CLKCR1, 0);
4662 cs461x_pokeBA0(card, BA0_SERMC1, 0);
4663
4664 /*
4665 * If we are in AC97 mode, then we must set the part to a host controlled
4666 * AC-link. Otherwise, we won't be able to bring up the link.
4667 */
4668 cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_1_03); /* 1.03 card */
4669 /* cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_2_0); */ /* 2.00 card */
4670
4671 /*
4672 * Drive the ARST# pin low for a minimum of 1uS (as defined in the AC97
4673 * spec) and then drive it high. This is done for non AC97 modes since
4674 * there might be logic external to the CS461x that uses the ARST# line
4675 * for a reset.
4676 */
4677 cs461x_pokeBA0(card, BA0_ACCTL, 1);
4678 udelay(50);
4679 cs461x_pokeBA0(card, BA0_ACCTL, 0);
4680 udelay(50);
4681 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN);
4682
4683 /*
4684 * The first thing we do here is to enable sync generation. As soon
4685 * as we start receiving bit clock, we'll start producing the SYNC
4686 * signal.
4687 */
4688 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_ESYN | ACCTL_RSTN);
4689
4690 /*
4691 * Now wait for a short while to allow the AC97 part to start
4692 * generating bit clock (so we don't try to start the PLL without an
4693 * input clock).
4694 */
4695 mdelay(5 * cs_laptop_wait); /* 1 should be enough ?? (and pigs might fly) */
4696
4697 /*
4698 * Set the serial port timing configuration, so that
4699 * the clock control circuit gets its clock from the correct place.
4700 */
4701 cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97);
4702
4703 /*
4704 * The part seems to not be ready for a while after a resume.
4705 * so, if we are resuming, then wait for 700 mils. Note that 600 mils
4706 * is not enough for some platforms! tested on an IBM Thinkpads and
4707 * reference cards.
4708 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004709 if (!(card->pm.flags & CS46XX_PM_IDLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 mdelay(initdelay);
4711 /*
4712 * Write the selected clock control setup to the hardware. Do not turn on
4713 * SWCE yet (if requested), so that the devices clocked by the output of
4714 * PLL are not clocked until the PLL is stable.
4715 */
4716 cs461x_pokeBA0(card, BA0_PLLCC, PLLCC_LPF_1050_2780_KHZ | PLLCC_CDR_73_104_MHZ);
4717 cs461x_pokeBA0(card, BA0_PLLM, 0x3a);
4718 cs461x_pokeBA0(card, BA0_CLKCR2, CLKCR2_PDIVS_8);
4719
4720 /*
4721 * Power up the PLL.
4722 */
4723 cs461x_pokeBA0(card, BA0_CLKCR1, CLKCR1_PLLP);
4724
4725 /*
4726 * Wait until the PLL has stabilized.
4727 */
4728 mdelay(5 * cs_laptop_wait); /* Again 1 should be enough ?? */
4729
4730 /*
4731 * Turn on clocking of the core so that we can setup the serial ports.
4732 */
4733 tmp = cs461x_peekBA0(card, BA0_CLKCR1) | CLKCR1_SWCE;
4734 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
4735
4736 /*
4737 * Fill the serial port FIFOs with silence.
4738 */
4739 cs461x_clear_serial_FIFOs(card,CS_TYPE_DAC | CS_TYPE_ADC);
4740
4741 /*
4742 * Set the serial port FIFO pointer to the first sample in the FIFO.
4743 */
4744 /* cs461x_pokeBA0(card, BA0_SERBSP, 0); */
4745
4746 /*
4747 * Write the serial port configuration to the part. The master
4748 * enable bit is not set until all other values have been written.
4749 */
4750 cs461x_pokeBA0(card, BA0_SERC1, SERC1_SO1F_AC97 | SERC1_SO1EN);
4751 cs461x_pokeBA0(card, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN);
4752 cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
4753
4754
4755 mdelay(5 * cs_laptop_wait); /* Shouldnt be needed ?? */
4756
4757/*
Matt LaPlante0779bf22006-11-30 05:24:39 +01004758* If we are resuming under 2.2.x then we cannot schedule a timeout,
4759* so just spin the CPU.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07004761 if (card->pm.flags & CS46XX_PM_IDLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 /*
4763 * Wait for the card ready signal from the AC97 card.
4764 */
4765 end_time = jiffies + 3 * (HZ >> 2);
4766 do {
4767 /*
4768 * Read the AC97 status register to see if we've seen a CODEC READY
4769 * signal from the AC97 card.
4770 */
4771 if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
4772 break;
4773 current->state = TASK_UNINTERRUPTIBLE;
4774 schedule_timeout(1);
4775 } while (time_before(jiffies, end_time));
Jesper Juhl2eebb192006-06-23 02:05:26 -07004776 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 for (count = 0; count < 100; count++) {
4778 // First, we want to wait for a short time.
4779 udelay(25 * cs_laptop_wait);
4780
4781 if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
4782 break;
4783 }
4784 }
4785
4786 /*
4787 * Make sure CODEC is READY.
4788 */
4789 if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)) {
4790 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
4791 "cs46xx: create - never read card ready from AC'97\n"));
4792 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
4793 "cs46xx: probably not a bug, try using the CS4232 driver,\n"));
4794 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
4795 "cs46xx: or turn off any automatic Power Management support in the BIOS.\n"));
4796 return -EIO;
4797 }
4798
4799 /*
4800 * Assert the vaid frame signal so that we can start sending commands
4801 * to the AC97 card.
4802 */
4803 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
4804
Jesper Juhl2eebb192006-06-23 02:05:26 -07004805 if (card->pm.flags & CS46XX_PM_IDLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 /*
4807 * Wait until we've sampled input slots 3 and 4 as valid, meaning that
4808 * the card is pumping ADC data across the AC-link.
4809 */
4810 end_time = jiffies + 3 * (HZ >> 2);
4811 do {
4812 /*
4813 * Read the input slot valid register and see if input slots 3 and
4814 * 4 are valid yet.
4815 */
4816 if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
4817 break;
4818 current->state = TASK_UNINTERRUPTIBLE;
4819 schedule_timeout(1);
4820 } while (time_before(jiffies, end_time));
Jesper Juhl2eebb192006-06-23 02:05:26 -07004821 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 for (count = 0; count < 100; count++) {
4823 // First, we want to wait for a short time.
4824 udelay(25 * cs_laptop_wait);
4825
4826 if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
4827 break;
4828 }
4829 }
4830 /*
4831 * Make sure input slots 3 and 4 are valid. If not, then return
4832 * an error.
4833 */
4834 if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) != (ACISV_ISV3 | ACISV_ISV4)) {
4835 printk(KERN_WARNING "cs46xx: create - never read ISV3 & ISV4 from AC'97\n");
4836 return -EIO;
4837 }
4838
4839 /*
4840 * Now, assert valid frame and the slot 3 and 4 valid bits. This will
4841 * commense the transfer of digital audio data to the AC97 card.
4842 */
4843 cs461x_pokeBA0(card, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4);
4844
4845 /*
4846 * Turn off the Processor by turning off the software clock enable flag in
4847 * the clock control register.
4848 */
4849 /* tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE; */
4850 /* cs461x_pokeBA0(card, BA0_CLKCR1, tmp); */
4851
4852 /*
4853 * Reset the processor.
4854 */
4855 cs461x_reset(card);
4856
4857 /*
4858 * Download the image to the processor.
4859 */
4860
4861 cs461x_download_image(card);
4862
4863 /*
4864 * Stop playback DMA.
4865 */
4866 tmp = cs461x_peek(card, BA1_PCTL);
4867 card->pctl = tmp & 0xffff0000;
4868 cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
4869
4870 /*
4871 * Stop capture DMA.
4872 */
4873 tmp = cs461x_peek(card, BA1_CCTL);
4874 card->cctl = tmp & 0x0000ffff;
4875 cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
4876
4877 /* initialize AC97 codec and register /dev/mixer */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004878 if (card->pm.flags & CS46XX_PM_IDLE) {
4879 if (cs_ac97_init(card) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07004881 "cs46xx: cs_ac97_init() failure\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 return -EIO;
4883 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004884 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 cs46xx_ac97_resume(card);
4886 }
4887
4888 cs461x_proc_start(card);
4889
4890 /*
4891 * Enable interrupts on the part.
4892 */
4893 cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM);
4894
4895 tmp = cs461x_peek(card, BA1_PFIE);
4896 tmp &= ~0x0000f03f;
4897 cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt enable */
4898
4899 tmp = cs461x_peek(card, BA1_CIE);
4900 tmp &= ~0x0000003f;
4901 tmp |= 0x00000001;
4902 cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt enable */
4903
4904 /*
4905 * If IDLE then Power down the part. We will power components up
4906 * when we need them.
4907 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004908 if (card->pm.flags & CS46XX_PM_IDLE) {
4909 if (!cs_powerdown) {
4910 if ((tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC |
4911 CS_POWER_MIXVON))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
4913 "cs46xx: cs461x_powerup() failure (0x%x)\n",tmp) );
4914 return -EIO;
4915 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004916 } else {
4917 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
4918 CS_POWER_MIXVON, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004919 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
4920 "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
4921 return -EIO;
4922 }
4923 }
4924 }
4925 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4926 "cs46xx: cs_hardware_init()- 0\n"));
4927 return 0;
4928}
4929
4930/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered
4931 until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
4932
4933/*
4934 * Card subid table
4935 */
4936
4937struct cs_card_type
4938{
4939 u16 vendor;
4940 u16 id;
4941 char *name;
4942 void (*amp)(struct cs_card *, int);
4943 void (*amp_init)(struct cs_card *);
4944 void (*active)(struct cs_card *, int);
4945};
4946
4947static struct cs_card_type cards[] = {
4948 {
4949 .vendor = 0x1489,
4950 .id = 0x7001,
4951 .name = "Genius Soundmaker 128 value",
4952 .amp = amp_none,
4953 },
4954 {
4955 .vendor = 0x5053,
4956 .id = 0x3357,
4957 .name = "Voyetra",
4958 .amp = amp_voyetra,
4959 },
4960 {
4961 .vendor = 0x1071,
4962 .id = 0x6003,
4963 .name = "Mitac MI6020/21",
4964 .amp = amp_voyetra,
4965 },
4966 {
4967 .vendor = 0x14AF,
4968 .id = 0x0050,
4969 .name = "Hercules Game Theatre XP",
4970 .amp = amp_hercules,
4971 },
4972 {
4973 .vendor = 0x1681,
4974 .id = 0x0050,
4975 .name = "Hercules Game Theatre XP",
4976 .amp = amp_hercules,
4977 },
4978 {
4979 .vendor = 0x1681,
4980 .id = 0x0051,
4981 .name = "Hercules Game Theatre XP",
4982 .amp = amp_hercules,
4983 },
4984 {
4985 .vendor = 0x1681,
4986 .id = 0x0052,
4987 .name = "Hercules Game Theatre XP",
4988 .amp = amp_hercules,
4989 },
4990 {
4991 .vendor = 0x1681,
4992 .id = 0x0053,
4993 .name = "Hercules Game Theatre XP",
4994 .amp = amp_hercules,
4995 },
4996 {
4997 .vendor = 0x1681,
4998 .id = 0x0054,
4999 .name = "Hercules Game Theatre XP",
5000 .amp = amp_hercules,
5001 },
5002 {
5003 .vendor = 0x1681,
5004 .id = 0xa010,
5005 .name = "Hercules Fortissimo II",
5006 .amp = amp_none,
5007 },
5008 /* Not sure if the 570 needs the clkrun hack */
5009 {
5010 .vendor = PCI_VENDOR_ID_IBM,
5011 .id = 0x0132,
5012 .name = "Thinkpad 570",
5013 .amp = amp_none,
5014 .active = clkrun_hack,
5015 },
5016 {
5017 .vendor = PCI_VENDOR_ID_IBM,
5018 .id = 0x0153,
5019 .name = "Thinkpad 600X/A20/T20",
5020 .amp = amp_none,
5021 .active = clkrun_hack,
5022 },
5023 {
5024 .vendor = PCI_VENDOR_ID_IBM,
5025 .id = 0x1010,
5026 .name = "Thinkpad 600E (unsupported)",
5027 },
5028 {
5029 .name = "Card without SSID set",
5030 },
5031 { 0, },
5032};
5033
5034MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <pcaudio@crystal.cirrus.com>");
5035MODULE_DESCRIPTION("Crystal SoundFusion Audio Support");
5036MODULE_LICENSE("GPL");
5037
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038static const char cs46xx_banner[] = KERN_INFO "Crystal 4280/46xx + AC97 Audio, version " CS46XX_MAJOR_VERSION "." CS46XX_MINOR_VERSION "." CS46XX_ARCH ", " __TIME__ " " __DATE__ "\n";
5039static const char fndmsg[] = KERN_INFO "cs46xx: Found %d audio device(s).\n";
5040
5041static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
5042 const struct pci_device_id *pciid)
5043{
Jesper Juhl2eebb192006-06-23 02:05:26 -07005044 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 u16 ss_card, ss_vendor;
5046 struct cs_card *card;
5047 dma_addr_t dma_mask;
5048 struct cs_card_type *cp = &cards[0];
5049
5050 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
5051 printk(KERN_INFO "cs46xx: probe()+\n"));
5052
5053 dma_mask = 0xffffffff; /* this enables playback and recording */
5054 if (pci_enable_device(pci_dev)) {
5055 CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
5056 "cs46xx: pci_enable_device() failed\n"));
5057 return -1;
5058 }
5059 if (!RSRCISMEMORYREGION(pci_dev, 0) ||
5060 !RSRCISMEMORYREGION(pci_dev, 1)) {
5061 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
5062 "cs46xx: probe()- Memory region not assigned\n"));
5063 return -1;
5064 }
5065 if (pci_dev->irq == 0) {
5066 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
5067 "cs46xx: probe() IRQ not assigned\n"));
5068 return -1;
5069 }
5070 if (!pci_dma_supported(pci_dev, 0xffffffff)) {
5071 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
5072 "cs46xx: probe() architecture does not support 32bit PCI busmaster DMA\n"));
5073 return -1;
5074 }
5075 pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
5076 pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card);
5077
5078 if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) {
5079 printk(KERN_ERR "cs46xx: out of memory\n");
5080 return -ENOMEM;
5081 }
5082 memset(card, 0, sizeof(*card));
5083 card->ba0_addr = RSRCADDRESS(pci_dev, 0);
5084 card->ba1_addr = RSRCADDRESS(pci_dev, 1);
5085 card->pci_dev = pci_dev;
5086 card->irq = pci_dev->irq;
5087 card->magic = CS_CARD_MAGIC;
5088 spin_lock_init(&card->lock);
5089 spin_lock_init(&card->ac97_lock);
5090
5091 pci_set_master(pci_dev);
5092
5093 printk(cs46xx_banner);
5094 printk(KERN_INFO "cs46xx: Card found at 0x%08lx and 0x%08lx, IRQ %d\n",
5095 card->ba0_addr, card->ba1_addr, card->irq);
5096
5097 card->alloc_pcm_channel = cs_alloc_pcm_channel;
5098 card->alloc_rec_pcm_channel = cs_alloc_rec_pcm_channel;
5099 card->free_pcm_channel = cs_free_pcm_channel;
5100 card->amplifier_ctrl = amp_none;
5101 card->active_ctrl = amp_none;
5102
5103 while (cp->name)
5104 {
Jesper Juhl2eebb192006-06-23 02:05:26 -07005105 if (cp->vendor == ss_vendor && cp->id == ss_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 card->amplifier_ctrl = cp->amp;
Jesper Juhl2eebb192006-06-23 02:05:26 -07005107 if (cp->active)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 card->active_ctrl = cp->active;
Jesper Juhl2eebb192006-06-23 02:05:26 -07005109 if (cp->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110 card->amp_init = cp->amp_init;
5111 break;
5112 }
5113 cp++;
5114 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005115 if (cp->name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 printk(KERN_INFO "cs46xx: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
5117 ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005118 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 printk(KERN_INFO "cs46xx: %s (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
5120 cp->name, ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
5121 }
5122
Jesper Juhl2eebb192006-06-23 02:05:26 -07005123 if (card->amplifier_ctrl == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 card->amplifier_ctrl = amp_none;
5125 card->active_ctrl = clkrun_hack;
5126 }
5127
Jesper Juhl2eebb192006-06-23 02:05:26 -07005128 if (external_amp == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 printk(KERN_INFO "cs46xx: Crystal EAPD support forced on.\n");
5130 card->amplifier_ctrl = amp_voyetra;
5131 }
5132
Jesper Juhl2eebb192006-06-23 02:05:26 -07005133 if (thinkpad == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005134 printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n");
5135 card->active_ctrl = clkrun_hack;
5136 }
5137/*
5138* The thinkpads don't work well without runtime updating on their kernel
5139* delay values (or any laptop with variable CPU speeds really).
5140* so, just to be safe set the init delay to 2100. Eliminates
5141* failures on T21 Thinkpads. remove this code when the udelay
5142* and mdelay kernel code is replaced by a pm timer, or the delays
5143* work well for battery and/or AC power both.
5144*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07005145 if (card->active_ctrl == clkrun_hack) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 initdelay = 2100;
5147 cs_laptop_wait = 5;
5148 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005149 if ((card->active_ctrl == clkrun_hack) && !(powerdown == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150/*
5151* for some currently unknown reason, powering down the DAC and ADC component
5152* blocks on thinkpads causes some funky behavior... distoorrrtion and ac97
5153* codec access problems. probably the serial clock becomes unsynced.
5154* added code to sync the chips back up, but only helped about 70% the time.
5155*/
5156 cs_powerdown = 0;
5157 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005158 if (powerdown == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 cs_powerdown = 0;
5160 card->active_ctrl(card, 1);
5161
5162 /* claim our iospace and irq */
5163
5164 card->ba0 = ioremap_nocache(card->ba0_addr, CS461X_BA0_SIZE);
5165 card->ba1.name.data0 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
5166 card->ba1.name.data1 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
5167 card->ba1.name.pmem = ioremap_nocache(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
5168 card->ba1.name.reg = ioremap_nocache(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
5169
5170 CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO
5171 "cs46xx: card=%p card->ba0=%p\n",card,card->ba0) );
5172 CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO
5173 "cs46xx: card->ba1=%p %p %p %p\n",
5174 card->ba1.name.data0,
5175 card->ba1.name.data1,
5176 card->ba1.name.pmem,
5177 card->ba1.name.reg) );
5178
Jesper Juhl2eebb192006-06-23 02:05:26 -07005179 if (card->ba0 == 0 || card->ba1.name.data0 == 0 ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 card->ba1.name.data1 == 0 || card->ba1.name.pmem == 0 ||
5181 card->ba1.name.reg == 0)
5182 goto fail2;
5183
Thomas Gleixner65ca68b2006-07-01 19:29:46 -07005184 if (request_irq(card->irq, &cs_interrupt, IRQF_SHARED, "cs46xx", card)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 printk(KERN_ERR "cs46xx: unable to allocate irq %d\n", card->irq);
5186 goto fail2;
5187 }
5188 /* register /dev/dsp */
5189 if ((card->dev_audio = register_sound_dsp(&cs461x_fops, -1)) < 0) {
5190 printk(KERN_ERR "cs46xx: unable to register dsp\n");
5191 goto fail;
5192 }
5193
5194 /* register /dev/midi */
Jesper Juhl2eebb192006-06-23 02:05:26 -07005195 if ((card->dev_midi = register_sound_midi(&cs_midi_fops, -1)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 printk(KERN_ERR "cs46xx: unable to register midi\n");
5197
5198 card->pm.flags |= CS46XX_PM_IDLE;
Jesper Juhl2eebb192006-06-23 02:05:26 -07005199 for (i = 0; i < 5; i++) {
5200 if (cs_hardware_init(card) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 CS_DBGOUT(CS_ERROR, 4, printk(
5202 "cs46xx: ERROR in cs_hardware_init()... retrying\n"));
5203 for (j = 0; j < NR_AC97; j++)
5204 if (card->ac97_codec[j] != NULL) {
5205 unregister_sound_mixer(card->ac97_codec[j]->dev_mixer);
5206 ac97_release_codec(card->ac97_codec[j]);
5207 }
5208 mdelay(10 * cs_laptop_wait);
5209 continue;
5210 }
5211 break;
5212 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005213 if(i >= 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
5215 "cs46xx: cs46xx_probe()- cs_hardware_init() failed, retried %d times.\n",i));
5216 unregister_sound_dsp(card->dev_audio);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005217 if (card->dev_midi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 unregister_sound_midi(card->dev_midi);
5219 goto fail;
5220 }
5221
5222 init_waitqueue_head(&card->midi.open_wait);
Ingo Molnar910f5d22006-03-23 03:00:39 -08005223 mutex_init(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 init_waitqueue_head(&card->midi.iwait);
5225 init_waitqueue_head(&card->midi.owait);
5226 cs461x_pokeBA0(card, BA0_MIDCR, MIDCR_MRST);
5227 cs461x_pokeBA0(card, BA0_MIDCR, 0);
5228
5229 /*
5230 * Check if we have to init the amplifier, but probably already done
5231 * since the CD logic in the ac97 init code will turn on the ext amp.
5232 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07005233 if (cp->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 cp->amp_init(card);
5235 card->active_ctrl(card, -1);
5236
5237 PCI_SET_DRIVER_DATA(pci_dev, card);
5238 PCI_SET_DMA_MASK(pci_dev, dma_mask);
5239 list_add(&card->list, &cs46xx_devs);
5240
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 CS_DBGOUT(CS_PM, 9, printk(KERN_INFO "cs46xx: pm.flags=0x%x card=%p\n",
5242 (unsigned)card->pm.flags,card));
5243
5244 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5245 "cs46xx: probe()- device allocated successfully\n"));
5246 return 0;
5247
5248fail:
5249 free_irq(card->irq, card);
5250fail2:
Jesper Juhl2eebb192006-06-23 02:05:26 -07005251 if (card->ba0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 iounmap(card->ba0);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005253 if (card->ba1.name.data0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 iounmap(card->ba1.name.data0);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005255 if (card->ba1.name.data1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 iounmap(card->ba1.name.data1);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005257 if (card->ba1.name.pmem)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258 iounmap(card->ba1.name.pmem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005259 if (card->ba1.name.reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260 iounmap(card->ba1.name.reg);
5261 kfree(card);
5262 CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
5263 "cs46xx: probe()- no device allocated\n"));
5264 return -ENODEV;
5265} // probe_cs46xx
5266
5267// ---------------------------------------------------------------------
5268
5269static void __devexit cs46xx_remove(struct pci_dev *pci_dev)
5270{
5271 struct cs_card *card = PCI_GET_DRIVER_DATA(pci_dev);
5272 int i;
5273 unsigned int tmp;
5274
5275 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5276 "cs46xx: cs46xx_remove()+\n"));
5277
5278 card->active_ctrl(card,1);
5279
5280 tmp = cs461x_peek(card, BA1_PFIE);
5281 tmp &= ~0x0000f03f;
5282 tmp |= 0x00000010;
5283 cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */
5284
5285 tmp = cs461x_peek(card, BA1_CIE);
5286 tmp &= ~0x0000003f;
5287 tmp |= 0x00000011;
5288 cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */
5289
5290 /*
5291 * Stop playback DMA.
5292 */
5293 tmp = cs461x_peek(card, BA1_PCTL);
5294 cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
5295
5296 /*
5297 * Stop capture DMA.
5298 */
5299 tmp = cs461x_peek(card, BA1_CCTL);
5300 cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
5301
5302 /*
5303 * Reset the processor.
5304 */
5305 cs461x_reset(card);
5306
5307 cs461x_proc_stop(card);
5308
5309 /*
5310 * Power down the DAC and ADC. We will power them up (if) when we need
5311 * them.
5312 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07005313 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
5314 CS_POWER_MIXVON, CS_TRUE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
5316 "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
5317 }
5318
5319 /*
5320 * Power down the PLL.
5321 */
5322 cs461x_pokeBA0(card, BA0_CLKCR1, 0);
5323
5324 /*
5325 * Turn off the Processor by turning off the software clock enable flag in
5326 * the clock control register.
5327 */
5328 tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE;
5329 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
5330
5331 card->active_ctrl(card,-1);
5332
5333 /* free hardware resources */
5334 free_irq(card->irq, card);
5335 iounmap(card->ba0);
5336 iounmap(card->ba1.name.data0);
5337 iounmap(card->ba1.name.data1);
5338 iounmap(card->ba1.name.pmem);
5339 iounmap(card->ba1.name.reg);
5340
5341 /* unregister audio devices */
5342 for (i = 0; i < NR_AC97; i++)
5343 if (card->ac97_codec[i] != NULL) {
5344 unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
5345 ac97_release_codec(card->ac97_codec[i]);
5346 }
5347 unregister_sound_dsp(card->dev_audio);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005348 if (card->dev_midi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349 unregister_sound_midi(card->dev_midi);
5350 list_del(&card->list);
5351 kfree(card);
5352 PCI_SET_DRIVER_DATA(pci_dev,NULL);
5353
5354 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5355 "cs46xx: cs46xx_remove()-: remove successful\n"));
5356}
5357
5358enum {
5359 CS46XX_4610 = 0,
5360 CS46XX_4612, /* same as 4630 */
5361 CS46XX_4615, /* same as 4624 */
5362};
5363
5364static struct pci_device_id cs46xx_pci_tbl[] = {
5365 {
5366 .vendor = PCI_VENDOR_ID_CIRRUS,
5367 .device = PCI_DEVICE_ID_CIRRUS_4610,
5368 .subvendor = PCI_ANY_ID,
5369 .subdevice = PCI_ANY_ID,
5370 .driver_data = CS46XX_4610,
5371 },
5372 {
5373 .vendor = PCI_VENDOR_ID_CIRRUS,
5374 .device = PCI_DEVICE_ID_CIRRUS_4612,
5375 .subvendor = PCI_ANY_ID,
5376 .subdevice = PCI_ANY_ID,
5377 .driver_data = CS46XX_4612,
5378 },
5379 {
5380 .vendor = PCI_VENDOR_ID_CIRRUS,
5381 .device = PCI_DEVICE_ID_CIRRUS_4615,
5382 .subvendor = PCI_ANY_ID,
5383 .subdevice = PCI_ANY_ID,
5384 .driver_data = CS46XX_4615,
5385 },
5386 { 0, },
5387};
5388
5389MODULE_DEVICE_TABLE(pci, cs46xx_pci_tbl);
5390
5391static struct pci_driver cs46xx_pci_driver = {
5392 .name = "cs46xx",
5393 .id_table = cs46xx_pci_tbl,
5394 .probe = cs46xx_probe,
5395 .remove = __devexit_p(cs46xx_remove),
Alexey Dobriyan99f932f2006-09-29 02:00:18 -07005396#ifdef CONFIG_PM
5397 .suspend = cs46xx_suspend_tbl,
5398 .resume = cs46xx_resume_tbl,
5399#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400};
5401
5402static int __init cs46xx_init_module(void)
5403{
5404 int rtn = 0;
5405 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5406 "cs46xx: cs46xx_init_module()+ \n"));
Greg Kroah-Hartman46654722005-12-06 15:33:15 -08005407 rtn = pci_register_driver(&cs46xx_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408
Jesper Juhl2eebb192006-06-23 02:05:26 -07005409 if (rtn == -ENODEV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(
5411 "cs46xx: Unable to detect valid cs46xx device\n"));
5412 }
5413
5414 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
5415 printk(KERN_INFO "cs46xx: cs46xx_init_module()- (%d)\n",rtn));
5416 return rtn;
5417}
5418
5419static void __exit cs46xx_cleanup_module(void)
5420{
5421 pci_unregister_driver(&cs46xx_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
5423 printk(KERN_INFO "cs46xx: cleanup_cs46xx() finished\n"));
5424}
5425
5426module_init(cs46xx_init_module);
5427module_exit(cs46xx_cleanup_module);
5428
Alexey Dobriyan99f932f2006-09-29 02:00:18 -07005429#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state)
5431{
5432 struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
5433 CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
5434 printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
Pavel Machek2a569572005-07-07 17:56:40 -07005435 cs46xx_suspend(s, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 return 0;
5437}
5438
5439static int cs46xx_resume_tbl(struct pci_dev *pcidev)
5440{
5441 struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
5442 CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
5443 printk(KERN_INFO "cs46xx: cs46xx_resume_tbl request\n"));
5444 cs46xx_resume(s);
5445 return 0;
5446}
5447#endif