blob: 3f81b79afbaaa23145d429ce482b39a09ffbed94 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95#include <asm/io.h>
96#include <asm/dma.h>
97#include <asm/uaccess.h>
98
Alexey Dobriyan99f932f2006-09-29 02:00:18 -070099#include "cs46xxpm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100#include "cs46xx_wrapper-24.h"
101#include "cs461x.h"
102
103/* MIDI buffer sizes */
104#define CS_MIDIINBUF 500
105#define CS_MIDIOUTBUF 500
106
107#define ADC_RUNNING 1
108#define DAC_RUNNING 2
109
110#define CS_FMT_16BIT 1 /* These are fixed in fact */
111#define CS_FMT_STEREO 2
112#define CS_FMT_MASK 3
113
114#define CS_TYPE_ADC 1
115#define CS_TYPE_DAC 2
116
117#define CS_TRUE 1
118#define CS_FALSE 0
119
120#define CS_INC_USE_COUNT(m) (atomic_inc(m))
121#define CS_DEC_USE_COUNT(m) (atomic_dec(m))
122#define CS_DEC_AND_TEST(m) (atomic_dec_and_test(m))
123#define CS_IN_USE(m) (atomic_read(m) != 0)
124
125#define CS_DBGBREAKPOINT {__asm__("INT $3");}
126/*
127 * CS461x definitions
128 */
129
130#define CS461X_BA0_SIZE 0x2000
131#define CS461X_BA1_DATA0_SIZE 0x3000
132#define CS461X_BA1_DATA1_SIZE 0x3800
133#define CS461X_BA1_PRG_SIZE 0x7000
134#define CS461X_BA1_REG_SIZE 0x0100
135
136#define GOF_PER_SEC 200
137
138#define CSDEBUG_INTERFACE 1
139#define CSDEBUG 1
140/*
141 * Turn on/off debugging compilation by using 1/0 respectively for CSDEBUG
142 *
143 *
144 * CSDEBUG is usual mode is set to 1, then use the
145 * cs_debuglevel and cs_debugmask to turn on or off debugging.
146 * Debug level of 1 has been defined to be kernel errors and info
147 * that should be printed on any released driver.
148 */
149#if CSDEBUG
Jesper Juhl2eebb192006-06-23 02:05:26 -0700150#define CS_DBGOUT(mask,level,x) if ((cs_debuglevel >= (level)) && ((mask) & cs_debugmask)) {x;}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151#else
152#define CS_DBGOUT(mask,level,x)
153#endif
154/*
155 * cs_debugmask areas
156 */
157#define CS_INIT 0x00000001 /* initialization and probe functions */
158#define CS_ERROR 0x00000002 /* tmp debugging bit placeholder */
159#define CS_INTERRUPT 0x00000004 /* interrupt handler (separate from all other) */
160#define CS_FUNCTION 0x00000008 /* enter/leave functions */
161#define CS_WAVE_WRITE 0x00000010 /* write information for wave */
162#define CS_WAVE_READ 0x00000020 /* read information for wave */
163#define CS_MIDI_WRITE 0x00000040 /* write information for midi */
164#define CS_MIDI_READ 0x00000080 /* read information for midi */
165#define CS_MPU401_WRITE 0x00000100 /* write information for mpu401 */
166#define CS_MPU401_READ 0x00000200 /* read information for mpu401 */
167#define CS_OPEN 0x00000400 /* all open functions in the driver */
168#define CS_RELEASE 0x00000800 /* all release functions in the driver */
169#define CS_PARMS 0x00001000 /* functional and operational parameters */
170#define CS_IOCTL 0x00002000 /* ioctl (non-mixer) */
171#define CS_PM 0x00004000 /* PM */
172#define CS_TMP 0x10000000 /* tmp debug mask bit */
173
174#define CS_IOCTL_CMD_SUSPEND 0x1 // suspend
175#define CS_IOCTL_CMD_RESUME 0x2 // resume
176
177#if CSDEBUG
Jesper Juhl2eebb192006-06-23 02:05:26 -0700178static unsigned long cs_debuglevel = 1; /* levels range from 1-9 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179module_param(cs_debuglevel, ulong, 0644);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700180static unsigned long cs_debugmask = CS_INIT | CS_ERROR; /* use CS_DBGOUT with various mask values */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181module_param(cs_debugmask, ulong, 0644);
182#endif
183static unsigned long hercules_egpio_disable; /* if non-zero set all EGPIO to 0 */
184module_param(hercules_egpio_disable, ulong, 0);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700185static unsigned long initdelay = 700; /* PM delay in millisecs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186module_param(initdelay, ulong, 0);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700187static unsigned long powerdown = -1; /* turn on/off powerdown processing in driver */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188module_param(powerdown, ulong, 0);
189#define DMABUF_DEFAULTORDER 3
Jesper Juhl2eebb192006-06-23 02:05:26 -0700190static unsigned long defaultorder = DMABUF_DEFAULTORDER;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191module_param(defaultorder, ulong, 0);
192
193static int external_amp;
194module_param(external_amp, bool, 0);
195static int thinkpad;
196module_param(thinkpad, bool, 0);
197
198/*
199* set the powerdown module parm to 0 to disable all
200* powerdown. also set thinkpad to 1 to disable powerdown,
201* but also to enable the clkrun functionality.
202*/
Jesper Juhl2eebb192006-06-23 02:05:26 -0700203static unsigned cs_powerdown = 1;
204static unsigned cs_laptop_wait = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206/* An instance of the 4610 channel */
207struct cs_channel
208{
209 int used;
210 int num;
211 void *state;
212};
213
214#define CS46XX_MAJOR_VERSION "1"
215#define CS46XX_MINOR_VERSION "28"
216
217#ifdef __ia64__
218#define CS46XX_ARCH "64" //architecture key
219#else
220#define CS46XX_ARCH "32" //architecture key
221#endif
222
223static struct list_head cs46xx_devs = { &cs46xx_devs, &cs46xx_devs };
224
225/* magic numbers to protect our data structures */
226#define CS_CARD_MAGIC 0x43525553 /* "CRUS" */
227#define CS_STATE_MAGIC 0x4c4f4749 /* "LOGI" */
228#define NR_HW_CH 3
229
230/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
231#define NR_AC97 2
232
233static const unsigned sample_size[] = { 1, 2, 2, 4 };
234static const unsigned sample_shift[] = { 0, 1, 1, 2 };
235
236/* "software" or virtual channel, an instance of opened /dev/dsp */
237struct cs_state {
238 unsigned int magic;
239 struct cs_card *card; /* Card info */
240
241 /* single open lock mechanism, only used for recording */
Ingo Molnar910f5d22006-03-23 03:00:39 -0800242 struct mutex open_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 wait_queue_head_t open_wait;
244
245 /* file mode */
246 mode_t open_mode;
247
248 /* virtual channel number */
249 int virt;
250
251 struct dmabuf {
252 /* wave sample stuff */
253 unsigned int rate;
254 unsigned char fmt, enable;
255
256 /* hardware channel */
257 struct cs_channel *channel;
258 int pringbuf; /* Software ring slot */
259 void *pbuf; /* 4K hardware DMA buffer */
260
261 /* OSS buffer management stuff */
262 void *rawbuf;
263 dma_addr_t dma_handle;
264 unsigned buforder;
265 unsigned numfrag;
266 unsigned fragshift;
267 unsigned divisor;
268 unsigned type;
269 void *tmpbuff; /* tmp buffer for sample conversions */
270 dma_addr_t dmaaddr;
271 dma_addr_t dmaaddr_tmpbuff;
272 unsigned buforder_tmpbuff; /* Log base 2 of size in bytes.. */
273
274 /* our buffer acts like a circular ring */
275 unsigned hwptr; /* where dma last started, updated by update_ptr */
276 unsigned swptr; /* where driver last clear/filled, updated by read/write */
277 int count; /* bytes to be comsumed or been generated by dma machine */
278 unsigned total_bytes; /* total bytes dmaed by hardware */
279 unsigned blocks; /* total blocks */
280
281 unsigned error; /* number of over/underruns */
282 unsigned underrun; /* underrun pending before next write has occurred */
283 wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
284
285 /* redundant, but makes calculations easier */
286 unsigned fragsize;
287 unsigned dmasize;
288 unsigned fragsamples;
289
290 /* OSS stuff */
291 unsigned mapped:1;
292 unsigned ready:1;
293 unsigned endcleared:1;
294 unsigned SGok:1;
295 unsigned update_flag;
296 unsigned ossfragshift;
297 int ossmaxfrags;
298 unsigned subdivision;
299 } dmabuf;
300 /* Guard against mmap/write/read races */
Ingo Molnar910f5d22006-03-23 03:00:39 -0800301 struct mutex sem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302};
303
304struct cs_card {
305 struct cs_channel channel[2];
306 unsigned int magic;
307
308 /* We keep cs461x cards in a linked list */
309 struct cs_card *next;
310
311 /* The cs461x has a certain amount of cross channel interaction
312 so we use a single per card lock */
313 spinlock_t lock;
314
315 /* Keep AC97 sane */
316 spinlock_t ac97_lock;
317
318 /* mixer use count */
319 atomic_t mixer_use_cnt;
320
321 /* PCI device stuff */
Jesper Juhl2eebb192006-06-23 02:05:26 -0700322 struct pci_dev *pci_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 struct list_head list;
324
325 unsigned int pctl, cctl; /* Hardware DMA flag sets */
326
327 /* soundcore stuff */
328 int dev_audio;
329 int dev_midi;
330
331 /* structures for abstraction of hardware facilities, codecs, banks and channels*/
332 struct ac97_codec *ac97_codec[NR_AC97];
333 struct cs_state *states[2];
334
335 u16 ac97_features;
336
337 int amplifier; /* Amplifier control */
338 void (*amplifier_ctrl)(struct cs_card *, int);
339 void (*amp_init)(struct cs_card *);
340
341 int active; /* Active clocking */
342 void (*active_ctrl)(struct cs_card *, int);
343
344 /* hardware resources */
345 unsigned long ba0_addr;
346 unsigned long ba1_addr;
347 u32 irq;
348
349 /* mappings */
350 void __iomem *ba0;
351 union
352 {
353 struct
354 {
355 u8 __iomem *data0;
356 u8 __iomem *data1;
357 u8 __iomem *pmem;
358 u8 __iomem *reg;
359 } name;
360 u8 __iomem *idx[4];
361 } ba1;
362
363 /* Function support */
364 struct cs_channel *(*alloc_pcm_channel)(struct cs_card *);
365 struct cs_channel *(*alloc_rec_pcm_channel)(struct cs_card *);
366 void (*free_pcm_channel)(struct cs_card *, int chan);
367
368 /* /dev/midi stuff */
369 struct {
370 unsigned ird, iwr, icnt;
371 unsigned ord, owr, ocnt;
372 wait_queue_head_t open_wait;
373 wait_queue_head_t iwait;
374 wait_queue_head_t owait;
375 spinlock_t lock;
376 unsigned char ibuf[CS_MIDIINBUF];
377 unsigned char obuf[CS_MIDIOUTBUF];
378 mode_t open_mode;
Ingo Molnar910f5d22006-03-23 03:00:39 -0800379 struct mutex open_mutex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 } midi;
381 struct cs46xx_pm pm;
382};
383
384static int cs_open_mixdev(struct inode *inode, struct file *file);
385static int cs_release_mixdev(struct inode *inode, struct file *file);
386static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
Jesper Juhl2eebb192006-06-23 02:05:26 -0700387 unsigned long arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388static int cs_hardware_init(struct cs_card *card);
389static int cs46xx_powerup(struct cs_card *card, unsigned int type);
390static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag);
391static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type);
Alexey Dobriyan99f932f2006-09-29 02:00:18 -0700392#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state);
394static int cs46xx_resume_tbl(struct pci_dev *pcidev);
Alexey Dobriyan99f932f2006-09-29 02:00:18 -0700395#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397#if CSDEBUG
398
399/* DEBUG ROUTINES */
400
401#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int)
402#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int)
403#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int)
404#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int)
405#define SOUND_MIXER_CS_APM _SIOWR('M',124, int)
406
407static void printioctl(unsigned int x)
408{
409 unsigned int i;
410 unsigned char vidx;
411 /* these values are incorrect for the ac97 driver, fix.
412 * Index of mixtable1[] member is Device ID
413 * and must be <= SOUND_MIXER_NRDEVICES.
414 * Value of array member is index into s->mix.vol[]
415 */
416 static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
417 [SOUND_MIXER_PCM] = 1, /* voice */
418 [SOUND_MIXER_LINE1] = 2, /* AUX */
419 [SOUND_MIXER_CD] = 3, /* CD */
420 [SOUND_MIXER_LINE] = 4, /* Line */
421 [SOUND_MIXER_SYNTH] = 5, /* FM */
422 [SOUND_MIXER_MIC] = 6, /* Mic */
423 [SOUND_MIXER_SPEAKER] = 7, /* Speaker */
424 [SOUND_MIXER_RECLEV] = 8, /* Recording level */
425 [SOUND_MIXER_VOLUME] = 9 /* Master Volume */
426 };
427
Jesper Juhl2eebb192006-06-23 02:05:26 -0700428 switch (x) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 case SOUND_MIXER_CS_GETDBGMASK:
430 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGMASK: ") );
431 break;
432 case SOUND_MIXER_CS_GETDBGLEVEL:
433 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGLEVEL: ") );
434 break;
435 case SOUND_MIXER_CS_SETDBGMASK:
436 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGMASK: ") );
437 break;
438 case SOUND_MIXER_CS_SETDBGLEVEL:
439 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGLEVEL: ") );
440 break;
441 case OSS_GETVERSION:
442 CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION: ") );
443 break;
444 case SNDCTL_DSP_SYNC:
445 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC: ") );
446 break;
447 case SNDCTL_DSP_SETDUPLEX:
448 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX: ") );
449 break;
450 case SNDCTL_DSP_GETCAPS:
451 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS: ") );
452 break;
453 case SNDCTL_DSP_RESET:
454 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET: ") );
455 break;
456 case SNDCTL_DSP_SPEED:
457 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED: ") );
458 break;
459 case SNDCTL_DSP_STEREO:
460 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO: ") );
461 break;
462 case SNDCTL_DSP_CHANNELS:
463 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS: ") );
464 break;
465 case SNDCTL_DSP_GETFMTS:
466 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS: ") );
467 break;
468 case SNDCTL_DSP_SETFMT:
469 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT: ") );
470 break;
471 case SNDCTL_DSP_POST:
472 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST: ") );
473 break;
474 case SNDCTL_DSP_GETTRIGGER:
475 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER: ") );
476 break;
477 case SNDCTL_DSP_SETTRIGGER:
478 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER: ") );
479 break;
480 case SNDCTL_DSP_GETOSPACE:
481 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE: ") );
482 break;
483 case SNDCTL_DSP_GETISPACE:
484 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE: ") );
485 break;
486 case SNDCTL_DSP_NONBLOCK:
487 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK: ") );
488 break;
489 case SNDCTL_DSP_GETODELAY:
490 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY: ") );
491 break;
492 case SNDCTL_DSP_GETIPTR:
493 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR: ") );
494 break;
495 case SNDCTL_DSP_GETOPTR:
496 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR: ") );
497 break;
498 case SNDCTL_DSP_GETBLKSIZE:
499 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE: ") );
500 break;
501 case SNDCTL_DSP_SETFRAGMENT:
502 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFRAGMENT: ") );
503 break;
504 case SNDCTL_DSP_SUBDIVIDE:
505 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE: ") );
506 break;
507 case SOUND_PCM_READ_RATE:
508 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE: ") );
509 break;
510 case SOUND_PCM_READ_CHANNELS:
511 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_CHANNELS: ") );
512 break;
513 case SOUND_PCM_READ_BITS:
514 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS: ") );
515 break;
516 case SOUND_PCM_WRITE_FILTER:
517 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_WRITE_FILTER: ") );
518 break;
519 case SNDCTL_DSP_SETSYNCRO:
520 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO: ") );
521 break;
522 case SOUND_PCM_READ_FILTER:
523 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER: ") );
524 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 case SOUND_MIXER_PRIVATE1:
526 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1: ") );
527 break;
528 case SOUND_MIXER_PRIVATE2:
529 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2: ") );
530 break;
531 case SOUND_MIXER_PRIVATE3:
532 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3: ") );
533 break;
534 case SOUND_MIXER_PRIVATE4:
535 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4: ") );
536 break;
537 case SOUND_MIXER_PRIVATE5:
538 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5: ") );
539 break;
540 case SOUND_MIXER_INFO:
541 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO: ") );
542 break;
543 case SOUND_OLD_MIXER_INFO:
544 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO: ") );
545 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 default:
Jesper Juhl2eebb192006-06-23 02:05:26 -0700547 switch (_IOC_NR(x)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 case SOUND_MIXER_VOLUME:
549 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_VOLUME: ") );
550 break;
551 case SOUND_MIXER_SPEAKER:
552 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SPEAKER: ") );
553 break;
554 case SOUND_MIXER_RECLEV:
555 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECLEV: ") );
556 break;
557 case SOUND_MIXER_MIC:
558 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_MIC: ") );
559 break;
560 case SOUND_MIXER_SYNTH:
561 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SYNTH: ") );
562 break;
563 case SOUND_MIXER_RECSRC:
564 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECSRC: ") );
565 break;
566 case SOUND_MIXER_DEVMASK:
567 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_DEVMASK: ") );
568 break;
569 case SOUND_MIXER_RECMASK:
570 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECMASK: ") );
571 break;
572 case SOUND_MIXER_STEREODEVS:
573 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_STEREODEVS: ") );
574 break;
575 case SOUND_MIXER_CAPS:
576 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:") );
577 break;
578 default:
579 i = _IOC_NR(x);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700580 if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 CS_DBGOUT(CS_IOCTL, 4, printk("UNKNOWN IOCTL: 0x%.8x NR=%d ",x,i) );
Jesper Juhl2eebb192006-06-23 02:05:26 -0700582 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d ",
Jesper Juhl2eebb192006-06-23 02:05:26 -0700584 x,i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 }
586 break;
587 }
588 }
589 CS_DBGOUT(CS_IOCTL, 4, printk("command = 0x%x IOC_NR=%d\n",x, _IOC_NR(x)) );
590}
591#endif
592
593/*
594 * common I/O routines
595 */
596
597static void cs461x_poke(struct cs_card *codec, unsigned long reg, unsigned int val)
598{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700599 writel(val, codec->ba1.idx[(reg >> 16) & 3] + (reg & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600}
601
602static unsigned int cs461x_peek(struct cs_card *codec, unsigned long reg)
603{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700604 return readl(codec->ba1.idx[(reg >> 16) & 3] + (reg & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605}
606
607static void cs461x_pokeBA0(struct cs_card *codec, unsigned long reg, unsigned int val)
608{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700609 writel(val, codec->ba0 + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610}
611
612static unsigned int cs461x_peekBA0(struct cs_card *codec, unsigned long reg)
613{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700614 return readl(codec->ba0 + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615}
616
617
618static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg);
619static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
620
621static struct cs_channel *cs_alloc_pcm_channel(struct cs_card *card)
622{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700623 if (card->channel[1].used == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 return NULL;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700625 card->channel[1].used = 1;
626 card->channel[1].num = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 return &card->channel[1];
628}
629
630static struct cs_channel *cs_alloc_rec_pcm_channel(struct cs_card *card)
631{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700632 if (card->channel[0].used == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 return NULL;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700634 card->channel[0].used = 1;
635 card->channel[0].num = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 return &card->channel[0];
637}
638
639static void cs_free_pcm_channel(struct cs_card *card, int channel)
640{
641 card->channel[channel].state = NULL;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700642 card->channel[channel].used = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643}
644
645/*
646 * setup a divisor value to help with conversion from
647 * 16bit Stereo, down to 8bit stereo/mono or 16bit mono.
648 * assign a divisor of 1 if using 16bit Stereo as that is
649 * the only format that the static image will capture.
650 */
651static void cs_set_divisor(struct dmabuf *dmabuf)
652{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700653 if (dmabuf->type == CS_TYPE_DAC)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 dmabuf->divisor = 1;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700655 else if (!(dmabuf->fmt & CS_FMT_STEREO) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 (dmabuf->fmt & CS_FMT_16BIT))
657 dmabuf->divisor = 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700658 else if ((dmabuf->fmt & CS_FMT_STEREO) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 !(dmabuf->fmt & CS_FMT_16BIT))
660 dmabuf->divisor = 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700661 else if (!(dmabuf->fmt & CS_FMT_STEREO) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 !(dmabuf->fmt & CS_FMT_16BIT))
663 dmabuf->divisor = 4;
664 else
665 dmabuf->divisor = 1;
666
667 CS_DBGOUT(CS_PARMS | CS_FUNCTION, 8, printk(
668 "cs46xx: cs_set_divisor()- %s %d\n",
669 (dmabuf->type == CS_TYPE_ADC) ? "ADC" : "DAC",
670 dmabuf->divisor) );
671}
672
673/*
674* mute some of the more prevalent registers to avoid popping.
675*/
676static void cs_mute(struct cs_card *card, int state)
677{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700678 struct ac97_codec *dev = card->ac97_codec[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
680 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()+ %s\n",
Jesper Juhl2eebb192006-06-23 02:05:26 -0700681 (state == CS_TRUE) ? "Muting" : "UnMuting"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Jesper Juhl2eebb192006-06-23 02:05:26 -0700683 if (state == CS_TRUE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 /*
685 * fix pops when powering up on thinkpads
686 */
687 card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev,
688 (u8)BA0_AC97_MASTER_VOLUME);
689 card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev,
690 (u8)BA0_AC97_HEADPHONE_VOLUME);
691 card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev,
692 (u8)BA0_AC97_MASTER_VOLUME_MONO);
693 card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev,
694 (u8)BA0_AC97_PCM_OUT_VOLUME);
695
696 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
697 cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
698 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
699 cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700700 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, card->pm.u32AC97_master_volume);
702 cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, card->pm.u32AC97_headphone_volume);
703 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, card->pm.u32AC97_master_volume_mono);
704 cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, card->pm.u32AC97_pcm_out_volume);
705 }
706 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()-\n"));
707}
708
709/* set playback sample rate */
710static unsigned int cs_set_dac_rate(struct cs_state * state, unsigned int rate)
711{
712 struct dmabuf *dmabuf = &state->dmabuf;
713 unsigned int tmp1, tmp2;
714 unsigned int phiIncr;
715 unsigned int correctionPerGOF, correctionPerSec;
716 unsigned long flags;
717
718 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()+ %d\n",rate) );
719
720 /*
721 * Compute the values used to drive the actual sample rate conversion.
722 * The following formulas are being computed, using inline assembly
723 * since we need to use 64 bit arithmetic to compute the values:
724 *
725 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
726 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
727 * GOF_PER_SEC)
728 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
729 * GOF_PER_SEC * correctionPerGOF
730 *
731 * i.e.
732 *
733 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
734 * correctionPerGOF:correctionPerSec =
735 * dividend:remainder(ulOther / GOF_PER_SEC)
736 */
737 tmp1 = rate << 16;
738 phiIncr = tmp1 / 48000;
739 tmp1 -= phiIncr * 48000;
740 tmp1 <<= 10;
741 phiIncr <<= 10;
742 tmp2 = tmp1 / 48000;
743 phiIncr += tmp2;
744 tmp1 -= tmp2 * 48000;
745 correctionPerGOF = tmp1 / GOF_PER_SEC;
746 tmp1 -= correctionPerGOF * GOF_PER_SEC;
747 correctionPerSec = tmp1;
748
749 /*
750 * Fill in the SampleRateConverter control block.
751 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 spin_lock_irqsave(&state->card->lock, flags);
753 cs461x_poke(state->card, BA1_PSRC,
754 ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
755 cs461x_poke(state->card, BA1_PPI, phiIncr);
756 spin_unlock_irqrestore(&state->card->lock, flags);
757 dmabuf->rate = rate;
758
759 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()- %d\n",rate) );
760 return rate;
761}
762
763/* set recording sample rate */
Jesper Juhl2eebb192006-06-23 02:05:26 -0700764static unsigned int cs_set_adc_rate(struct cs_state *state, unsigned int rate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765{
766 struct dmabuf *dmabuf = &state->dmabuf;
767 struct cs_card *card = state->card;
768 unsigned int phiIncr, coeffIncr, tmp1, tmp2;
769 unsigned int correctionPerGOF, correctionPerSec, initialDelay;
770 unsigned int frameGroupLength, cnt;
771 unsigned long flags;
772 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()+ %d\n",rate) );
773
774 /*
775 * We can only decimate by up to a factor of 1/9th the hardware rate.
776 * Correct the value if an attempt is made to stray outside that limit.
777 */
778 if ((rate * 9) < 48000)
779 rate = 48000 / 9;
780
781 /*
782 * We can not capture at at rate greater than the Input Rate (48000).
783 * Return an error if an attempt is made to stray outside that limit.
784 */
785 if (rate > 48000)
786 rate = 48000;
787
788 /*
789 * Compute the values used to drive the actual sample rate conversion.
790 * The following formulas are being computed, using inline assembly
791 * since we need to use 64 bit arithmetic to compute the values:
792 *
793 * coeffIncr = -floor((Fs,out * 2^23) / Fs,in)
794 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
795 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
796 * GOF_PER_SEC)
797 * correctionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -
798 * GOF_PER_SEC * correctionPerGOF
799 * initialDelay = ceil((24 * Fs,in) / Fs,out)
800 *
801 * i.e.
802 *
803 * coeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in))
804 * phiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out)
805 * correctionPerGOF:correctionPerSec =
806 * dividend:remainder(ulOther / GOF_PER_SEC)
807 * initialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out)
808 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 tmp1 = rate << 16;
810 coeffIncr = tmp1 / 48000;
811 tmp1 -= coeffIncr * 48000;
812 tmp1 <<= 7;
813 coeffIncr <<= 7;
814 coeffIncr += tmp1 / 48000;
815 coeffIncr ^= 0xFFFFFFFF;
816 coeffIncr++;
817 tmp1 = 48000 << 16;
818 phiIncr = tmp1 / rate;
819 tmp1 -= phiIncr * rate;
820 tmp1 <<= 10;
821 phiIncr <<= 10;
822 tmp2 = tmp1 / rate;
823 phiIncr += tmp2;
824 tmp1 -= tmp2 * rate;
825 correctionPerGOF = tmp1 / GOF_PER_SEC;
826 tmp1 -= correctionPerGOF * GOF_PER_SEC;
827 correctionPerSec = tmp1;
828 initialDelay = ((48000 * 24) + rate - 1) / rate;
829
830 /*
831 * Fill in the VariDecimate control block.
832 */
833 spin_lock_irqsave(&card->lock, flags);
834 cs461x_poke(card, BA1_CSRC,
835 ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
836 cs461x_poke(card, BA1_CCI, coeffIncr);
837 cs461x_poke(card, BA1_CD,
838 (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80);
839 cs461x_poke(card, BA1_CPI, phiIncr);
840 spin_unlock_irqrestore(&card->lock, flags);
841
842 /*
843 * Figure out the frame group length for the write back task. Basically,
844 * this is just the factors of 24000 (2^6*3*5^3) that are not present in
845 * the output sample rate.
846 */
847 frameGroupLength = 1;
848 for (cnt = 2; cnt <= 64; cnt *= 2) {
849 if (((rate / cnt) * cnt) != rate)
850 frameGroupLength *= 2;
851 }
852 if (((rate / 3) * 3) != rate) {
853 frameGroupLength *= 3;
854 }
855 for (cnt = 5; cnt <= 125; cnt *= 5) {
856 if (((rate / cnt) * cnt) != rate)
857 frameGroupLength *= 5;
858 }
859
860 /*
861 * Fill in the WriteBack control block.
862 */
863 spin_lock_irqsave(&card->lock, flags);
864 cs461x_poke(card, BA1_CFG1, frameGroupLength);
865 cs461x_poke(card, BA1_CFG2, (0x00800000 | frameGroupLength));
866 cs461x_poke(card, BA1_CCST, 0x0000FFFF);
867 cs461x_poke(card, BA1_CSPB, ((65536 * rate) / 24000));
868 cs461x_poke(card, (BA1_CSPB + 4), 0x0000FFFF);
869 spin_unlock_irqrestore(&card->lock, flags);
870 dmabuf->rate = rate;
871 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()- %d\n",rate) );
872 return rate;
873}
874
875/* prepare channel attributes for playback */
876static void cs_play_setup(struct cs_state *state)
877{
878 struct dmabuf *dmabuf = &state->dmabuf;
879 struct cs_card *card = state->card;
880 unsigned int tmp, Count, playFormat;
881
882 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()+\n") );
883 cs461x_poke(card, BA1_PVOL, 0x80008000);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700884 if (!dmabuf->SGok)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 cs461x_poke(card, BA1_PBA, virt_to_bus(dmabuf->pbuf));
886
887 Count = 4;
888 playFormat=cs461x_peek(card, BA1_PFIE);
889 if ((dmabuf->fmt & CS_FMT_STEREO)) {
890 playFormat &= ~DMA_RQ_C2_AC_MONO_TO_STEREO;
891 Count *= 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700892 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 playFormat |= DMA_RQ_C2_AC_MONO_TO_STEREO;
894
895 if ((dmabuf->fmt & CS_FMT_16BIT)) {
896 playFormat &= ~(DMA_RQ_C2_AC_8_TO_16_BIT
897 | DMA_RQ_C2_AC_SIGNED_CONVERT);
898 Count *= 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700899 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 playFormat |= (DMA_RQ_C2_AC_8_TO_16_BIT
901 | DMA_RQ_C2_AC_SIGNED_CONVERT);
902
903 cs461x_poke(card, BA1_PFIE, playFormat);
904
905 tmp = cs461x_peek(card, BA1_PDTC);
906 tmp &= 0xfffffe00;
907 cs461x_poke(card, BA1_PDTC, tmp | --Count);
908
909 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()-\n") );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910}
911
912static struct InitStruct
913{
914 u32 off;
915 u32 val;
916} InitArray[] = { {0x00000040, 0x3fc0000f},
917 {0x0000004c, 0x04800000},
918
919 {0x000000b3, 0x00000780},
920 {0x000000b7, 0x00000000},
921 {0x000000bc, 0x07800000},
922
923 {0x000000cd, 0x00800000},
924 };
925
926/*
927 * "SetCaptureSPValues()" -- Initialize record task values before each
928 * capture startup.
929 */
930static void SetCaptureSPValues(struct cs_card *card)
931{
932 unsigned i, offset;
933 CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()+\n") );
Jesper Juhl2eebb192006-06-23 02:05:26 -0700934 for (i = 0; i < sizeof(InitArray) / sizeof(struct InitStruct); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 offset = InitArray[i].off*4; /* 8bit to 32bit offset value */
936 cs461x_poke(card, offset, InitArray[i].val );
937 }
938 CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()-\n") );
939}
940
941/* prepare channel attributes for recording */
942static void cs_rec_setup(struct cs_state *state)
943{
944 struct cs_card *card = state->card;
945 struct dmabuf *dmabuf = &state->dmabuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
Jesper Juhl2eebb192006-06-23 02:05:26 -0700947 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()+\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 SetCaptureSPValues(card);
949
950 /*
951 * set the attenuation to 0dB
952 */
953 cs461x_poke(card, BA1_CVOL, 0x80008000);
954
955 /*
956 * set the physical address of the capture buffer into the SP
957 */
958 cs461x_poke(card, BA1_CBA, virt_to_bus(dmabuf->rawbuf));
959
960 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()-\n") );
961}
962
963
964/* get current playback/recording dma buffer pointer (byte offset from LBA),
965 called with spinlock held! */
966
967static inline unsigned cs_get_dma_addr(struct cs_state *state)
968{
969 struct dmabuf *dmabuf = &state->dmabuf;
970 u32 offset;
971
972 if ( (!(dmabuf->enable & DAC_RUNNING)) &&
973 (!(dmabuf->enable & ADC_RUNNING) ) )
974 {
975 CS_DBGOUT(CS_ERROR, 2, printk(
976 "cs46xx: ERROR cs_get_dma_addr(): not enabled \n") );
977 return 0;
978 }
979
980 /*
981 * granularity is byte boundary, good part.
982 */
Jesper Juhl2eebb192006-06-23 02:05:26 -0700983 if (dmabuf->enable & DAC_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 offset = cs461x_peek(state->card, BA1_PBA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 else /* ADC_RUNNING must be set */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 offset = cs461x_peek(state->card, BA1_CBA);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 CS_DBGOUT(CS_PARMS | CS_FUNCTION, 9,
989 printk("cs46xx: cs_get_dma_addr() %d\n",offset) );
990 offset = (u32)bus_to_virt((unsigned long)offset) - (u32)dmabuf->rawbuf;
991 CS_DBGOUT(CS_PARMS | CS_FUNCTION, 8,
992 printk("cs46xx: cs_get_dma_addr()- %d\n",offset) );
993 return offset;
994}
995
996static void resync_dma_ptrs(struct cs_state *state)
997{
998 struct dmabuf *dmabuf;
999
1000 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()+ \n") );
Jesper Juhl2eebb192006-06-23 02:05:26 -07001001 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 dmabuf = &state->dmabuf;
1003 dmabuf->hwptr=dmabuf->swptr = 0;
1004 dmabuf->pringbuf = 0;
1005 }
1006 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()- \n") );
1007}
1008
1009/* Stop recording (lock held) */
1010static inline void __stop_adc(struct cs_state *state)
1011{
1012 struct dmabuf *dmabuf = &state->dmabuf;
1013 struct cs_card *card = state->card;
1014 unsigned int tmp;
1015
1016 dmabuf->enable &= ~ADC_RUNNING;
1017
1018 tmp = cs461x_peek(card, BA1_CCTL);
1019 tmp &= 0xFFFF0000;
1020 cs461x_poke(card, BA1_CCTL, tmp );
1021}
1022
1023static void stop_adc(struct cs_state *state)
1024{
1025 unsigned long flags;
1026
1027 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_adc()+ \n") );
1028 spin_lock_irqsave(&state->card->lock, flags);
1029 __stop_adc(state);
1030 spin_unlock_irqrestore(&state->card->lock, flags);
1031 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_adc()- \n") );
1032}
1033
1034static void start_adc(struct cs_state *state)
1035{
1036 struct dmabuf *dmabuf = &state->dmabuf;
1037 struct cs_card *card = state->card;
1038 unsigned long flags;
1039 unsigned int tmp;
1040
1041 spin_lock_irqsave(&card->lock, flags);
1042 if (!(dmabuf->enable & ADC_RUNNING) &&
1043 ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize)
1044 && dmabuf->ready) &&
1045 ((card->pm.flags & CS46XX_PM_IDLE) ||
1046 (card->pm.flags & CS46XX_PM_RESUMED)) )
1047 {
1048 dmabuf->enable |= ADC_RUNNING;
1049 cs_set_divisor(dmabuf);
1050 tmp = cs461x_peek(card, BA1_CCTL);
1051 tmp &= 0xFFFF0000;
1052 tmp |= card->cctl;
1053 CS_DBGOUT(CS_FUNCTION, 2, printk(
1054 "cs46xx: start_adc() poke 0x%x \n",tmp) );
1055 cs461x_poke(card, BA1_CCTL, tmp);
1056 }
1057 spin_unlock_irqrestore(&card->lock, flags);
1058}
1059
1060/* stop playback (lock held) */
1061static inline void __stop_dac(struct cs_state *state)
1062{
1063 struct dmabuf *dmabuf = &state->dmabuf;
1064 struct cs_card *card = state->card;
1065 unsigned int tmp;
1066
1067 dmabuf->enable &= ~DAC_RUNNING;
1068
1069 tmp=cs461x_peek(card, BA1_PCTL);
1070 tmp&=0xFFFF;
1071 cs461x_poke(card, BA1_PCTL, tmp);
1072}
1073
1074static void stop_dac(struct cs_state *state)
1075{
1076 unsigned long flags;
1077
1078 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_dac()+ \n") );
1079 spin_lock_irqsave(&state->card->lock, flags);
1080 __stop_dac(state);
1081 spin_unlock_irqrestore(&state->card->lock, flags);
1082 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_dac()- \n") );
1083}
1084
1085static void start_dac(struct cs_state *state)
1086{
1087 struct dmabuf *dmabuf = &state->dmabuf;
1088 struct cs_card *card = state->card;
1089 unsigned long flags;
1090 int tmp;
1091
1092 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()+ \n") );
1093 spin_lock_irqsave(&card->lock, flags);
1094 if (!(dmabuf->enable & DAC_RUNNING) &&
1095 ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) &&
1096 ((card->pm.flags & CS46XX_PM_IDLE) ||
1097 (card->pm.flags & CS46XX_PM_RESUMED)) )
1098 {
1099 dmabuf->enable |= DAC_RUNNING;
1100 tmp = cs461x_peek(card, BA1_PCTL);
1101 tmp &= 0xFFFF;
1102 tmp |= card->pctl;
1103 CS_DBGOUT(CS_PARMS, 6, printk(
1104 "cs46xx: start_dac() poke card=%p tmp=0x%.08x addr=%p \n",
1105 card, (unsigned)tmp,
1106 card->ba1.idx[(BA1_PCTL >> 16) & 3]+(BA1_PCTL&0xffff) ) );
1107 cs461x_poke(card, BA1_PCTL, tmp);
1108 }
1109 spin_unlock_irqrestore(&card->lock, flags);
1110 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()- \n") );
1111}
1112
1113#define DMABUF_MINORDER 1
1114
1115/*
1116 * allocate DMA buffer, playback and recording buffers are separate.
1117 */
1118static int alloc_dmabuf(struct cs_state *state)
1119{
1120
1121 struct cs_card *card=state->card;
1122 struct dmabuf *dmabuf = &state->dmabuf;
1123 void *rawbuf = NULL;
1124 void *tmpbuff = NULL;
1125 int order;
1126 struct page *map, *mapend;
1127 unsigned long df;
1128
1129 dmabuf->ready = dmabuf->mapped = 0;
1130 dmabuf->SGok = 0;
1131/*
1132* check for order within limits, but do not overwrite value.
1133*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07001134 if ((defaultorder > 1) && (defaultorder < 12))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 df = defaultorder;
1136 else
1137 df = 2;
1138
1139 for (order = df; order >= DMABUF_MINORDER; order--)
Jesper Juhl2eebb192006-06-23 02:05:26 -07001140 if ((rawbuf = (void *)pci_alloc_consistent(
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr)))
1142 break;
1143 if (!rawbuf) {
1144 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
1145 "cs46xx: alloc_dmabuf(): unable to allocate rawbuf\n"));
1146 return -ENOMEM;
1147 }
1148 dmabuf->buforder = order;
1149 dmabuf->rawbuf = rawbuf;
1150 // Now mark the pages as reserved; otherwise the
1151 // remap_pfn_range() in cs46xx_mmap doesn't work.
1152 // 1. get index to last page in mem_map array for rawbuf.
1153 mapend = virt_to_page(dmabuf->rawbuf +
1154 (PAGE_SIZE << dmabuf->buforder) - 1);
1155
1156 // 2. mark each physical page in range as 'reserved'.
1157 for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
1158 cs4x_mem_map_reserve(map);
1159
1160 CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: alloc_dmabuf(): allocated %ld (order = %d) bytes at %p\n",
1161 PAGE_SIZE << order, order, rawbuf) );
1162
1163/*
1164* only allocate the conversion buffer for the ADC
1165*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07001166 if (dmabuf->type == CS_TYPE_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 dmabuf->tmpbuff = NULL;
1168 dmabuf->buforder_tmpbuff = 0;
1169 return 0;
1170 }
1171/*
1172 * now the temp buffer for 16/8 conversions
1173 */
1174
1175 tmpbuff = (void *) pci_alloc_consistent(
1176 card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr_tmpbuff);
1177
1178 if (!tmpbuff)
1179 return -ENOMEM;
1180 CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: allocated %ld (order = %d) bytes at %p\n",
1181 PAGE_SIZE << order, order, tmpbuff) );
1182
1183 dmabuf->tmpbuff = tmpbuff;
1184 dmabuf->buforder_tmpbuff = order;
1185
1186 // Now mark the pages as reserved; otherwise the
1187 // remap_pfn_range() in cs46xx_mmap doesn't work.
1188 // 1. get index to last page in mem_map array for rawbuf.
1189 mapend = virt_to_page(dmabuf->tmpbuff +
1190 (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
1191
1192 // 2. mark each physical page in range as 'reserved'.
1193 for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++)
1194 cs4x_mem_map_reserve(map);
1195 return 0;
1196}
1197
1198/* free DMA buffer */
1199static void dealloc_dmabuf(struct cs_state *state)
1200{
1201 struct dmabuf *dmabuf = &state->dmabuf;
1202 struct page *map, *mapend;
1203
1204 if (dmabuf->rawbuf) {
1205 // Undo prog_dmabuf()'s marking the pages as reserved
1206 mapend = virt_to_page(dmabuf->rawbuf +
1207 (PAGE_SIZE << dmabuf->buforder) - 1);
1208 for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
1209 cs4x_mem_map_unreserve(map);
1210 free_dmabuf(state->card, dmabuf);
1211 }
1212
1213 if (dmabuf->tmpbuff) {
1214 // Undo prog_dmabuf()'s marking the pages as reserved
1215 mapend = virt_to_page(dmabuf->tmpbuff +
1216 (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
1217 for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++)
1218 cs4x_mem_map_unreserve(map);
1219 free_dmabuf2(state->card, dmabuf);
1220 }
1221
1222 dmabuf->rawbuf = NULL;
1223 dmabuf->tmpbuff = NULL;
1224 dmabuf->mapped = dmabuf->ready = 0;
1225 dmabuf->SGok = 0;
1226}
1227
1228static int __prog_dmabuf(struct cs_state *state)
1229{
1230 struct dmabuf *dmabuf = &state->dmabuf;
1231 unsigned long flags;
1232 unsigned long allocated_pages, allocated_bytes;
1233 unsigned long tmp1, tmp2, fmt=0;
1234 unsigned long *ptmp = (unsigned long *) dmabuf->pbuf;
1235 unsigned long SGarray[9], nSGpages=0;
1236 int ret;
1237
1238 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()+ \n"));
1239/*
1240 * check for CAPTURE and use only non-sg for initial release
1241 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001242 if (dmabuf->type == CS_TYPE_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf() ADC\n"));
1244 /*
1245 * add in non-sg support for capture.
1246 */
1247 spin_lock_irqsave(&state->card->lock, flags);
1248 /* add code to reset the rawbuf memory. TRW */
1249 resync_dma_ptrs(state);
1250 dmabuf->total_bytes = dmabuf->blocks = 0;
1251 dmabuf->count = dmabuf->error = dmabuf->underrun = 0;
1252
1253 dmabuf->SGok = 0;
1254
1255 spin_unlock_irqrestore(&state->card->lock, flags);
1256
1257 /* allocate DMA buffer if not allocated yet */
1258 if (!dmabuf->rawbuf || !dmabuf->tmpbuff)
1259 if ((ret = alloc_dmabuf(state)))
1260 return ret;
1261 /*
1262 * static image only supports 16Bit signed, stereo - hard code fmt
1263 */
1264 fmt = CS_FMT_16BIT | CS_FMT_STEREO;
1265
1266 dmabuf->numfrag = 2;
1267 dmabuf->fragsize = 2048;
1268 dmabuf->fragsamples = 2048 >> sample_shift[fmt];
1269 dmabuf->dmasize = 4096;
1270 dmabuf->fragshift = 11;
1271
1272 memset(dmabuf->rawbuf, (fmt & CS_FMT_16BIT) ? 0 : 0x80,
1273 dmabuf->dmasize);
1274 memset(dmabuf->tmpbuff, (fmt & CS_FMT_16BIT) ? 0 : 0x80,
1275 PAGE_SIZE<<dmabuf->buforder_tmpbuff);
1276
1277 /*
1278 * Now set up the ring
1279 */
1280
1281 spin_lock_irqsave(&state->card->lock, flags);
1282 cs_rec_setup(state);
1283 spin_unlock_irqrestore(&state->card->lock, flags);
1284
1285 /* set the ready flag for the dma buffer */
1286 dmabuf->ready = 1;
1287
1288 CS_DBGOUT(CS_PARMS, 4, printk(
1289 "cs46xx: prog_dmabuf(): CAPTURE rate=%d fmt=0x%x numfrag=%d "
1290 "fragsize=%d dmasize=%d\n",
1291 dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
1292 dmabuf->fragsize, dmabuf->dmasize) );
1293
1294 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- 0 \n"));
1295 return 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001296 } else if (dmabuf->type == CS_TYPE_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 /*
1298 * Must be DAC
1299 */
1300 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf() DAC\n"));
1301 spin_lock_irqsave(&state->card->lock, flags);
1302 resync_dma_ptrs(state);
1303 dmabuf->total_bytes = dmabuf->blocks = 0;
1304 dmabuf->count = dmabuf->error = dmabuf->underrun = 0;
1305
1306 dmabuf->SGok = 0;
1307
1308 spin_unlock_irqrestore(&state->card->lock, flags);
1309
1310 /* allocate DMA buffer if not allocated yet */
1311 if (!dmabuf->rawbuf)
1312 if ((ret = alloc_dmabuf(state)))
1313 return ret;
1314
1315 allocated_pages = 1 << dmabuf->buforder;
1316 allocated_bytes = allocated_pages*PAGE_SIZE;
1317
Jesper Juhl2eebb192006-06-23 02:05:26 -07001318 if (allocated_pages < 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 CS_DBGOUT(CS_FUNCTION, 4, printk(
1320 "cs46xx: prog_dmabuf() Error: allocated_pages too small (%d)\n",
1321 (unsigned)allocated_pages));
1322 return -ENOMEM;
1323 }
1324
1325 /* Use all the pages allocated, fragsize 4k. */
1326 /* Use 'pbuf' for S/G page map table. */
1327 dmabuf->SGok = 1; /* Use S/G. */
1328
1329 nSGpages = allocated_bytes/4096; /* S/G pages always 4k. */
1330
1331 /* Set up S/G variables. */
1332 *ptmp = virt_to_bus(dmabuf->rawbuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001333 *(ptmp + 1) = 0x00000008;
1334 for (tmp1 = 1; tmp1 < nSGpages; tmp1++) {
1335 *(ptmp + 2 * tmp1) = virt_to_bus((dmabuf->rawbuf) + 4096 * tmp1);
1336 if (tmp1 == nSGpages - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 tmp2 = 0xbfff0000;
1338 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07001339 tmp2 = 0x80000000 + 8 * (tmp1 + 1);
1340 *(ptmp + 2 * tmp1 + 1) = tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 }
1342 SGarray[0] = 0x82c0200d;
1343 SGarray[1] = 0xffff0000;
1344 SGarray[2] = *ptmp;
1345 SGarray[3] = 0x00010600;
1346 SGarray[4] = *(ptmp+2);
1347 SGarray[5] = 0x80000010;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001348 SGarray[6] = *ptmp;
1349 SGarray[7] = *(ptmp+2);
1350 SGarray[8] = (virt_to_bus(dmabuf->pbuf) & 0xffff000) | 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Jesper Juhl2eebb192006-06-23 02:05:26 -07001352 if (dmabuf->SGok) {
1353 dmabuf->numfrag = nSGpages;
1354 dmabuf->fragsize = 4096;
1355 dmabuf->fragsamples = 4096 >> sample_shift[dmabuf->fmt];
1356 dmabuf->fragshift = 12;
1357 dmabuf->dmasize = dmabuf->numfrag * 4096;
1358 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 SGarray[0] = 0xf2c0000f;
1360 SGarray[1] = 0x00000200;
1361 SGarray[2] = 0;
1362 SGarray[3] = 0x00010600;
1363 SGarray[4]=SGarray[5]=SGarray[6]=SGarray[7]=SGarray[8] = 0;
1364 dmabuf->numfrag = 2;
1365 dmabuf->fragsize = 2048;
1366 dmabuf->fragsamples = 2048 >> sample_shift[dmabuf->fmt];
1367 dmabuf->dmasize = 4096;
1368 dmabuf->fragshift = 11;
1369 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001370 for (tmp1 = 0; tmp1 < sizeof(SGarray) / 4; tmp1++)
1371 cs461x_poke(state->card, BA1_PDTC+tmp1 * 4, SGarray[tmp1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372
1373 memset(dmabuf->rawbuf, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
1374 dmabuf->dmasize);
1375
1376 /*
1377 * Now set up the ring
1378 */
1379
1380 spin_lock_irqsave(&state->card->lock, flags);
1381 cs_play_setup(state);
1382 spin_unlock_irqrestore(&state->card->lock, flags);
1383
1384 /* set the ready flag for the dma buffer */
1385 dmabuf->ready = 1;
1386
1387 CS_DBGOUT(CS_PARMS, 4, printk(
1388 "cs46xx: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d "
1389 "fragsize=%d dmasize=%d\n",
1390 dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
1391 dmabuf->fragsize, dmabuf->dmasize) );
1392
1393 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- \n"));
1394 return 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001395 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- Invalid Type %d\n",
1397 dmabuf->type));
1398 }
1399 return 1;
1400}
1401
1402static int prog_dmabuf(struct cs_state *state)
1403{
1404 int ret;
1405
Ingo Molnar910f5d22006-03-23 03:00:39 -08001406 mutex_lock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 ret = __prog_dmabuf(state);
Ingo Molnar910f5d22006-03-23 03:00:39 -08001408 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
1410 return ret;
1411}
1412
1413static void cs_clear_tail(struct cs_state *state)
1414{
1415}
1416
1417static int drain_dac(struct cs_state *state, int nonblock)
1418{
1419 DECLARE_WAITQUEUE(wait, current);
1420 struct dmabuf *dmabuf = &state->dmabuf;
1421 struct cs_card *card=state->card;
1422 unsigned long flags;
1423 unsigned long tmo;
1424 int count;
1425
1426 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()+ \n"));
1427 if (dmabuf->mapped || !dmabuf->ready)
1428 {
1429 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0, not ready\n"));
1430 return 0;
1431 }
1432
1433 add_wait_queue(&dmabuf->wait, &wait);
1434 for (;;) {
1435 /* It seems that we have to set the current state to TASK_INTERRUPTIBLE
1436 every time to make the process really go to sleep */
1437 current->state = TASK_INTERRUPTIBLE;
1438
1439 spin_lock_irqsave(&state->card->lock, flags);
1440 count = dmabuf->count;
1441 spin_unlock_irqrestore(&state->card->lock, flags);
1442
1443 if (count <= 0)
1444 break;
1445
1446 if (signal_pending(current))
1447 break;
1448
1449 if (nonblock) {
1450 remove_wait_queue(&dmabuf->wait, &wait);
1451 current->state = TASK_RUNNING;
1452 return -EBUSY;
1453 }
1454
1455 tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
1456 tmo >>= sample_shift[dmabuf->fmt];
1457 tmo += (2048*HZ)/dmabuf->rate;
1458
1459 if (!schedule_timeout(tmo ? tmo : 1) && tmo){
1460 printk(KERN_ERR "cs46xx: drain_dac, dma timeout? %d\n", count);
1461 break;
1462 }
1463 }
1464 remove_wait_queue(&dmabuf->wait, &wait);
1465 current->state = TASK_RUNNING;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001466 if (signal_pending(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- -ERESTARTSYS\n"));
1468 /*
1469 * set to silence and let that clear the fifos.
1470 */
1471 cs461x_clear_serial_FIFOs(card, CS_TYPE_DAC);
1472 return -ERESTARTSYS;
1473 }
1474
1475 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0\n"));
1476 return 0;
1477}
1478
1479
1480/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
1481static void cs_update_ptr(struct cs_card *card, int wake)
1482{
1483 struct cs_state *state;
1484 struct dmabuf *dmabuf;
1485 unsigned hwptr;
1486 int diff;
1487
1488 /* error handling and process wake up for ADC */
1489 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07001490 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 dmabuf = &state->dmabuf;
1492 if (dmabuf->enable & ADC_RUNNING) {
1493 /* update hardware pointer */
1494 hwptr = cs_get_dma_addr(state);
1495
1496 diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
1497 CS_DBGOUT(CS_PARMS, 9, printk(
1498 "cs46xx: cs_update_ptr()+ ADC hwptr=%d diff=%d\n",
1499 hwptr,diff) );
1500 dmabuf->hwptr = hwptr;
1501 dmabuf->total_bytes += diff;
1502 dmabuf->count += diff;
1503 if (dmabuf->count > dmabuf->dmasize)
1504 dmabuf->count = dmabuf->dmasize;
1505
Jesper Juhl2eebb192006-06-23 02:05:26 -07001506 if (dmabuf->mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
1508 wake_up(&dmabuf->wait);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001509 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 if (wake && dmabuf->count > 0)
1511 wake_up(&dmabuf->wait);
1512 }
1513 }
1514 }
1515
1516/*
1517 * Now the DAC
1518 */
1519 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07001520 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 dmabuf = &state->dmabuf;
1522 /* error handling and process wake up for DAC */
1523 if (dmabuf->enable & DAC_RUNNING) {
1524 /* update hardware pointer */
1525 hwptr = cs_get_dma_addr(state);
1526
1527 diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
1528 CS_DBGOUT(CS_PARMS, 9, printk(
1529 "cs46xx: cs_update_ptr()+ DAC hwptr=%d diff=%d\n",
1530 hwptr,diff) );
1531 dmabuf->hwptr = hwptr;
1532 dmabuf->total_bytes += diff;
1533 if (dmabuf->mapped) {
1534 dmabuf->count += diff;
1535 if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
1536 wake_up(&dmabuf->wait);
1537 /*
1538 * other drivers use fragsize, but don't see any sense
1539 * in that, since dmasize is the buffer asked for
1540 * via mmap.
1541 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001542 if (dmabuf->count > dmabuf->dmasize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 dmabuf->count &= dmabuf->dmasize-1;
1544 } else {
1545 dmabuf->count -= diff;
1546 /*
1547 * backfill with silence and clear out the last
1548 * "diff" number of bytes.
1549 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001550 if (hwptr >= diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 memset(dmabuf->rawbuf + hwptr - diff,
1552 (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, diff);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001553 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 memset(dmabuf->rawbuf,
1555 (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
1556 (unsigned)hwptr);
1557 memset((char *)dmabuf->rawbuf +
1558 dmabuf->dmasize + hwptr - diff,
1559 (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
1560 diff - hwptr);
1561 }
1562
1563 if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
1564 CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
1565 "cs46xx: ERROR DAC count<0 or count > dmasize (%d)\n",
1566 dmabuf->count));
1567 /*
1568 * buffer underrun or buffer overrun, reset the
1569 * count of bytes written back to 0.
1570 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001571 if (dmabuf->count < 0)
1572 dmabuf->underrun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 dmabuf->count = 0;
1574 dmabuf->error++;
1575 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001576 if (wake && dmabuf->count < (signed)dmabuf->dmasize / 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 wake_up(&dmabuf->wait);
1578 }
1579 }
1580 }
1581}
1582
1583
1584/* hold spinlock for the following! */
1585static void cs_handle_midi(struct cs_card *card)
1586{
1587 unsigned char ch;
1588 int wake;
1589 unsigned temp1;
1590
1591 wake = 0;
1592 while (!(cs461x_peekBA0(card, BA0_MIDSR) & MIDSR_RBE)) {
1593 ch = cs461x_peekBA0(card, BA0_MIDRP);
1594 if (card->midi.icnt < CS_MIDIINBUF) {
1595 card->midi.ibuf[card->midi.iwr] = ch;
1596 card->midi.iwr = (card->midi.iwr + 1) % CS_MIDIINBUF;
1597 card->midi.icnt++;
1598 }
1599 wake = 1;
1600 }
1601 if (wake)
1602 wake_up(&card->midi.iwait);
1603 wake = 0;
1604 while (!(cs461x_peekBA0(card, BA0_MIDSR) & MIDSR_TBF) && card->midi.ocnt > 0) {
1605 temp1 = ( card->midi.obuf[card->midi.ord] ) & 0x000000ff;
1606 cs461x_pokeBA0(card, BA0_MIDWP,temp1);
1607 card->midi.ord = (card->midi.ord + 1) % CS_MIDIOUTBUF;
1608 card->midi.ocnt--;
1609 if (card->midi.ocnt < CS_MIDIOUTBUF-16)
1610 wake = 1;
1611 }
1612 if (wake)
1613 wake_up(&card->midi.owait);
1614}
1615
1616static irqreturn_t cs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
1617{
1618 struct cs_card *card = (struct cs_card *)dev_id;
1619 /* Single channel card */
1620 struct cs_state *recstate = card->channel[0].state;
1621 struct cs_state *playstate = card->channel[1].state;
1622 u32 status;
1623
1624 CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()+ \n"));
1625
1626 spin_lock(&card->lock);
1627
1628 status = cs461x_peekBA0(card, BA0_HISR);
1629
Jesper Juhl2eebb192006-06-23 02:05:26 -07001630 if ((status & 0x7fffffff) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV);
1632 spin_unlock(&card->lock);
1633 return IRQ_HANDLED; /* Might be IRQ_NONE.. */
1634 }
1635
1636 /*
1637 * check for playback or capture interrupt only
1638 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001639 if (((status & HISR_VC0) && playstate && playstate->dmabuf.ready) ||
1640 (((status & HISR_VC1) && recstate && recstate->dmabuf.ready))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 CS_DBGOUT(CS_INTERRUPT, 8, printk(
1642 "cs46xx: cs_interrupt() interrupt bit(s) set (0x%x)\n",status));
1643 cs_update_ptr(card, CS_TRUE);
1644 }
1645
Jesper Juhl2eebb192006-06-23 02:05:26 -07001646 if (status & HISR_MIDI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 cs_handle_midi(card);
1648
1649 /* clear 'em */
1650 cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV);
1651 spin_unlock(&card->lock);
1652 CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()- \n"));
1653 return IRQ_HANDLED;
1654}
1655
1656
1657/**********************************************************************/
1658
1659static ssize_t cs_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
1660{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001661 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 ssize_t ret;
1663 unsigned long flags;
1664 unsigned ptr;
1665 int cnt;
1666
1667 if (!access_ok(VERIFY_WRITE, buffer, count))
1668 return -EFAULT;
1669 ret = 0;
1670 while (count > 0) {
1671 spin_lock_irqsave(&card->lock, flags);
1672 ptr = card->midi.ird;
1673 cnt = CS_MIDIINBUF - ptr;
1674 if (card->midi.icnt < cnt)
1675 cnt = card->midi.icnt;
1676 spin_unlock_irqrestore(&card->lock, flags);
1677 if (cnt > count)
1678 cnt = count;
1679 if (cnt <= 0) {
1680 if (file->f_flags & O_NONBLOCK)
1681 return ret ? ret : -EAGAIN;
1682 interruptible_sleep_on(&card->midi.iwait);
1683 if (signal_pending(current))
1684 return ret ? ret : -ERESTARTSYS;
1685 continue;
1686 }
1687 if (copy_to_user(buffer, card->midi.ibuf + ptr, cnt))
1688 return ret ? ret : -EFAULT;
1689 ptr = (ptr + cnt) % CS_MIDIINBUF;
1690 spin_lock_irqsave(&card->lock, flags);
1691 card->midi.ird = ptr;
1692 card->midi.icnt -= cnt;
1693 spin_unlock_irqrestore(&card->lock, flags);
1694 count -= cnt;
1695 buffer += cnt;
1696 ret += cnt;
1697 }
1698 return ret;
1699}
1700
1701
1702static ssize_t cs_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
1703{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001704 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 ssize_t ret;
1706 unsigned long flags;
1707 unsigned ptr;
1708 int cnt;
1709
1710 if (!access_ok(VERIFY_READ, buffer, count))
1711 return -EFAULT;
1712 ret = 0;
1713 while (count > 0) {
1714 spin_lock_irqsave(&card->lock, flags);
1715 ptr = card->midi.owr;
1716 cnt = CS_MIDIOUTBUF - ptr;
1717 if (card->midi.ocnt + cnt > CS_MIDIOUTBUF)
1718 cnt = CS_MIDIOUTBUF - card->midi.ocnt;
1719 if (cnt <= 0)
1720 cs_handle_midi(card);
1721 spin_unlock_irqrestore(&card->lock, flags);
1722 if (cnt > count)
1723 cnt = count;
1724 if (cnt <= 0) {
1725 if (file->f_flags & O_NONBLOCK)
1726 return ret ? ret : -EAGAIN;
1727 interruptible_sleep_on(&card->midi.owait);
1728 if (signal_pending(current))
1729 return ret ? ret : -ERESTARTSYS;
1730 continue;
1731 }
1732 if (copy_from_user(card->midi.obuf + ptr, buffer, cnt))
1733 return ret ? ret : -EFAULT;
1734 ptr = (ptr + cnt) % CS_MIDIOUTBUF;
1735 spin_lock_irqsave(&card->lock, flags);
1736 card->midi.owr = ptr;
1737 card->midi.ocnt += cnt;
1738 spin_unlock_irqrestore(&card->lock, flags);
1739 count -= cnt;
1740 buffer += cnt;
1741 ret += cnt;
1742 spin_lock_irqsave(&card->lock, flags);
1743 cs_handle_midi(card);
1744 spin_unlock_irqrestore(&card->lock, flags);
1745 }
1746 return ret;
1747}
1748
1749
1750static unsigned int cs_midi_poll(struct file *file, struct poll_table_struct *wait)
1751{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001752 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 unsigned long flags;
1754 unsigned int mask = 0;
1755
1756 if (file->f_flags & FMODE_WRITE)
1757 poll_wait(file, &card->midi.owait, wait);
1758 if (file->f_flags & FMODE_READ)
1759 poll_wait(file, &card->midi.iwait, wait);
1760 spin_lock_irqsave(&card->lock, flags);
1761 if (file->f_flags & FMODE_READ) {
1762 if (card->midi.icnt > 0)
1763 mask |= POLLIN | POLLRDNORM;
1764 }
1765 if (file->f_flags & FMODE_WRITE) {
1766 if (card->midi.ocnt < CS_MIDIOUTBUF)
1767 mask |= POLLOUT | POLLWRNORM;
1768 }
1769 spin_unlock_irqrestore(&card->lock, flags);
1770 return mask;
1771}
1772
1773
1774static int cs_midi_open(struct inode *inode, struct file *file)
1775{
1776 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001777 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 unsigned long flags;
1779 struct list_head *entry;
1780
Jesper Juhl2eebb192006-06-23 02:05:26 -07001781 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 card = list_entry(entry, struct cs_card, list);
1783 if (card->dev_midi == minor)
1784 break;
1785 }
1786
1787 if (entry == &cs46xx_devs)
1788 return -ENODEV;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001789 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
1791 "cs46xx: cs46xx_midi_open(): Error - unable to find card struct\n"));
1792 return -ENODEV;
1793 }
1794
1795 file->private_data = card;
1796 /* wait for device to become free */
Ingo Molnar910f5d22006-03-23 03:00:39 -08001797 mutex_lock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 while (card->midi.open_mode & file->f_mode) {
1799 if (file->f_flags & O_NONBLOCK) {
Ingo Molnar910f5d22006-03-23 03:00:39 -08001800 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 return -EBUSY;
1802 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08001803 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 interruptible_sleep_on(&card->midi.open_wait);
1805 if (signal_pending(current))
1806 return -ERESTARTSYS;
Ingo Molnar910f5d22006-03-23 03:00:39 -08001807 mutex_lock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 }
1809 spin_lock_irqsave(&card->midi.lock, flags);
1810 if (!(card->midi.open_mode & (FMODE_READ | FMODE_WRITE))) {
1811 card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
1812 card->midi.ord = card->midi.owr = card->midi.ocnt = 0;
1813 card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
1814 cs461x_pokeBA0(card, BA0_MIDCR, 0x0000000f); /* Enable xmit, rcv. */
1815 cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM); /* Enable interrupts */
1816 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001817 if (file->f_mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001819 if (file->f_mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 card->midi.ord = card->midi.owr = card->midi.ocnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 spin_unlock_irqrestore(&card->midi.lock, flags);
1822 card->midi.open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE));
Ingo Molnar910f5d22006-03-23 03:00:39 -08001823 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 return 0;
1825}
1826
1827
1828static int cs_midi_release(struct inode *inode, struct file *file)
1829{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001830 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 DECLARE_WAITQUEUE(wait, current);
1832 unsigned long flags;
1833 unsigned count, tmo;
1834
1835 if (file->f_mode & FMODE_WRITE) {
1836 current->state = TASK_INTERRUPTIBLE;
1837 add_wait_queue(&card->midi.owait, &wait);
1838 for (;;) {
1839 spin_lock_irqsave(&card->midi.lock, flags);
1840 count = card->midi.ocnt;
1841 spin_unlock_irqrestore(&card->midi.lock, flags);
1842 if (count <= 0)
1843 break;
1844 if (signal_pending(current))
1845 break;
1846 if (file->f_flags & O_NONBLOCK)
1847 break;
1848 tmo = (count * HZ) / 3100;
1849 if (!schedule_timeout(tmo ? : 1) && tmo)
1850 printk(KERN_DEBUG "cs46xx: midi timed out??\n");
1851 }
1852 remove_wait_queue(&card->midi.owait, &wait);
1853 current->state = TASK_RUNNING;
1854 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08001855 mutex_lock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 card->midi.open_mode &= (~(file->f_mode & (FMODE_READ | FMODE_WRITE)));
Ingo Molnar910f5d22006-03-23 03:00:39 -08001857 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 wake_up(&card->midi.open_wait);
1859 return 0;
1860}
1861
1862/*
1863 * Midi file operations struct.
1864 */
1865static /*const*/ struct file_operations cs_midi_fops = {
1866 CS_OWNER CS_THIS_MODULE
1867 .llseek = no_llseek,
1868 .read = cs_midi_read,
1869 .write = cs_midi_write,
1870 .poll = cs_midi_poll,
1871 .open = cs_midi_open,
1872 .release = cs_midi_release,
1873};
1874
1875/*
1876 *
1877 * CopySamples copies 16-bit stereo signed samples from the source to the
1878 * destination, possibly converting down to unsigned 8-bit and/or mono.
1879 * count specifies the number of output bytes to write.
1880 *
1881 * Arguments:
1882 *
1883 * dst - Pointer to a destination buffer.
1884 * src - Pointer to a source buffer
1885 * count - The number of bytes to copy into the destination buffer.
1886 * fmt - CS_FMT_16BIT and/or CS_FMT_STEREO bits
1887 * dmabuf - pointer to the dma buffer structure
1888 *
1889 * NOTES: only call this routine if the output desired is not 16 Signed Stereo
1890 *
1891 *
1892 */
1893static void CopySamples(char *dst, char *src, int count, unsigned fmt,
1894 struct dmabuf *dmabuf)
1895{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 s32 s32AudioSample;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001897 s16 *psSrc = (s16 *)src;
1898 s16 *psDst = (s16 *)dst;
1899 u8 *pucDst = (u8 *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: CopySamples()+ ") );
1902 CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
1903 " dst=%p src=%p count=%d fmt=0x%x\n",
1904 dst,src,count,fmt) );
1905
1906 /*
1907 * See if the data should be output as 8-bit unsigned stereo.
1908 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001909 if ((fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 /*
1911 * Convert each 16-bit signed stereo sample to 8-bit unsigned
1912 * stereo using rounding.
1913 */
1914 psSrc = (s16 *)src;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001915 count = count / 2;
1916 while (count--)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 *(pucDst++) = (u8)(((s16)(*psSrc++) + (s16)0x8000) >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 }
1919 /*
1920 * See if the data should be output at 8-bit unsigned mono.
1921 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001922 else if (!(fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 /*
1924 * Convert each 16-bit signed stereo sample to 8-bit unsigned
1925 * mono using averaging and rounding.
1926 */
1927 psSrc = (s16 *)src;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001928 count = count / 2;
1929 while (count--) {
1930 s32AudioSample = ((*psSrc) + (*(psSrc + 1))) / 2 + (s32)0x80;
1931 if (s32AudioSample > 0x7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 s32AudioSample = 0x7fff;
1933 *(pucDst++) = (u8)(((s16)s32AudioSample + (s16)0x8000) >> 8);
1934 psSrc += 2;
1935 }
1936 }
1937 /*
1938 * See if the data should be output at 16-bit signed mono.
1939 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001940 else if (!(fmt & CS_FMT_STEREO) && (fmt & CS_FMT_16BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 /*
1942 * Convert each 16-bit signed stereo sample to 16-bit signed
1943 * mono using averaging.
1944 */
1945 psSrc = (s16 *)src;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001946 count = count / 2;
1947 while (count--) {
1948 *(psDst++) = (s16)((*psSrc) + (*(psSrc + 1))) / 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 psSrc += 2;
1950 }
1951 }
1952}
1953
1954/*
1955 * cs_copy_to_user()
1956 * replacement for the standard copy_to_user, to allow for a conversion from
1957 * 16 bit to 8 bit and from stereo to mono, if the record conversion is active.
1958 * The current CS46xx/CS4280 static image only records in 16bit unsigned Stereo,
1959 * so we convert from any of the other format combinations.
1960 */
1961static unsigned cs_copy_to_user(
1962 struct cs_state *s,
1963 void __user *dest,
1964 void *hwsrc,
1965 unsigned cnt,
1966 unsigned *copied)
1967{
1968 struct dmabuf *dmabuf = &s->dmabuf;
1969 void *src = hwsrc; /* default to the standard destination buffer addr */
1970
1971 CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO
1972 "cs_copy_to_user()+ fmt=0x%x cnt=%d dest=%p\n",
1973 dmabuf->fmt,(unsigned)cnt,dest) );
1974
Jesper Juhl2eebb192006-06-23 02:05:26 -07001975 if (cnt > dmabuf->dmasize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 cnt = dmabuf->dmasize;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001977 if (!cnt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 *copied = 0;
1979 return 0;
1980 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001981 if (dmabuf->divisor != 1) {
1982 if (!dmabuf->tmpbuff) {
1983 *copied = cnt / dmabuf->divisor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 return 0;
1985 }
1986
1987 CopySamples((char *)dmabuf->tmpbuff, (char *)hwsrc, cnt,
1988 dmabuf->fmt, dmabuf);
1989 src = dmabuf->tmpbuff;
1990 cnt = cnt/dmabuf->divisor;
1991 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001992 if (copy_to_user(dest, src, cnt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
1994 "cs46xx: cs_copy_to_user()- fault dest=%p src=%p cnt=%d\n",
Jesper Juhl2eebb192006-06-23 02:05:26 -07001995 dest,src,cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 *copied = 0;
1997 return -EFAULT;
1998 }
1999 *copied = cnt;
2000 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07002001 "cs46xx: cs_copy_to_user()- copied bytes is %d \n",cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 return 0;
2003}
2004
2005/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to
2006 the user's buffer. it is filled by the dma machine and drained by this loop. */
2007static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2008{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002009 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 struct cs_state *state;
2011 DECLARE_WAITQUEUE(wait, current);
2012 struct dmabuf *dmabuf;
2013 ssize_t ret = 0;
2014 unsigned long flags;
2015 unsigned swptr;
2016 int cnt;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002017 unsigned copied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
2019 CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
2020 printk("cs46xx: cs_read()+ %zd\n",count) );
Jesper Juhl2eebb192006-06-23 02:05:26 -07002021 state = card->states[0];
2022 if (!state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 return -ENODEV;
2024 dmabuf = &state->dmabuf;
2025
2026 if (dmabuf->mapped)
2027 return -ENXIO;
2028 if (!access_ok(VERIFY_WRITE, buffer, count))
2029 return -EFAULT;
2030
Ingo Molnar910f5d22006-03-23 03:00:39 -08002031 mutex_lock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
2033 goto out2;
2034
2035 add_wait_queue(&state->dmabuf.wait, &wait);
2036 while (count > 0) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002037 while (!(card->pm.flags & CS46XX_PM_IDLE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 schedule();
2039 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002040 if (!ret)
2041 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 goto out;
2043 }
2044 }
2045 spin_lock_irqsave(&state->card->lock, flags);
2046 swptr = dmabuf->swptr;
2047 cnt = dmabuf->dmasize - swptr;
2048 if (dmabuf->count < cnt)
2049 cnt = dmabuf->count;
2050 if (cnt <= 0)
2051 __set_current_state(TASK_INTERRUPTIBLE);
2052 spin_unlock_irqrestore(&state->card->lock, flags);
2053
2054 if (cnt > (count * dmabuf->divisor))
2055 cnt = count * dmabuf->divisor;
2056 if (cnt <= 0) {
2057 /* buffer is empty, start the dma machine and wait for data to be
2058 recorded */
2059 start_adc(state);
2060 if (file->f_flags & O_NONBLOCK) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002061 if (!ret)
2062 ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 goto out;
2064 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002065 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 schedule();
2067 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002068 if (!ret)
2069 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 goto out;
2071 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002072 mutex_lock(&state->sem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002073 if (dmabuf->mapped) {
2074 if (!ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 ret = -ENXIO;
2076 goto out;
2077 }
2078 continue;
2079 }
2080
2081 CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
2082 "_read() copy_to cnt=%d count=%zd ", cnt,count) );
2083 CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
2084 " .dmasize=%d .count=%d buffer=%p ret=%zd\n",
Jesper Juhl2eebb192006-06-23 02:05:26 -07002085 dmabuf->dmasize,dmabuf->count,buffer,ret));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
2087 if (cs_copy_to_user(state, buffer,
Jesper Juhl2eebb192006-06-23 02:05:26 -07002088 (char *)dmabuf->rawbuf + swptr, cnt, &copied)) {
2089 if (!ret)
2090 ret = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 goto out;
2092 }
2093 swptr = (swptr + cnt) % dmabuf->dmasize;
2094 spin_lock_irqsave(&card->lock, flags);
2095 dmabuf->swptr = swptr;
2096 dmabuf->count -= cnt;
2097 spin_unlock_irqrestore(&card->lock, flags);
2098 count -= copied;
2099 buffer += copied;
2100 ret += copied;
2101 start_adc(state);
2102 }
2103out:
2104 remove_wait_queue(&state->dmabuf.wait, &wait);
2105out2:
Ingo Molnar910f5d22006-03-23 03:00:39 -08002106 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 set_current_state(TASK_RUNNING);
2108 CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
2109 printk("cs46xx: cs_read()- %zd\n",ret) );
2110 return ret;
2111}
2112
2113/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
2114 the soundcard. it is drained by the dma machine and filled by this loop. */
2115static ssize_t cs_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
2116{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002117 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 struct cs_state *state;
2119 DECLARE_WAITQUEUE(wait, current);
2120 struct dmabuf *dmabuf;
2121 ssize_t ret;
2122 unsigned long flags;
2123 unsigned swptr;
2124 int cnt;
2125
2126 CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 4,
2127 printk("cs46xx: cs_write called, count = %zd\n", count) );
Jesper Juhl2eebb192006-06-23 02:05:26 -07002128 state = card->states[1];
2129 if (!state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 return -ENODEV;
2131 if (!access_ok(VERIFY_READ, buffer, count))
2132 return -EFAULT;
2133 dmabuf = &state->dmabuf;
2134
Ingo Molnar910f5d22006-03-23 03:00:39 -08002135 mutex_lock(&state->sem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002136 if (dmabuf->mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 ret = -ENXIO;
2138 goto out;
2139 }
2140
2141 if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
2142 goto out;
2143 add_wait_queue(&state->dmabuf.wait, &wait);
2144 ret = 0;
2145/*
2146* Start the loop to read from the user's buffer and write to the dma buffer.
2147* check for PM events and underrun/overrun in the loop.
2148*/
2149 while (count > 0) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002150 while (!(card->pm.flags & CS46XX_PM_IDLE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 schedule();
2152 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002153 if (!ret)
2154 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 goto out;
2156 }
2157 }
2158 spin_lock_irqsave(&state->card->lock, flags);
2159 if (dmabuf->count < 0) {
2160 /* buffer underrun, we are recovering from sleep_on_timeout,
2161 resync hwptr and swptr */
2162 dmabuf->count = 0;
2163 dmabuf->swptr = dmabuf->hwptr;
2164 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002165 if (dmabuf->underrun) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 dmabuf->underrun = 0;
2167 dmabuf->hwptr = cs_get_dma_addr(state);
2168 dmabuf->swptr = dmabuf->hwptr;
2169 }
2170
2171 swptr = dmabuf->swptr;
2172 cnt = dmabuf->dmasize - swptr;
2173 if (dmabuf->count + cnt > dmabuf->dmasize)
2174 cnt = dmabuf->dmasize - dmabuf->count;
2175 if (cnt <= 0)
2176 __set_current_state(TASK_INTERRUPTIBLE);
2177 spin_unlock_irqrestore(&state->card->lock, flags);
2178
2179 if (cnt > count)
2180 cnt = count;
2181 if (cnt <= 0) {
2182 /* buffer is full, start the dma machine and wait for data to be
2183 played */
2184 start_dac(state);
2185 if (file->f_flags & O_NONBLOCK) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002186 if (!ret)
2187 ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 goto out;
2189 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002190 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 schedule();
2192 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002193 if (!ret)
2194 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 goto out;
2196 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002197 mutex_lock(&state->sem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002198 if (dmabuf->mapped) {
2199 if (!ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 ret = -ENXIO;
2201 goto out;
2202 }
2203 continue;
2204 }
2205 if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002206 if (!ret)
2207 ret = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 goto out;
2209 }
2210 spin_lock_irqsave(&state->card->lock, flags);
2211 swptr = (swptr + cnt) % dmabuf->dmasize;
2212 dmabuf->swptr = swptr;
2213 dmabuf->count += cnt;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002214 if (dmabuf->count > dmabuf->dmasize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 CS_DBGOUT(CS_WAVE_WRITE | CS_ERROR, 2, printk(
2216 "cs46xx: cs_write() d->count > dmasize - resetting\n"));
2217 dmabuf->count = dmabuf->dmasize;
2218 }
2219 dmabuf->endcleared = 0;
2220 spin_unlock_irqrestore(&state->card->lock, flags);
2221
2222 count -= cnt;
2223 buffer += cnt;
2224 ret += cnt;
2225 start_dac(state);
2226 }
2227out:
Ingo Molnar910f5d22006-03-23 03:00:39 -08002228 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 remove_wait_queue(&state->dmabuf.wait, &wait);
2230 set_current_state(TASK_RUNNING);
2231
2232 CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 2,
Jesper Juhl2eebb192006-06-23 02:05:26 -07002233 printk("cs46xx: cs_write()- ret=%zd\n", ret));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 return ret;
2235}
2236
2237static unsigned int cs_poll(struct file *file, struct poll_table_struct *wait)
2238{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002239 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 struct dmabuf *dmabuf;
2241 struct cs_state *state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 unsigned long flags;
2243 unsigned int mask = 0;
2244
2245 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()+ \n"));
Jesper Juhl2eebb192006-06-23 02:05:26 -07002246 if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 return -EINVAL;
2248 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002249 if (file->f_mode & FMODE_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002251 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 dmabuf = &state->dmabuf;
2253 poll_wait(file, &dmabuf->wait, wait);
2254 }
2255 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002256 if (file->f_mode & FMODE_READ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002258 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 dmabuf = &state->dmabuf;
2260 poll_wait(file, &dmabuf->wait, wait);
2261 }
2262 }
2263
2264 spin_lock_irqsave(&card->lock, flags);
2265 cs_update_ptr(card, CS_FALSE);
2266 if (file->f_mode & FMODE_READ) {
2267 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002268 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 dmabuf = &state->dmabuf;
2270 if (dmabuf->count >= (signed)dmabuf->fragsize)
2271 mask |= POLLIN | POLLRDNORM;
2272 }
2273 }
2274 if (file->f_mode & FMODE_WRITE) {
2275 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002276 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 dmabuf = &state->dmabuf;
2278 if (dmabuf->mapped) {
2279 if (dmabuf->count >= (signed)dmabuf->fragsize)
2280 mask |= POLLOUT | POLLWRNORM;
2281 } else {
2282 if ((signed)dmabuf->dmasize >= dmabuf->count
2283 + (signed)dmabuf->fragsize)
2284 mask |= POLLOUT | POLLWRNORM;
2285 }
2286 }
2287 }
2288 spin_unlock_irqrestore(&card->lock, flags);
2289
2290 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()- (0x%x) \n",
2291 mask));
2292 return mask;
2293}
2294
2295/*
2296 * We let users mmap the ring buffer. Its not the real DMA buffer but
2297 * that side of the code is hidden in the IRQ handling. We do a software
2298 * emulation of DMA from a 64K or so buffer into a 2K FIFO.
2299 * (the hardware probably deserves a moan here but Crystal send me nice
2300 * toys ;)).
2301 */
2302
2303static int cs_mmap(struct file *file, struct vm_area_struct *vma)
2304{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002305 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 struct cs_state *state;
2307 struct dmabuf *dmabuf;
2308 int ret = 0;
2309 unsigned long size;
2310
2311 CS_DBGOUT(CS_FUNCTION | CS_PARMS, 2, printk("cs46xx: cs_mmap()+ file=%p %s %s\n",
2312 file, vma->vm_flags & VM_WRITE ? "VM_WRITE" : "",
2313 vma->vm_flags & VM_READ ? "VM_READ" : "") );
2314
2315 if (vma->vm_flags & VM_WRITE) {
2316 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002317 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 CS_DBGOUT(CS_OPEN, 2, printk(
2319 "cs46xx: cs_mmap() VM_WRITE - state TRUE prog_dmabuf DAC\n") );
2320 if ((ret = prog_dmabuf(state)) != 0)
2321 return ret;
2322 }
2323 } else if (vma->vm_flags & VM_READ) {
2324 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002325 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 CS_DBGOUT(CS_OPEN, 2, printk(
2327 "cs46xx: cs_mmap() VM_READ - state TRUE prog_dmabuf ADC\n") );
2328 if ((ret = prog_dmabuf(state)) != 0)
2329 return ret;
2330 }
2331 } else {
2332 CS_DBGOUT(CS_ERROR, 2, printk(
2333 "cs46xx: cs_mmap() return -EINVAL\n") );
2334 return -EINVAL;
2335 }
2336
2337/*
2338 * For now ONLY support playback, but seems like the only way to use
2339 * mmap() is to open an FD with RDWR, just read or just write access
2340 * does not function, get an error back from the kernel.
2341 * Also, QuakeIII opens with RDWR! So, there must be something
2342 * to needing read/write access mapping. So, allow read/write but
2343 * use the DAC only.
2344 */
2345 state = card->states[1];
2346 if (!state) {
2347 ret = -EINVAL;
2348 goto out;
2349 }
2350
Ingo Molnar910f5d22006-03-23 03:00:39 -08002351 mutex_lock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002353 if (cs4x_pgoff(vma) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 ret = -EINVAL;
2355 goto out;
2356 }
2357 size = vma->vm_end - vma->vm_start;
2358
2359 CS_DBGOUT(CS_PARMS, 2, printk("cs46xx: cs_mmap(): size=%d\n",(unsigned)size) );
2360
Jesper Juhl2eebb192006-06-23 02:05:26 -07002361 if (size > (PAGE_SIZE << dmabuf->buforder)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 ret = -EINVAL;
2363 goto out;
2364 }
2365 if (remap_pfn_range(vma, vma->vm_start,
2366 virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
Jesper Juhl2eebb192006-06-23 02:05:26 -07002367 size, vma->vm_page_prot)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 ret = -EAGAIN;
2369 goto out;
2370 }
2371 dmabuf->mapped = 1;
2372
2373 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mmap()-\n") );
2374out:
Ingo Molnar910f5d22006-03-23 03:00:39 -08002375 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 return ret;
2377}
2378
2379static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
2380{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002381 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 struct cs_state *state;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002383 struct dmabuf *dmabuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 unsigned long flags;
2385 audio_buf_info abinfo;
2386 count_info cinfo;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002387 int val, valsave, ret;
2388 int mapped = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 void __user *argp = (void __user *)arg;
2390 int __user *p = argp;
2391
Jesper Juhl2eebb192006-06-23 02:05:26 -07002392 state = card->states[0];
2393 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 dmabuf = &state->dmabuf;
2395 mapped = (file->f_mode & FMODE_READ) && dmabuf->mapped;
2396 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002397 state = card->states[1];
2398 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 dmabuf = &state->dmabuf;
2400 mapped |= (file->f_mode & FMODE_WRITE) && dmabuf->mapped;
2401 }
2402
2403#if CSDEBUG
2404 printioctl(cmd);
2405#endif
2406
Jesper Juhl2eebb192006-06-23 02:05:26 -07002407 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 case OSS_GETVERSION:
2409 return put_user(SOUND_VERSION, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 case SNDCTL_DSP_RESET:
2411 /* FIXME: spin_lock ? */
2412 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002413 state = card->states[1];
2414 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 dmabuf = &state->dmabuf;
2416 stop_dac(state);
2417 synchronize_irq(card->irq);
2418 dmabuf->ready = 0;
2419 resync_dma_ptrs(state);
2420 dmabuf->swptr = dmabuf->hwptr = 0;
2421 dmabuf->count = dmabuf->total_bytes = 0;
2422 dmabuf->blocks = 0;
2423 dmabuf->SGok = 0;
2424 }
2425 }
2426 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002427 state = card->states[0];
2428 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 dmabuf = &state->dmabuf;
2430 stop_adc(state);
2431 synchronize_irq(card->irq);
2432 resync_dma_ptrs(state);
2433 dmabuf->ready = 0;
2434 dmabuf->swptr = dmabuf->hwptr = 0;
2435 dmabuf->count = dmabuf->total_bytes = 0;
2436 dmabuf->blocks = 0;
2437 dmabuf->SGok = 0;
2438 }
2439 }
2440 CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_RESET()-\n") );
2441 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 case SNDCTL_DSP_SYNC:
2443 if (file->f_mode & FMODE_WRITE)
2444 return drain_dac(state, file->f_flags & O_NONBLOCK);
2445 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 case SNDCTL_DSP_SPEED: /* set sample rate */
2447 if (get_user(val, p))
2448 return -EFAULT;
2449 if (val >= 0) {
2450 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002451 state = card->states[0];
2452 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 dmabuf = &state->dmabuf;
2454 stop_adc(state);
2455 dmabuf->ready = 0;
2456 dmabuf->SGok = 0;
2457 cs_set_adc_rate(state, val);
2458 cs_set_divisor(dmabuf);
2459 }
2460 }
2461 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002462 state = card->states[1];
2463 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 dmabuf = &state->dmabuf;
2465 stop_dac(state);
2466 dmabuf->ready = 0;
2467 dmabuf->SGok = 0;
2468 cs_set_dac_rate(state, val);
2469 cs_set_divisor(dmabuf);
2470 }
2471 }
2472 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2473 "cs46xx: cs_ioctl() DSP_SPEED %s %s %d\n",
2474 file->f_mode & FMODE_WRITE ? "DAC" : "",
2475 file->f_mode & FMODE_READ ? "ADC" : "",
2476 dmabuf->rate ) );
2477 return put_user(dmabuf->rate, p);
2478 }
2479 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
2481 if (get_user(val, p))
2482 return -EFAULT;
2483 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002484 state = card->states[1];
2485 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 dmabuf = &state->dmabuf;
2487 stop_dac(state);
2488 dmabuf->ready = 0;
2489 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002490 if (val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 dmabuf->fmt |= CS_FMT_STEREO;
2492 else
2493 dmabuf->fmt &= ~CS_FMT_STEREO;
2494 cs_set_divisor(dmabuf);
2495 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2496 "cs46xx: DSP_STEREO() DAC %s\n",
2497 (dmabuf->fmt & CS_FMT_STEREO) ?
2498 "STEREO":"MONO") );
2499 }
2500 }
2501 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002502 state = card->states[0];
2503 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 dmabuf = &state->dmabuf;
2505 stop_adc(state);
2506 dmabuf->ready = 0;
2507 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002508 if (val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 dmabuf->fmt |= CS_FMT_STEREO;
2510 else
2511 dmabuf->fmt &= ~CS_FMT_STEREO;
2512 cs_set_divisor(dmabuf);
2513 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2514 "cs46xx: DSP_STEREO() ADC %s\n",
2515 (dmabuf->fmt & CS_FMT_STEREO) ?
2516 "STEREO":"MONO") );
2517 }
2518 }
2519 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 case SNDCTL_DSP_GETBLKSIZE:
2521 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002522 state = card->states[1];
2523 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 dmabuf = &state->dmabuf;
2525 if ((val = prog_dmabuf(state)))
2526 return val;
2527 return put_user(dmabuf->fragsize, p);
2528 }
2529 }
2530 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002531 state = card->states[0];
2532 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 dmabuf = &state->dmabuf;
2534 if ((val = prog_dmabuf(state)))
2535 return val;
2536 return put_user(dmabuf->fragsize/dmabuf->divisor,
2537 p);
2538 }
2539 }
2540 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
2542 return put_user(AFMT_S16_LE | AFMT_U8, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 case SNDCTL_DSP_SETFMT: /* Select sample format */
2544 if (get_user(val, p))
2545 return -EFAULT;
2546 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2547 "cs46xx: cs_ioctl() DSP_SETFMT %s %s %s %s\n",
2548 file->f_mode & FMODE_WRITE ? "DAC" : "",
2549 file->f_mode & FMODE_READ ? "ADC" : "",
2550 val == AFMT_S16_LE ? "16Bit Signed" : "",
2551 val == AFMT_U8 ? "8Bit Unsigned" : "") );
2552 valsave = val;
2553 if (val != AFMT_QUERY) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002554 if (val==AFMT_S16_LE || val==AFMT_U8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002556 state = card->states[1];
2557 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 dmabuf = &state->dmabuf;
2559 stop_dac(state);
2560 dmabuf->ready = 0;
2561 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002562 if (val == AFMT_S16_LE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 dmabuf->fmt |= CS_FMT_16BIT;
2564 else
2565 dmabuf->fmt &= ~CS_FMT_16BIT;
2566 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002567 if ((ret = prog_dmabuf(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 return ret;
2569 }
2570 }
2571 if (file->f_mode & FMODE_READ) {
2572 val = valsave;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002573 state = card->states[0];
2574 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 dmabuf = &state->dmabuf;
2576 stop_adc(state);
2577 dmabuf->ready = 0;
2578 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002579 if (val == AFMT_S16_LE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 dmabuf->fmt |= CS_FMT_16BIT;
2581 else
2582 dmabuf->fmt &= ~CS_FMT_16BIT;
2583 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002584 if ((ret = prog_dmabuf(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 return ret;
2586 }
2587 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002588 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 CS_DBGOUT(CS_IOCTL | CS_ERROR, 2, printk(
2590 "cs46xx: DSP_SETFMT() Unsupported format (0x%x)\n",
2591 valsave) );
2592 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002593 } else {
2594 if (file->f_mode & FMODE_WRITE) {
2595 state = card->states[1];
2596 if (state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002598 } else if (file->f_mode & FMODE_READ) {
2599 state = card->states[0];
2600 if (state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 dmabuf = &state->dmabuf;
2602 }
2603 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002604 if (dmabuf) {
2605 if (dmabuf->fmt & CS_FMT_16BIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 return put_user(AFMT_S16_LE, p);
2607 else
2608 return put_user(AFMT_U8, p);
2609 }
2610 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 case SNDCTL_DSP_CHANNELS:
2612 if (get_user(val, p))
2613 return -EFAULT;
2614 if (val != 0) {
2615 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002616 state = card->states[1];
2617 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 dmabuf = &state->dmabuf;
2619 stop_dac(state);
2620 dmabuf->ready = 0;
2621 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002622 if (val > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 dmabuf->fmt |= CS_FMT_STEREO;
2624 else
2625 dmabuf->fmt &= ~CS_FMT_STEREO;
2626 cs_set_divisor(dmabuf);
2627 if (prog_dmabuf(state))
2628 return 0;
2629 }
2630 }
2631 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002632 state = card->states[0];
2633 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 dmabuf = &state->dmabuf;
2635 stop_adc(state);
2636 dmabuf->ready = 0;
2637 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002638 if (val > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 dmabuf->fmt |= CS_FMT_STEREO;
2640 else
2641 dmabuf->fmt &= ~CS_FMT_STEREO;
2642 cs_set_divisor(dmabuf);
2643 if (prog_dmabuf(state))
2644 return 0;
2645 }
2646 }
2647 }
2648 return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
2649 p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 case SNDCTL_DSP_POST:
2651 /*
2652 * There will be a longer than normal pause in the data.
2653 * so... do nothing, because there is nothing that we can do.
2654 */
2655 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 case SNDCTL_DSP_SUBDIVIDE:
2657 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002658 state = card->states[1];
2659 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 dmabuf = &state->dmabuf;
2661 if (dmabuf->subdivision)
2662 return -EINVAL;
2663 if (get_user(val, p))
2664 return -EFAULT;
2665 if (val != 1 && val != 2)
2666 return -EINVAL;
2667 dmabuf->subdivision = val;
2668 }
2669 }
2670 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002671 state = card->states[0];
2672 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 dmabuf = &state->dmabuf;
2674 if (dmabuf->subdivision)
2675 return -EINVAL;
2676 if (get_user(val, p))
2677 return -EFAULT;
2678 if (val != 1 && val != 2)
2679 return -EINVAL;
2680 dmabuf->subdivision = val;
2681 }
2682 }
2683 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 case SNDCTL_DSP_SETFRAGMENT:
2685 if (get_user(val, p))
2686 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002688 state = card->states[1];
2689 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 dmabuf = &state->dmabuf;
2691 dmabuf->ossfragshift = val & 0xffff;
2692 dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
2693 }
2694 }
2695 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002696 state = card->states[0];
2697 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 dmabuf = &state->dmabuf;
2699 dmabuf->ossfragshift = val & 0xffff;
2700 dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
2701 }
2702 }
2703 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 case SNDCTL_DSP_GETOSPACE:
2705 if (!(file->f_mode & FMODE_WRITE))
2706 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002707 state = card->states[1];
2708 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 dmabuf = &state->dmabuf;
2710 spin_lock_irqsave(&state->card->lock, flags);
2711 cs_update_ptr(card, CS_TRUE);
2712 abinfo.fragsize = dmabuf->fragsize;
2713 abinfo.fragstotal = dmabuf->numfrag;
2714 /*
2715 * for mmap we always have total space available
2716 */
2717 if (dmabuf->mapped)
2718 abinfo.bytes = dmabuf->dmasize;
2719 else
2720 abinfo.bytes = dmabuf->dmasize - dmabuf->count;
2721
2722 abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
2723 spin_unlock_irqrestore(&state->card->lock, flags);
2724 return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
2725 }
2726 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 case SNDCTL_DSP_GETISPACE:
2728 if (!(file->f_mode & FMODE_READ))
2729 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002730 state = card->states[0];
2731 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 dmabuf = &state->dmabuf;
2733 spin_lock_irqsave(&state->card->lock, flags);
2734 cs_update_ptr(card, CS_TRUE);
2735 abinfo.fragsize = dmabuf->fragsize/dmabuf->divisor;
2736 abinfo.bytes = dmabuf->count/dmabuf->divisor;
2737 abinfo.fragstotal = dmabuf->numfrag;
2738 abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
2739 spin_unlock_irqrestore(&state->card->lock, flags);
2740 return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
2741 }
2742 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 case SNDCTL_DSP_NONBLOCK:
2744 file->f_flags |= O_NONBLOCK;
2745 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 case SNDCTL_DSP_GETCAPS:
2747 return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
2748 p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 case SNDCTL_DSP_GETTRIGGER:
2750 val = 0;
2751 CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()+\n") );
Jesper Juhl2eebb192006-06-23 02:05:26 -07002752 if (file->f_mode & FMODE_WRITE) {
2753 state = card->states[1];
2754 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002756 if (dmabuf->enable & DAC_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 val |= PCM_ENABLE_INPUT;
2758 }
2759 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002760 if (file->f_mode & FMODE_READ) {
2761 if (state) {
2762 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002764 if (dmabuf->enable & ADC_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 val |= PCM_ENABLE_OUTPUT;
2766 }
2767 }
2768 CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()- val=0x%x\n",val) );
2769 return put_user(val, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 case SNDCTL_DSP_SETTRIGGER:
2771 if (get_user(val, p))
2772 return -EFAULT;
2773 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002774 state = card->states[0];
2775 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 dmabuf = &state->dmabuf;
2777 if (val & PCM_ENABLE_INPUT) {
2778 if (!dmabuf->ready && (ret = prog_dmabuf(state)))
2779 return ret;
2780 start_adc(state);
2781 } else
2782 stop_adc(state);
2783 }
2784 }
2785 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002786 state = card->states[1];
2787 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 dmabuf = &state->dmabuf;
2789 if (val & PCM_ENABLE_OUTPUT) {
2790 if (!dmabuf->ready && (ret = prog_dmabuf(state)))
2791 return ret;
2792 start_dac(state);
2793 } else
2794 stop_dac(state);
2795 }
2796 }
2797 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 case SNDCTL_DSP_GETIPTR:
2799 if (!(file->f_mode & FMODE_READ))
2800 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002801 state = card->states[0];
2802 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 dmabuf = &state->dmabuf;
2804 spin_lock_irqsave(&state->card->lock, flags);
2805 cs_update_ptr(card, CS_TRUE);
2806 cinfo.bytes = dmabuf->total_bytes/dmabuf->divisor;
2807 cinfo.blocks = dmabuf->count/dmabuf->divisor >> dmabuf->fragshift;
2808 cinfo.ptr = dmabuf->hwptr/dmabuf->divisor;
2809 spin_unlock_irqrestore(&state->card->lock, flags);
2810 if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
2811 return -EFAULT;
2812 return 0;
2813 }
2814 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 case SNDCTL_DSP_GETOPTR:
2816 if (!(file->f_mode & FMODE_WRITE))
2817 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002818 state = card->states[1];
2819 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 dmabuf = &state->dmabuf;
2821 spin_lock_irqsave(&state->card->lock, flags);
2822 cs_update_ptr(card, CS_TRUE);
2823 cinfo.bytes = dmabuf->total_bytes;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002824 if (dmabuf->mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 cinfo.blocks = (cinfo.bytes >> dmabuf->fragshift)
2826 - dmabuf->blocks;
2827 CS_DBGOUT(CS_PARMS, 8,
2828 printk("total_bytes=%d blocks=%d dmabuf->blocks=%d\n",
2829 cinfo.bytes,cinfo.blocks,dmabuf->blocks) );
2830 dmabuf->blocks = cinfo.bytes >> dmabuf->fragshift;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002831 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
2833 }
2834 cinfo.ptr = dmabuf->hwptr;
2835
2836 CS_DBGOUT(CS_PARMS, 4, printk(
2837 "cs46xx: GETOPTR bytes=%d blocks=%d ptr=%d\n",
2838 cinfo.bytes,cinfo.blocks,cinfo.ptr) );
2839 spin_unlock_irqrestore(&state->card->lock, flags);
2840 if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
2841 return -EFAULT;
2842 return 0;
2843 }
2844 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 case SNDCTL_DSP_SETDUPLEX:
2846 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 case SNDCTL_DSP_GETODELAY:
2848 if (!(file->f_mode & FMODE_WRITE))
2849 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002850 state = card->states[1];
2851 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 dmabuf = &state->dmabuf;
2853 spin_lock_irqsave(&state->card->lock, flags);
2854 cs_update_ptr(card, CS_TRUE);
2855 val = dmabuf->count;
2856 spin_unlock_irqrestore(&state->card->lock, flags);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002857 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 val = 0;
2859 return put_user(val, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 case SOUND_PCM_READ_RATE:
Jesper Juhl2eebb192006-06-23 02:05:26 -07002861 if (file->f_mode & FMODE_READ)
2862 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07002864 state = card->states[1];
2865 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 dmabuf = &state->dmabuf;
2867 return put_user(dmabuf->rate, p);
2868 }
2869 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 case SOUND_PCM_READ_CHANNELS:
Jesper Juhl2eebb192006-06-23 02:05:26 -07002871 if (file->f_mode & FMODE_READ)
2872 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07002874 state = card->states[1];
2875 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 dmabuf = &state->dmabuf;
2877 return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
2878 p);
2879 }
2880 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 case SOUND_PCM_READ_BITS:
Jesper Juhl2eebb192006-06-23 02:05:26 -07002882 if (file->f_mode & FMODE_READ)
2883 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07002885 state = card->states[1];
2886 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 dmabuf = &state->dmabuf;
2888 return put_user((dmabuf->fmt & CS_FMT_16BIT) ?
2889 AFMT_S16_LE : AFMT_U8, p);
2890
2891 }
2892 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 case SNDCTL_DSP_MAPINBUF:
2894 case SNDCTL_DSP_MAPOUTBUF:
2895 case SNDCTL_DSP_SETSYNCRO:
2896 case SOUND_PCM_WRITE_FILTER:
2897 case SOUND_PCM_READ_FILTER:
2898 return -EINVAL;
2899 }
2900 return -EINVAL;
2901}
2902
2903
2904/*
2905 * AMP control - null AMP
2906 */
2907
2908static void amp_none(struct cs_card *card, int change)
2909{
2910}
2911
2912/*
2913 * Crystal EAPD mode
2914 */
2915
2916static void amp_voyetra(struct cs_card *card, int change)
2917{
2918 /* Manage the EAPD bit on the Crystal 4297
2919 and the Analog AD1885 */
2920
Jesper Juhl2eebb192006-06-23 02:05:26 -07002921 int old = card->amplifier;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
2923 card->amplifier+=change;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002924 if (card->amplifier && !old) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 /* Turn the EAPD amp on */
2926 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL,
2927 cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) |
2928 0x8000);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002929 } else if(old && !card->amplifier) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 /* Turn the EAPD amp off */
2931 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL,
2932 cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
2933 ~0x8000);
2934 }
2935}
2936
2937
2938/*
2939 * Game Theatre XP card - EGPIO[2] is used to enable the external amp.
2940 */
2941
2942static void amp_hercules(struct cs_card *card, int change)
2943{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002944 int old = card->amplifier;
2945 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
2947 "cs46xx: amp_hercules() called before initialized.\n"));
2948 return;
2949 }
2950 card->amplifier+=change;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002951 if ((card->amplifier && !old) && !(hercules_egpio_disable)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO
2953 "cs46xx: amp_hercules() external amp enabled\n"));
2954 cs461x_pokeBA0(card, BA0_EGPIODR,
2955 EGPIODR_GPOE2); /* enable EGPIO2 output */
2956 cs461x_pokeBA0(card, BA0_EGPIOPTR,
2957 EGPIOPTR_GPPT2); /* open-drain on output */
Jesper Juhl2eebb192006-06-23 02:05:26 -07002958 } else if (old && !card->amplifier) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO
2960 "cs46xx: amp_hercules() external amp disabled\n"));
2961 cs461x_pokeBA0(card, BA0_EGPIODR, 0); /* disable */
2962 cs461x_pokeBA0(card, BA0_EGPIOPTR, 0); /* disable */
2963 }
2964}
2965
2966/*
2967 * Handle the CLKRUN on a thinkpad. We must disable CLKRUN support
2968 * whenever we need to beat on the chip.
2969 *
2970 * The original idea and code for this hack comes from David Kaiser at
2971 * Linuxcare. Perhaps one day Crystal will document their chips well
2972 * enough to make them useful.
2973 */
2974
2975static void clkrun_hack(struct cs_card *card, int change)
2976{
2977 struct pci_dev *acpi_dev;
2978 u16 control;
2979 u8 pp;
2980 unsigned long port;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002981 int old = card->active;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982
2983 card->active+=change;
2984
2985 acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002986 if (acpi_dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 return; /* Not a thinkpad thats for sure */
2988
2989 /* Find the control port */
2990 pci_read_config_byte(acpi_dev, 0x41, &pp);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002991 port = pp << 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992
2993 /* Read ACPI port */
Jesper Juhl2eebb192006-06-23 02:05:26 -07002994 control = inw(port + 0x10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
2996 /* Flip CLKRUN off while running */
Jesper Juhl2eebb192006-06-23 02:05:26 -07002997 if (!card->active && old) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
2999 "cs46xx: clkrun() enable clkrun - change=%d active=%d\n",
3000 change,card->active));
3001 outw(control|0x2000, port+0x10);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003002 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 /*
3004 * sometimes on a resume the bit is set, so always reset the bit.
3005 */
3006 CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
3007 "cs46xx: clkrun() disable clkrun - change=%d active=%d\n",
3008 change,card->active));
3009 outw(control&~0x2000, port+0x10);
3010 }
3011}
3012
3013
3014static int cs_open(struct inode *inode, struct file *file)
3015{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003016 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 struct cs_state *state = NULL;
3018 struct dmabuf *dmabuf = NULL;
3019 struct list_head *entry;
3020 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003021 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 unsigned int tmp;
3023
3024 CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()+ file=%p %s %s\n",
3025 file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
3026 file->f_mode & FMODE_READ ? "FMODE_READ" : "") );
3027
Jesper Juhl2eebb192006-06-23 02:05:26 -07003028 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 card = list_entry(entry, struct cs_card, list);
3030
3031 if (!((card->dev_audio ^ minor) & ~0xf))
3032 break;
3033 }
3034 if (entry == &cs46xx_devs)
3035 return -ENODEV;
3036 if (!card) {
3037 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
3038 "cs46xx: cs_open(): Error - unable to find audio card struct\n"));
3039 return -ENODEV;
3040 }
3041
3042 /*
3043 * hardcode state[0] for capture, [1] for playback
3044 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003045 if (file->f_mode & FMODE_READ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 CS_DBGOUT(CS_WAVE_READ, 2, printk("cs46xx: cs_open() FMODE_READ\n") );
3047 if (card->states[0] == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003048 state = card->states[0] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 kmalloc(sizeof(struct cs_state), GFP_KERNEL);
3050 if (state == NULL)
3051 return -ENOMEM;
3052 memset(state, 0, sizeof(struct cs_state));
Ingo Molnar910f5d22006-03-23 03:00:39 -08003053 mutex_init(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 dmabuf = &state->dmabuf;
3055 dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003056 if (dmabuf->pbuf == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 kfree(state);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003058 card->states[0] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 return -ENOMEM;
3060 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003061 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003063 if (state->open_mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 return -EBUSY;
3065 }
3066 dmabuf->channel = card->alloc_rec_pcm_channel(card);
3067
3068 if (dmabuf->channel == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003069 kfree(card->states[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 card->states[0] = NULL;
3071 return -ENODEV;
3072 }
3073
3074 /* Now turn on external AMP if needed */
3075 state->card = card;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003076 state->card->active_ctrl(state->card, 1);
3077 state->card->amplifier_ctrl(state->card, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078
Jesper Juhl2eebb192006-06-23 02:05:26 -07003079 if ((tmp = cs46xx_powerup(card, CS_POWER_ADC))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003081 "cs46xx: cs46xx_powerup of ADC failed (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 return -EIO;
3083 }
3084
3085 dmabuf->channel->state = state;
3086 /* initialize the virtual channel */
3087 state->virt = 0;
3088 state->magic = CS_STATE_MAGIC;
3089 init_waitqueue_head(&dmabuf->wait);
Ingo Molnar910f5d22006-03-23 03:00:39 -08003090 mutex_init(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 file->private_data = card;
3092
Ingo Molnar910f5d22006-03-23 03:00:39 -08003093 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
3095 /* set default sample format. According to OSS Programmer's Guide /dev/dsp
3096 should be default to unsigned 8-bits, mono, with sample rate 8kHz and
3097 /dev/dspW will accept 16-bits sample */
3098
3099 /* Default input is 8bit mono */
3100 dmabuf->fmt &= ~CS_FMT_MASK;
3101 dmabuf->type = CS_TYPE_ADC;
3102 dmabuf->ossfragshift = 0;
3103 dmabuf->ossmaxfrags = 0;
3104 dmabuf->subdivision = 0;
3105 cs_set_adc_rate(state, 8000);
3106 cs_set_divisor(dmabuf);
3107
3108 state->open_mode |= FMODE_READ;
Ingo Molnar910f5d22006-03-23 03:00:39 -08003109 mutex_unlock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003111 if (file->f_mode & FMODE_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 CS_DBGOUT(CS_OPEN, 2, printk("cs46xx: cs_open() FMODE_WRITE\n") );
3113 if (card->states[1] == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003114 state = card->states[1] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115 kmalloc(sizeof(struct cs_state), GFP_KERNEL);
3116 if (state == NULL)
3117 return -ENOMEM;
3118 memset(state, 0, sizeof(struct cs_state));
Ingo Molnar910f5d22006-03-23 03:00:39 -08003119 mutex_init(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 dmabuf = &state->dmabuf;
3121 dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003122 if (dmabuf->pbuf == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 kfree(state);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003124 card->states[1] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 return -ENOMEM;
3126 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003127 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003129 if (state->open_mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 return -EBUSY;
3131 }
3132 dmabuf->channel = card->alloc_pcm_channel(card);
3133
3134 if (dmabuf->channel == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003135 kfree(card->states[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 card->states[1] = NULL;
3137 return -ENODEV;
3138 }
3139
3140 /* Now turn on external AMP if needed */
3141 state->card = card;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003142 state->card->active_ctrl(state->card, 1);
3143 state->card->amplifier_ctrl(state->card, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144
Jesper Juhl2eebb192006-06-23 02:05:26 -07003145 if ((tmp = cs46xx_powerup(card, CS_POWER_DAC))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003147 "cs46xx: cs46xx_powerup of DAC failed (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 return -EIO;
3149 }
3150
3151 dmabuf->channel->state = state;
3152 /* initialize the virtual channel */
3153 state->virt = 1;
3154 state->magic = CS_STATE_MAGIC;
3155 init_waitqueue_head(&dmabuf->wait);
Ingo Molnar910f5d22006-03-23 03:00:39 -08003156 mutex_init(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 file->private_data = card;
3158
Ingo Molnar910f5d22006-03-23 03:00:39 -08003159 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
3161 /* set default sample format. According to OSS Programmer's Guide /dev/dsp
3162 should be default to unsigned 8-bits, mono, with sample rate 8kHz and
3163 /dev/dspW will accept 16-bits sample */
3164
3165 /* Default output is 8bit mono. */
3166 dmabuf->fmt &= ~CS_FMT_MASK;
3167 dmabuf->type = CS_TYPE_DAC;
3168 dmabuf->ossfragshift = 0;
3169 dmabuf->ossmaxfrags = 0;
3170 dmabuf->subdivision = 0;
3171 cs_set_dac_rate(state, 8000);
3172 cs_set_divisor(dmabuf);
3173
3174 state->open_mode |= FMODE_WRITE;
Ingo Molnar910f5d22006-03-23 03:00:39 -08003175 mutex_unlock(&state->open_mutex);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003176 if ((ret = prog_dmabuf(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 return ret;
3178 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003179 CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()- 0\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 return nonseekable_open(inode, file);
3181}
3182
3183static int cs_release(struct inode *inode, struct file *file)
3184{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003185 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 struct dmabuf *dmabuf;
3187 struct cs_state *state;
3188 unsigned int tmp;
3189 CS_DBGOUT(CS_RELEASE | CS_FUNCTION, 2, printk("cs46xx: cs_release()+ file=%p %s %s\n",
3190 file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
Jesper Juhl2eebb192006-06-23 02:05:26 -07003191 file->f_mode & FMODE_READ ? "FMODE_READ" : ""));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
3193 if (!(file->f_mode & (FMODE_WRITE | FMODE_READ)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003196 if (state) {
3197 if ((state->open_mode & FMODE_WRITE) & (file->f_mode & FMODE_WRITE)) {
3198 CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_WRITE\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 dmabuf = &state->dmabuf;
3200 cs_clear_tail(state);
3201 drain_dac(state, file->f_flags & O_NONBLOCK);
3202 /* stop DMA state machine and free DMA buffers/channels */
Ingo Molnar910f5d22006-03-23 03:00:39 -08003203 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 stop_dac(state);
3205 dealloc_dmabuf(state);
3206 state->card->free_pcm_channel(state->card, dmabuf->channel->num);
3207 free_page((unsigned long)state->dmabuf.pbuf);
3208
Ingo Molnar910f5d22006-03-23 03:00:39 -08003209 /* we're covered by the open_mutex */
3210 mutex_unlock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 state->card->states[state->virt] = NULL;
3212 state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
3213
Jesper Juhl2eebb192006-06-23 02:05:26 -07003214 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
3216 "cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) );
3217 }
3218
3219 /* Now turn off external AMP if needed */
3220 state->card->amplifier_ctrl(state->card, -1);
3221 state->card->active_ctrl(state->card, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 kfree(state);
3223 }
3224 }
3225
3226 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003227 if (state) {
3228 if ((state->open_mode & FMODE_READ) & (file->f_mode & FMODE_READ)) {
3229 CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_READ\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 dmabuf = &state->dmabuf;
Ingo Molnar910f5d22006-03-23 03:00:39 -08003231 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 stop_adc(state);
3233 dealloc_dmabuf(state);
3234 state->card->free_pcm_channel(state->card, dmabuf->channel->num);
3235 free_page((unsigned long)state->dmabuf.pbuf);
3236
Ingo Molnar910f5d22006-03-23 03:00:39 -08003237 /* we're covered by the open_mutex */
3238 mutex_unlock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 state->card->states[state->virt] = NULL;
3240 state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
3241
Jesper Juhl2eebb192006-06-23 02:05:26 -07003242 if ((tmp = cs461x_powerdown(card, CS_POWER_ADC, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
3244 "cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) );
3245 }
3246
3247 /* Now turn off external AMP if needed */
3248 state->card->amplifier_ctrl(state->card, -1);
3249 state->card->active_ctrl(state->card, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 kfree(state);
3251 }
3252 }
3253
Jesper Juhl2eebb192006-06-23 02:05:26 -07003254 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk("cs46xx: cs_release()- 0\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 return 0;
3256}
3257
3258static void printpm(struct cs_card *s)
3259{
3260 CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
3261 CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
3262 (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue));
3263 CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n",
3264 s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue));
3265 CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n",
3266 s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue));
3267 CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n",
3268 s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue));
3269 CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n",
3270 s->pm.u32SSCR,s->pm.u32SRCSA));
3271 CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n",
3272 s->pm.u32DacASR,s->pm.u32AdcASR));
3273 CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n",
3274 s->pm.u32DacSR,s->pm.u32AdcSR));
3275 CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n",
3276 s->pm.u32MIDCR_Save));
3277 CS_DBGOUT(CS_PM, 9, printk("u32AC97_powerdown: 0x%x _general_purpose 0x%x\n",
3278 s->pm.u32AC97_powerdown,s->pm.u32AC97_general_purpose));
3279 CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume: 0x%x\n",
3280 s->pm.u32AC97_master_volume));
3281 CS_DBGOUT(CS_PM, 9, printk("u32AC97_headphone_volume: 0x%x\n",
3282 s->pm.u32AC97_headphone_volume));
3283 CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume_mono: 0x%x\n",
3284 s->pm.u32AC97_master_volume_mono));
3285 CS_DBGOUT(CS_PM, 9, printk("u32AC97_pcm_out_volume: 0x%x\n",
3286 s->pm.u32AC97_pcm_out_volume));
3287 CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_play: 0x%x dmabuf_count_play: %d\n",
3288 s->pm.dmabuf_swptr_play,s->pm.dmabuf_count_play));
3289 CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_capture: 0x%x dmabuf_count_capture: %d\n",
3290 s->pm.dmabuf_swptr_capture,s->pm.dmabuf_count_capture));
3291
3292}
3293
3294/****************************************************************************
3295*
3296* Suspend - save the ac97 regs, mute the outputs and power down the part.
3297*
3298****************************************************************************/
3299static void cs46xx_ac97_suspend(struct cs_card *card)
3300{
3301 int Count,i;
3302 struct ac97_codec *dev=card->ac97_codec[0];
3303 unsigned int tmp;
3304
3305 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n"));
3306
Jesper Juhl2eebb192006-06-23 02:05:26 -07003307 if (card->states[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 stop_dac(card->states[1]);
3309 resync_dma_ptrs(card->states[1]);
3310 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003311 if (card->states[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 stop_adc(card->states[0]);
3313 resync_dma_ptrs(card->states[0]);
3314 }
3315
Jesper Juhl2eebb192006-06-23 02:05:26 -07003316 for (Count = 0x2, i = 0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE)
3317 && (i < CS46XX_AC97_NUMBER_RESTORE_REGS);
3318 Count += 2, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 card->pm.ac97[i] = cs_ac97_get(dev, BA0_AC97_RESET + Count);
3320 }
3321/*
3322* Save the ac97 volume registers as well as the current powerdown state.
3323* Now, mute the all the outputs (master, headphone, and mono), as well
3324* as the PCM volume, in preparation for powering down the entire part.
3325 card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev,
3326 (u8)BA0_AC97_MASTER_VOLUME);
3327 card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev,
3328 (u8)BA0_AC97_HEADPHONE_VOLUME);
3329 card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev,
3330 (u8)BA0_AC97_MASTER_VOLUME_MONO);
3331 card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev,
3332 (u8)BA0_AC97_PCM_OUT_VOLUME);
3333*/
3334/*
3335* mute the outputs
3336*/
3337 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
3338 cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
3339 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
3340 cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
3341
3342/*
3343* save the registers that cause pops
3344*/
3345 card->pm.u32AC97_powerdown = (u32)cs_ac97_get(dev, (u8)AC97_POWER_CONTROL);
3346 card->pm.u32AC97_general_purpose = (u32)cs_ac97_get(dev, (u8)BA0_AC97_GENERAL_PURPOSE);
3347/*
3348* And power down everything on the AC97 codec.
3349* well, for now, only power down the DAC/ADC and MIXER VREFON components.
3350* trouble with removing VREF.
3351*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003352 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
3353 CS_POWER_MIXVON, CS_TRUE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003355 "cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 }
3357
3358 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()-\n"));
3359}
3360
3361/****************************************************************************
3362*
3363* Resume - power up the part and restore its registers..
3364*
3365****************************************************************************/
3366static void cs46xx_ac97_resume(struct cs_card *card)
3367{
3368 int Count,i;
3369 struct ac97_codec *dev=card->ac97_codec[0];
3370
3371 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()+\n"));
3372
3373/*
3374* First, we restore the state of the general purpose register. This
3375* contains the mic select (mic1 or mic2) and if we restore this after
3376* we restore the mic volume/boost state and mic2 was selected at
3377* suspend time, we will end up with a brief period of time where mic1
3378* is selected with the volume/boost settings for mic2, causing
3379* acoustic feedback. So we restore the general purpose register
3380* first, thereby getting the correct mic selected before we restore
3381* the mic volume/boost.
3382*/
3383 cs_ac97_set(dev, (u8)BA0_AC97_GENERAL_PURPOSE,
3384 (u16)card->pm.u32AC97_general_purpose);
3385/*
3386* Now, while the outputs are still muted, restore the state of power
3387* on the AC97 part.
3388*/
3389 cs_ac97_set(dev, (u8)BA0_AC97_POWERDOWN, (u16)card->pm.u32AC97_powerdown);
3390 mdelay(5 * cs_laptop_wait);
3391/*
3392* Restore just the first set of registers, from register number
3393* 0x02 to the register number that ulHighestRegToRestore specifies.
3394*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003395 for (Count = 0x2, i=0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE) &&
3396 (i < CS46XX_AC97_NUMBER_RESTORE_REGS); Count += 2, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 cs_ac97_set(dev, (u8)(BA0_AC97_RESET + Count), (u16)card->pm.ac97[i]);
3398 }
3399
3400 /* Check if we have to init the amplifier */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003401 if (card->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 card->amp_init(card);
3403
3404 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()-\n"));
3405}
3406
3407
3408static int cs46xx_restart_part(struct cs_card *card)
3409{
3410 struct dmabuf *dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003411
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3413 printk( "cs46xx: cs46xx_restart_part()+\n"));
Jesper Juhl2eebb192006-06-23 02:05:26 -07003414 if (card->states[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415 dmabuf = &card->states[1]->dmabuf;
3416 dmabuf->ready = 0;
3417 resync_dma_ptrs(card->states[1]);
3418 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003419 if (__prog_dmabuf(card->states[1])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 CS_DBGOUT(CS_PM | CS_ERROR, 1,
3421 printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n"));
3422 return -1;
3423 }
3424 cs_set_dac_rate(card->states[1], dmabuf->rate);
3425 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003426 if (card->states[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 dmabuf = &card->states[0]->dmabuf;
3428 dmabuf->ready = 0;
3429 resync_dma_ptrs(card->states[0]);
3430 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003431 if (__prog_dmabuf(card->states[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 CS_DBGOUT(CS_PM | CS_ERROR, 1,
3433 printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n"));
3434 return -1;
3435 }
3436 cs_set_adc_rate(card->states[0], dmabuf->rate);
3437 }
3438 card->pm.flags |= CS46XX_PM_RESUMED;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003439 if (card->states[0])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 start_adc(card->states[0]);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003441 if (card->states[1])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 start_dac(card->states[1]);
3443
3444 card->pm.flags |= CS46XX_PM_IDLE;
3445 card->pm.flags &= ~(CS46XX_PM_SUSPENDING | CS46XX_PM_SUSPENDED
3446 | CS46XX_PM_RESUMING | CS46XX_PM_RESUMED);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003447 if (card->states[0])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 wake_up(&card->states[0]->dmabuf.wait);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003449 if (card->states[1])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 wake_up(&card->states[1]->dmabuf.wait);
3451
3452 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3453 printk( "cs46xx: cs46xx_restart_part()-\n"));
3454 return 0;
3455}
3456
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457static void cs461x_reset(struct cs_card *card);
3458static void cs461x_proc_stop(struct cs_card *card);
Pavel Machek3bfffd92005-04-16 15:25:37 -07003459static int cs46xx_suspend(struct cs_card *card, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460{
3461 unsigned int tmp;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003462
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3464 printk("cs46xx: cs46xx_suspend()+ flags=0x%x s=%p\n",
3465 (unsigned)card->pm.flags,card));
3466/*
3467* check the current state, only suspend if IDLE
3468*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003469 if (!(card->pm.flags & CS46XX_PM_IDLE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 CS_DBGOUT(CS_PM | CS_ERROR, 2,
3471 printk("cs46xx: cs46xx_suspend() unable to suspend, not IDLE\n"));
3472 return 1;
3473 }
3474 card->pm.flags &= ~CS46XX_PM_IDLE;
3475 card->pm.flags |= CS46XX_PM_SUSPENDING;
3476
3477 card->active_ctrl(card,1);
3478
3479 tmp = cs461x_peek(card, BA1_PFIE);
3480 tmp &= ~0x0000f03f;
3481 tmp |= 0x00000010;
3482 cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */
3483
3484 tmp = cs461x_peek(card, BA1_CIE);
3485 tmp &= ~0x0000003f;
3486 tmp |= 0x00000011;
3487 cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */
3488
3489 /*
3490 * Stop playback DMA.
3491 */
3492 tmp = cs461x_peek(card, BA1_PCTL);
3493 cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
3494
3495 /*
3496 * Stop capture DMA.
3497 */
3498 tmp = cs461x_peek(card, BA1_CCTL);
3499 cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
3500
Jesper Juhl2eebb192006-06-23 02:05:26 -07003501 if (card->states[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 card->pm.dmabuf_swptr_play = card->states[1]->dmabuf.swptr;
3503 card->pm.dmabuf_count_play = card->states[1]->dmabuf.count;
3504 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003505 if (card->states[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 card->pm.dmabuf_swptr_capture = card->states[0]->dmabuf.swptr;
3507 card->pm.dmabuf_count_capture = card->states[0]->dmabuf.count;
3508 }
3509
3510 cs46xx_ac97_suspend(card);
3511
3512 /*
3513 * Reset the processor.
3514 */
3515 cs461x_reset(card);
3516
3517 cs461x_proc_stop(card);
3518
3519 /*
3520 * Power down the DAC and ADC. For now leave the other areas on.
3521 */
3522 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x0300);
3523
3524 /*
3525 * Power down the PLL.
3526 */
3527 cs461x_pokeBA0(card, BA0_CLKCR1, 0);
3528
3529 /*
3530 * Turn off the Processor by turning off the software clock enable flag in
3531 * the clock control register.
3532 */
3533 tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE;
3534 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
3535
3536 card->active_ctrl(card,-1);
3537
3538 card->pm.flags &= ~CS46XX_PM_SUSPENDING;
3539 card->pm.flags |= CS46XX_PM_SUSPENDED;
3540
3541 printpm(card);
3542
3543 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3544 printk("cs46xx: cs46xx_suspend()- flags=0x%x\n",
3545 (unsigned)card->pm.flags));
3546 return 0;
3547}
3548
3549static int cs46xx_resume(struct cs_card *card)
3550{
3551 int i;
3552
3553 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3554 printk( "cs46xx: cs46xx_resume()+ flags=0x%x\n",
3555 (unsigned)card->pm.flags));
Jesper Juhl2eebb192006-06-23 02:05:26 -07003556 if (!(card->pm.flags & CS46XX_PM_SUSPENDED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 CS_DBGOUT(CS_PM | CS_ERROR, 2,
3558 printk("cs46xx: cs46xx_resume() unable to resume, not SUSPENDED\n"));
3559 return 1;
3560 }
3561 card->pm.flags |= CS46XX_PM_RESUMING;
3562 card->pm.flags &= ~CS46XX_PM_SUSPENDED;
3563 printpm(card);
3564 card->active_ctrl(card, 1);
3565
Jesper Juhl2eebb192006-06-23 02:05:26 -07003566 for (i = 0; i < 5; i++) {
3567 if (cs_hardware_init(card) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
3569 "cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n"));
3570 mdelay(10 * cs_laptop_wait);
3571 cs461x_reset(card);
3572 continue;
3573 }
3574 break;
3575 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003576 if (i >= 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
3578 "cs46xx: cs46xx_resume()- cs_hardware_init() failed, retried %d times.\n",i));
3579 return 0;
3580 }
3581
Jesper Juhl2eebb192006-06-23 02:05:26 -07003582 if (cs46xx_restart_part(card)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
3584 "cs46xx: cs46xx_resume(): cs46xx_restart_part() returned error\n"));
3585 }
3586
3587 card->active_ctrl(card, -1);
3588
3589 CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=0x%x\n",
3590 (unsigned)card->pm.flags));
3591 return 0;
3592}
3593
3594static /*const*/ struct file_operations cs461x_fops = {
3595 CS_OWNER CS_THIS_MODULE
3596 .llseek = no_llseek,
3597 .read = cs_read,
3598 .write = cs_write,
3599 .poll = cs_poll,
3600 .ioctl = cs_ioctl,
3601 .mmap = cs_mmap,
3602 .open = cs_open,
3603 .release = cs_release,
3604};
3605
3606/* Write AC97 codec registers */
3607
3608
3609static u16 _cs_ac97_get(struct ac97_codec *dev, u8 reg)
3610{
3611 struct cs_card *card = dev->private_data;
3612 int count,loopcnt;
3613 unsigned int tmp;
3614 u16 ret;
3615
3616 /*
3617 * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
3618 * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97
3619 * 3. Write ACCTL = Control Register = 460h for initiating the write
3620 * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
3621 * 5. if DCV not cleared, break and return error
3622 * 6. Read ACSTS = Status Register = 464h, check VSTS bit
3623 */
3624
3625 cs461x_peekBA0(card, BA0_ACSDA);
3626
3627 /*
3628 * Setup the AC97 control registers on the CS461x to send the
3629 * appropriate command to the AC97 to perform the read.
3630 * ACCAD = Command Address Register = 46Ch
3631 * ACCDA = Command Data Register = 470h
3632 * ACCTL = Control Register = 460h
3633 * set DCV - will clear when process completed
3634 * set CRW - Read command
3635 * set VFRM - valid frame enabled
3636 * set ESYN - ASYNC generation enabled
3637 * set RSTN - ARST# inactive, AC97 codec not reset
3638 */
3639
3640 cs461x_pokeBA0(card, BA0_ACCAD, reg);
3641 cs461x_pokeBA0(card, BA0_ACCDA, 0);
3642 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW |
3643 ACCTL_VFRM | ACCTL_ESYN |
3644 ACCTL_RSTN);
3645
3646
3647 /*
3648 * Wait for the read to occur.
3649 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003650 if (!(card->pm.flags & CS46XX_PM_IDLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 loopcnt = 2000;
3652 else
3653 loopcnt = 500 * cs_laptop_wait;
3654 loopcnt *= cs_laptop_wait;
3655 for (count = 0; count < loopcnt; count++) {
3656 /*
3657 * First, we want to wait for a short time.
3658 */
3659 udelay(10 * cs_laptop_wait);
3660 /*
3661 * Now, check to see if the read has completed.
3662 * ACCTL = 460h, DCV should be reset by now and 460h = 17h
3663 */
3664 if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV))
3665 break;
3666 }
3667
3668 /*
3669 * Make sure the read completed.
3670 */
3671 if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
3672 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
3673 "cs46xx: AC'97 read problem (ACCTL_DCV), reg = 0x%x returning 0xffff\n", reg));
3674 return 0xffff;
3675 }
3676
3677 /*
3678 * Wait for the valid status bit to go active.
3679 */
3680
Jesper Juhl2eebb192006-06-23 02:05:26 -07003681 if (!(card->pm.flags & CS46XX_PM_IDLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 loopcnt = 2000;
3683 else
3684 loopcnt = 1000;
3685 loopcnt *= cs_laptop_wait;
3686 for (count = 0; count < loopcnt; count++) {
3687 /*
3688 * Read the AC97 status register.
3689 * ACSTS = Status Register = 464h
3690 * VSTS - Valid Status
3691 */
3692 if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)
3693 break;
3694 udelay(10 * cs_laptop_wait);
3695 }
3696
3697 /*
3698 * Make sure we got valid status.
3699 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003700 if (!((tmp = cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 CS_DBGOUT(CS_ERROR, 2, printk(KERN_WARNING
3702 "cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x 0xffff \n",
3703 reg, tmp));
3704 return 0xffff;
3705 }
3706
3707 /*
3708 * Read the data returned from the AC97 register.
3709 * ACSDA = Status Data Register = 474h
3710 */
3711 CS_DBGOUT(CS_FUNCTION, 9, printk(KERN_INFO
3712 "cs46xx: cs_ac97_get() reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n",
3713 reg, cs461x_peekBA0(card, BA0_ACSDA),
3714 cs461x_peekBA0(card, BA0_ACCAD)));
3715 ret = cs461x_peekBA0(card, BA0_ACSDA);
3716 return ret;
3717}
3718
3719static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg)
3720{
3721 u16 ret;
3722 struct cs_card *card = dev->private_data;
3723
3724 spin_lock(&card->ac97_lock);
3725 ret = _cs_ac97_get(dev, reg);
3726 spin_unlock(&card->ac97_lock);
3727 return ret;
3728}
3729
3730static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
3731{
3732 struct cs_card *card = dev->private_data;
3733 int count;
3734 int val2 = 0;
3735
3736 spin_lock(&card->ac97_lock);
3737
Jesper Juhl2eebb192006-06-23 02:05:26 -07003738 if (reg == AC97_CD_VOL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 val2 = _cs_ac97_get(dev, AC97_CD_VOL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003740
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 /*
3742 * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
3743 * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97
3744 * 3. Write ACCTL = Control Register = 460h for initiating the write
3745 * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h
3746 * 5. if DCV not cleared, break and return error
3747 */
3748
3749 /*
3750 * Setup the AC97 control registers on the CS461x to send the
3751 * appropriate command to the AC97 to perform the read.
3752 * ACCAD = Command Address Register = 46Ch
3753 * ACCDA = Command Data Register = 470h
3754 * ACCTL = Control Register = 460h
3755 * set DCV - will clear when process completed
3756 * reset CRW - Write command
3757 * set VFRM - valid frame enabled
3758 * set ESYN - ASYNC generation enabled
3759 * set RSTN - ARST# inactive, AC97 codec not reset
3760 */
3761 cs461x_pokeBA0(card, BA0_ACCAD, reg);
3762 cs461x_pokeBA0(card, BA0_ACCDA, val);
3763 cs461x_peekBA0(card, BA0_ACCTL);
3764 cs461x_pokeBA0(card, BA0_ACCTL, 0 | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
3765 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM |
3766 ACCTL_ESYN | ACCTL_RSTN);
3767 for (count = 0; count < 1000; count++) {
3768 /*
3769 * First, we want to wait for a short time.
3770 */
3771 udelay(10 * cs_laptop_wait);
3772 /*
3773 * Now, check to see if the write has completed.
3774 * ACCTL = 460h, DCV should be reset by now and 460h = 07h
3775 */
3776 if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV))
3777 break;
3778 }
3779 /*
3780 * Make sure the write completed.
3781 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003782 if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
3784 "cs46xx: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val));
3785 }
3786
3787 spin_unlock(&card->ac97_lock);
3788
3789 /*
3790 * Adjust power if the mixer is selected/deselected according
3791 * to the CD.
3792 *
3793 * IF the CD is a valid input source (mixer or direct) AND
3794 * the CD is not muted THEN power is needed
3795 *
3796 * We do two things. When record select changes the input to
3797 * add/remove the CD we adjust the power count if the CD is
3798 * unmuted.
3799 *
3800 * When the CD mute changes we adjust the power level if the
3801 * CD was a valid input.
3802 *
3803 * We also check for CD volume != 0, as the CD mute isn't
3804 * normally tweaked from userspace.
3805 */
3806
3807 /* CD mute change ? */
3808
Jesper Juhl2eebb192006-06-23 02:05:26 -07003809 if (reg == AC97_CD_VOL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 /* Mute bit change ? */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003811 if ((val2^val) & 0x8000 ||
3812 ((val2 == 0x1f1f || val == 0x1f1f) && val2 != val)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 /* This is a hack but its cleaner than the alternatives.
3814 Right now card->ac97_codec[0] might be NULL as we are
3815 still doing codec setup. This does an early assignment
3816 to avoid the problem if it occurs */
3817
Jesper Juhl2eebb192006-06-23 02:05:26 -07003818 if (card->ac97_codec[0] == NULL)
3819 card->ac97_codec[0] = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820
3821 /* Mute on */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003822 if (val & 0x8000 || val == 0x1f1f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 card->amplifier_ctrl(card, -1);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003824 else { /* Mute off power on */
3825 if (card->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 card->amp_init(card);
3827 card->amplifier_ctrl(card, 1);
3828 }
3829 }
3830 }
3831}
3832
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833/* OSS /dev/mixer file operation methods */
3834
3835static int cs_open_mixdev(struct inode *inode, struct file *file)
3836{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003837 int i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003839 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 struct list_head *entry;
3841 unsigned int tmp;
3842
3843 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
3844 printk(KERN_INFO "cs46xx: cs_open_mixdev()+\n"));
3845
Jesper Juhl2eebb192006-06-23 02:05:26 -07003846 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 card = list_entry(entry, struct cs_card, list);
3848 for (i = 0; i < NR_AC97; i++)
3849 if (card->ac97_codec[i] != NULL &&
3850 card->ac97_codec[i]->dev_mixer == minor)
3851 goto match;
3852 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003853 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
3855 printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
3856 return -ENODEV;
3857 }
3858 match:
Jesper Juhl2eebb192006-06-23 02:05:26 -07003859 if (!card->ac97_codec[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 return -ENODEV;
3861 file->private_data = card->ac97_codec[i];
3862
3863 card->active_ctrl(card,1);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003864 if (!CS_IN_USE(&card->mixer_use_cnt)) {
3865 if ((tmp = cs46xx_powerup(card, CS_POWER_MIXVON))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003867 "cs46xx: cs_open_mixdev() powerup failure (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 return -EIO;
3869 }
3870 }
3871 card->amplifier_ctrl(card, 1);
3872 CS_INC_USE_COUNT(&card->mixer_use_cnt);
3873 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
3874 printk(KERN_INFO "cs46xx: cs_open_mixdev()- 0\n"));
3875 return nonseekable_open(inode, file);
3876}
3877
3878static int cs_release_mixdev(struct inode *inode, struct file *file)
3879{
3880 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003881 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 struct list_head *entry;
3883 int i;
3884 unsigned int tmp;
3885
3886 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
3887 printk(KERN_INFO "cs46xx: cs_release_mixdev()+\n"));
3888 list_for_each(entry, &cs46xx_devs)
3889 {
3890 card = list_entry(entry, struct cs_card, list);
3891 for (i = 0; i < NR_AC97; i++)
3892 if (card->ac97_codec[i] != NULL &&
3893 card->ac97_codec[i]->dev_mixer == minor)
3894 goto match;
3895 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003896 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
3898 printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
3899 return -ENODEV;
3900 }
3901match:
Jesper Juhl2eebb192006-06-23 02:05:26 -07003902 if (!CS_DEC_AND_TEST(&card->mixer_use_cnt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
3904 printk(KERN_INFO "cs46xx: cs_release_mixdev()- no powerdown, usecnt>0\n"));
3905 card->active_ctrl(card, -1);
3906 card->amplifier_ctrl(card, -1);
3907 return 0;
3908 }
3909/*
3910* ok, no outstanding mixer opens, so powerdown.
3911*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003912 if ((tmp = cs461x_powerdown(card, CS_POWER_MIXVON, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003914 "cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 card->active_ctrl(card, -1);
3916 card->amplifier_ctrl(card, -1);
3917 return -EIO;
3918 }
3919 card->active_ctrl(card, -1);
3920 card->amplifier_ctrl(card, -1);
3921 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
3922 printk(KERN_INFO "cs46xx: cs_release_mixdev()- 0\n"));
3923 return 0;
3924}
3925
3926static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
Jesper Juhl2eebb192006-06-23 02:05:26 -07003927 unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003929 struct ac97_codec *codec = file->private_data;
3930 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 struct list_head *entry;
3932 unsigned long __user *p = (long __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933#if CSDEBUG_INTERFACE
3934 int val;
3935
Jesper Juhl2eebb192006-06-23 02:05:26 -07003936 if ( (cmd == SOUND_MIXER_CS_GETDBGMASK) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 (cmd == SOUND_MIXER_CS_SETDBGMASK) ||
3938 (cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
3939 (cmd == SOUND_MIXER_CS_SETDBGLEVEL) ||
Jesper Juhl2eebb192006-06-23 02:05:26 -07003940 (cmd == SOUND_MIXER_CS_APM)) {
3941 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 case SOUND_MIXER_CS_GETDBGMASK:
3943 return put_user(cs_debugmask, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 case SOUND_MIXER_CS_GETDBGLEVEL:
3945 return put_user(cs_debuglevel, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946 case SOUND_MIXER_CS_SETDBGMASK:
3947 if (get_user(val, p))
3948 return -EFAULT;
3949 cs_debugmask = val;
3950 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 case SOUND_MIXER_CS_SETDBGLEVEL:
3952 if (get_user(val, p))
3953 return -EFAULT;
3954 cs_debuglevel = val;
3955 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 case SOUND_MIXER_CS_APM:
3957 if (get_user(val, p))
3958 return -EFAULT;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003959 if (val == CS_IOCTL_CMD_SUSPEND) {
3960 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 card = list_entry(entry, struct cs_card, list);
Pavel Machek2a569572005-07-07 17:56:40 -07003962 cs46xx_suspend(card, PMSG_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 }
3964
Jesper Juhl2eebb192006-06-23 02:05:26 -07003965 } else if (val == CS_IOCTL_CMD_RESUME) {
3966 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 card = list_entry(entry, struct cs_card, list);
3968 cs46xx_resume(card);
3969 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003970 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
3972 "cs46xx: mixer_ioctl(): invalid APM cmd (%d)\n",
3973 val));
3974 }
3975 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 default:
3977 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003978 "cs46xx: mixer_ioctl(): ERROR unknown debug cmd\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 return 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 }
3982#endif
3983 return codec->mixer_ioctl(codec, cmd, arg);
3984}
3985
3986static /*const*/ struct file_operations cs_mixer_fops = {
3987 CS_OWNER CS_THIS_MODULE
3988 .llseek = no_llseek,
3989 .ioctl = cs_ioctl_mixdev,
3990 .open = cs_open_mixdev,
3991 .release = cs_release_mixdev,
3992};
3993
3994/* AC97 codec initialisation. */
3995static int __init cs_ac97_init(struct cs_card *card)
3996{
3997 int num_ac97 = 0;
3998 int ready_2nd = 0;
3999 struct ac97_codec *codec;
4000 u16 eid;
4001
4002 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4003 "cs46xx: cs_ac97_init()+\n") );
4004
4005 for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
4006 if ((codec = ac97_alloc_codec()) == NULL)
4007 return -ENOMEM;
4008
4009 /* initialize some basic codec information, other fields will be filled
4010 in ac97_probe_codec */
4011 codec->private_data = card;
4012 codec->id = num_ac97;
4013
4014 codec->codec_read = cs_ac97_get;
4015 codec->codec_write = cs_ac97_set;
4016
Jesper Juhl2eebb192006-06-23 02:05:26 -07004017 if (ac97_probe_codec(codec) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4019 "cs46xx: cs_ac97_init()- codec number %d not found\n",
4020 num_ac97) );
4021 card->ac97_codec[num_ac97] = NULL;
4022 break;
4023 }
4024 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07004025 "cs46xx: cs_ac97_init() found codec %d\n",num_ac97));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026
4027 eid = cs_ac97_get(codec, AC97_EXTENDED_ID);
4028
Jesper Juhl2eebb192006-06-23 02:05:26 -07004029 if (eid == 0xFFFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 printk(KERN_WARNING "cs46xx: codec %d not present\n",num_ac97);
4031 ac97_release_codec(codec);
4032 break;
4033 }
4034
4035 card->ac97_features = eid;
4036
4037 if ((codec->dev_mixer = register_sound_mixer(&cs_mixer_fops, -1)) < 0) {
4038 printk(KERN_ERR "cs46xx: couldn't register mixer!\n");
4039 ac97_release_codec(codec);
4040 break;
4041 }
4042 card->ac97_codec[num_ac97] = codec;
4043
4044 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4045 "cs46xx: cs_ac97_init() ac97_codec[%d] set to %p\n",
4046 (unsigned int)num_ac97,
4047 codec));
4048 /* if there is no secondary codec at all, don't probe any more */
4049 if (!ready_2nd)
4050 {
4051 num_ac97 += 1;
4052 break;
4053 }
4054 }
4055 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4056 "cs46xx: cs_ac97_init()- %d\n", (unsigned int)num_ac97));
4057 return num_ac97;
4058}
4059
4060/*
4061 * load the static image into the DSP
4062 */
4063#include "cs461x_image.h"
4064static void cs461x_download_image(struct cs_card *card)
4065{
4066 unsigned i, j, temp1, temp2, offset, count;
4067 unsigned char __iomem *pBA1 = ioremap(card->ba1_addr, 0x40000);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004068 for (i = 0; i < CLEAR__COUNT; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 offset = ClrStat[i].BA1__DestByteOffset;
4070 count = ClrStat[i].BA1__SourceSize;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004071 for (temp1 = offset; temp1 < (offset + count); temp1 += 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 writel(0, pBA1+temp1);
4073 }
4074
Jesper Juhl2eebb192006-06-23 02:05:26 -07004075 for (i = 0; i < FILL__COUNT; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 temp2 = FillStat[i].Offset;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004077 for (j = 0; j < (FillStat[i].Size) / 4; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 temp1 = (FillStat[i]).pFill[j];
Jesper Juhl2eebb192006-06-23 02:05:26 -07004079 writel(temp1, pBA1+temp2 + j * 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 }
4081 }
4082 iounmap(pBA1);
4083}
4084
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085/*
4086 * Chip reset
4087 */
4088
4089static void cs461x_reset(struct cs_card *card)
4090{
4091 int idx;
4092
4093 /*
4094 * Write the reset bit of the SP control register.
4095 */
4096 cs461x_poke(card, BA1_SPCR, SPCR_RSTSP);
4097
4098 /*
4099 * Write the control register.
4100 */
4101 cs461x_poke(card, BA1_SPCR, SPCR_DRQEN);
4102
4103 /*
4104 * Clear the trap registers.
4105 */
4106 for (idx = 0; idx < 8; idx++) {
4107 cs461x_poke(card, BA1_DREG, DREG_REGID_TRAP_SELECT + idx);
4108 cs461x_poke(card, BA1_TWPR, 0xFFFF);
4109 }
4110 cs461x_poke(card, BA1_DREG, 0);
4111
4112 /*
4113 * Set the frame timer to reflect the number of cycles per frame.
4114 */
4115 cs461x_poke(card, BA1_FRMT, 0xadf);
4116}
4117
4118static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type)
4119{
4120 int idx, loop, startfifo=0, endfifo=0, powerdown1 = 0;
4121 unsigned int tmp;
4122
4123 /*
4124 * See if the devices are powered down. If so, we must power them up first
4125 * or they will not respond.
4126 */
4127 if (!((tmp = cs461x_peekBA0(card, BA0_CLKCR1)) & CLKCR1_SWCE)) {
4128 cs461x_pokeBA0(card, BA0_CLKCR1, tmp | CLKCR1_SWCE);
4129 powerdown1 = 1;
4130 }
4131
4132 /*
4133 * We want to clear out the serial port FIFOs so we don't end up playing
4134 * whatever random garbage happens to be in them. We fill the sample FIFOS
4135 * with zero (silence).
4136 */
4137 cs461x_pokeBA0(card, BA0_SERBWP, 0);
4138
4139 /*
4140 * Check for which FIFO locations to clear, if we are currently
4141 * playing or capturing then we don't want to put in 128 bytes of
4142 * "noise".
4143 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004144 if (type & CS_TYPE_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 startfifo = 128;
4146 endfifo = 256;
4147 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004148 if (type & CS_TYPE_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 startfifo = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004150 if (!endfifo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 endfifo = 128;
4152 }
4153 /*
4154 * Fill sample FIFO locations (256 locations total).
4155 */
4156 for (idx = startfifo; idx < endfifo; idx++) {
4157 /*
4158 * Make sure the previous FIFO write operation has completed.
4159 */
4160 for (loop = 0; loop < 5; loop++) {
4161 udelay(50);
4162 if (!(cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY))
4163 break;
4164 }
4165 if (cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY) {
4166 if (powerdown1)
4167 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
4168 }
4169 /*
4170 * Write the serial port FIFO index.
4171 */
4172 cs461x_pokeBA0(card, BA0_SERBAD, idx);
4173 /*
4174 * Tell the serial port to load the new value into the FIFO location.
4175 */
4176 cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC);
4177 }
4178 /*
4179 * Now, if we powered up the devices, then power them back down again.
4180 * This is kinda ugly, but should never happen.
4181 */
4182 if (powerdown1)
4183 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
4184}
4185
4186
4187static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag)
4188{
4189 int count;
4190 unsigned int tmp=0,muted=0;
4191
4192 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
4193 "cs46xx: cs461x_powerdown()+ type=0x%x\n",type));
Jesper Juhl2eebb192006-06-23 02:05:26 -07004194 if (!cs_powerdown && !suspendflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4196 "cs46xx: cs461x_powerdown() DISABLED exiting\n"));
4197 return 0;
4198 }
4199 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
4200 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4201 "cs46xx: cs461x_powerdown() powerdown reg=0x%x\n",tmp));
4202/*
4203* if powering down only the VREF, and not powering down the DAC/ADC,
4204* then do not power down the VREF, UNLESS both the DAC and ADC are not
4205* currently powered down. If powering down DAC and ADC, then
4206* it is possible to power down the VREF (ON).
4207*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07004208 if (((type & CS_POWER_MIXVON) &&
4209 (!(type & CS_POWER_ADC) || (!(type & CS_POWER_DAC))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 &&
4211 ((tmp & CS_AC97_POWER_CONTROL_ADC_ON) ||
Jesper Juhl2eebb192006-06-23 02:05:26 -07004212 (tmp & CS_AC97_POWER_CONTROL_DAC_ON))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4214 "cs46xx: cs461x_powerdown()- 0 unable to powerdown. tmp=0x%x\n",tmp));
4215 return 0;
4216 }
4217/*
4218* for now, always keep power to the mixer block.
4219* not sure why it's a problem but it seems to be if we power off.
4220*/
4221 type &= ~CS_POWER_MIXVON;
4222 type &= ~CS_POWER_MIXVOFF;
4223
4224 /*
4225 * Power down indicated areas.
4226 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004227 if (type & CS_POWER_MIXVOFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228
4229 CS_DBGOUT(CS_FUNCTION, 4,
4230 printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVOFF\n"));
4231 /*
4232 * Power down the MIXER (VREF ON) on the AC97 card.
4233 */
4234 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004235 if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON) {
4236 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004238 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 }
4240 tmp |= CS_AC97_POWER_CONTROL_MIXVOFF;
4241 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4242 /*
4243 * Now, we wait until we sample a ready state.
4244 */
4245 for (count = 0; count < 32; count++) {
4246 /*
4247 * First, lets wait a short while to let things settle out a
4248 * bit, and to prevent retrying the read too quickly.
4249 */
4250 udelay(500);
4251
4252 /*
4253 * Read the current state of the power control register.
4254 */
4255 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4256 CS_AC97_POWER_CONTROL_MIXVOFF_ON))
4257 break;
4258 }
4259
4260 /*
4261 * Check the status..
4262 */
4263 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004264 CS_AC97_POWER_CONTROL_MIXVOFF_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4266 "cs46xx: powerdown MIXVOFF failed\n"));
4267 return 1;
4268 }
4269 }
4270 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004271 if (type & CS_POWER_MIXVON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272
4273 CS_DBGOUT(CS_FUNCTION, 4,
4274 printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVON\n"));
4275 /*
4276 * Power down the MIXER (VREF ON) on the AC97 card.
4277 */
4278 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004279 if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON) {
4280 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004282 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 }
4284 tmp |= CS_AC97_POWER_CONTROL_MIXVON;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004285 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 /*
4287 * Now, we wait until we sample a ready state.
4288 */
4289 for (count = 0; count < 32; count++) {
4290 /*
4291 * First, lets wait a short while to let things settle out a
4292 * bit, and to prevent retrying the read too quickly.
4293 */
4294 udelay(500);
4295
4296 /*
4297 * Read the current state of the power control register.
4298 */
4299 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4300 CS_AC97_POWER_CONTROL_MIXVON_ON))
4301 break;
4302 }
4303
4304 /*
4305 * Check the status..
4306 */
4307 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004308 CS_AC97_POWER_CONTROL_MIXVON_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4310 "cs46xx: powerdown MIXVON failed\n"));
4311 return 1;
4312 }
4313 }
4314 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004315 if (type & CS_POWER_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 /*
4317 * Power down the ADC on the AC97 card.
4318 */
4319 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs461x_powerdown()+ ADC\n"));
4320 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004321 if (tmp & CS_AC97_POWER_CONTROL_ADC_ON) {
4322 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004324 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 }
4326 tmp |= CS_AC97_POWER_CONTROL_ADC;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004327 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328
4329 /*
4330 * Now, we wait until we sample a ready state.
4331 */
4332 for (count = 0; count < 32; count++) {
4333 /*
4334 * First, lets wait a short while to let things settle out a
4335 * bit, and to prevent retrying the read too quickly.
4336 */
4337 udelay(500);
4338
4339 /*
4340 * Read the current state of the power control register.
4341 */
4342 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4343 CS_AC97_POWER_CONTROL_ADC_ON))
4344 break;
4345 }
4346
4347 /*
4348 * Check the status..
4349 */
4350 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004351 CS_AC97_POWER_CONTROL_ADC_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4353 "cs46xx: powerdown ADC failed\n"));
4354 return 1;
4355 }
4356 }
4357 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004358 if (type & CS_POWER_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 /*
4360 * Power down the DAC on the AC97 card.
4361 */
4362
4363 CS_DBGOUT(CS_FUNCTION, 4,
4364 printk(KERN_INFO "cs46xx: cs461x_powerdown()+ DAC\n"));
4365 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004366 if (tmp & CS_AC97_POWER_CONTROL_DAC_ON) {
4367 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004369 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 }
4371 tmp |= CS_AC97_POWER_CONTROL_DAC;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004372 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 /*
4374 * Now, we wait until we sample a ready state.
4375 */
4376 for (count = 0; count < 32; count++) {
4377 /*
4378 * First, lets wait a short while to let things settle out a
4379 * bit, and to prevent retrying the read too quickly.
4380 */
4381 udelay(500);
4382
4383 /*
4384 * Read the current state of the power control register.
4385 */
4386 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4387 CS_AC97_POWER_CONTROL_DAC_ON))
4388 break;
4389 }
4390
4391 /*
4392 * Check the status..
4393 */
4394 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004395 CS_AC97_POWER_CONTROL_DAC_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4397 "cs46xx: powerdown DAC failed\n"));
4398 return 1;
4399 }
4400 }
4401 }
4402 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004403 if (muted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 cs_mute(card, CS_FALSE);
4405 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
4406 "cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp));
4407 return 0;
4408}
4409
4410static int cs46xx_powerup(struct cs_card *card, unsigned int type)
4411{
4412 int count;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004413 unsigned int tmp = 0, muted = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414
4415 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4416 "cs46xx: cs46xx_powerup()+ type=0x%x\n",type));
4417 /*
4418 * check for VREF and powerup if need to.
4419 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004420 if (type & CS_POWER_MIXVON)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 type |= CS_POWER_MIXVOFF;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004422 if (type & (CS_POWER_DAC | CS_POWER_ADC))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF;
4424
4425 /*
4426 * Power up indicated areas.
4427 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004428 if (type & CS_POWER_MIXVOFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429
4430 CS_DBGOUT(CS_FUNCTION, 4,
4431 printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVOFF\n"));
4432 /*
4433 * Power up the MIXER (VREF ON) on the AC97 card.
4434 */
4435 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004436 if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)) {
4437 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004439 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 }
4441 tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF;
4442 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4443 /*
4444 * Now, we wait until we sample a ready state.
4445 */
4446 for (count = 0; count < 32; count++) {
4447 /*
4448 * First, lets wait a short while to let things settle out a
4449 * bit, and to prevent retrying the read too quickly.
4450 */
4451 udelay(500);
4452
4453 /*
4454 * Read the current state of the power control register.
4455 */
4456 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4457 CS_AC97_POWER_CONTROL_MIXVOFF_ON)
4458 break;
4459 }
4460
4461 /*
4462 * Check the status..
4463 */
4464 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004465 CS_AC97_POWER_CONTROL_MIXVOFF_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4467 "cs46xx: powerup MIXVOFF failed\n"));
4468 return 1;
4469 }
4470 }
4471 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004472 if(type & CS_POWER_MIXVON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473
4474 CS_DBGOUT(CS_FUNCTION, 4,
4475 printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVON\n"));
4476 /*
4477 * Power up the MIXER (VREF ON) on the AC97 card.
4478 */
4479 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004480 if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)) {
4481 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004483 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 }
4485 tmp &= ~CS_AC97_POWER_CONTROL_MIXVON;
4486 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4487 /*
4488 * Now, we wait until we sample a ready state.
4489 */
4490 for (count = 0; count < 32; count++) {
4491 /*
4492 * First, lets wait a short while to let things settle out a
4493 * bit, and to prevent retrying the read too quickly.
4494 */
4495 udelay(500);
4496
4497 /*
4498 * Read the current state of the power control register.
4499 */
4500 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4501 CS_AC97_POWER_CONTROL_MIXVON_ON)
4502 break;
4503 }
4504
4505 /*
4506 * Check the status..
4507 */
4508 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004509 CS_AC97_POWER_CONTROL_MIXVON_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4511 "cs46xx: powerup MIXVON failed\n"));
4512 return 1;
4513 }
4514 }
4515 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004516 if (type & CS_POWER_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 /*
4518 * Power up the ADC on the AC97 card.
4519 */
4520 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs46xx_powerup()+ ADC\n"));
4521 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004522 if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON)) {
4523 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004525 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 }
4527 tmp &= ~CS_AC97_POWER_CONTROL_ADC;
4528 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4529
4530 /*
4531 * Now, we wait until we sample a ready state.
4532 */
4533 for (count = 0; count < 32; count++) {
4534 /*
4535 * First, lets wait a short while to let things settle out a
4536 * bit, and to prevent retrying the read too quickly.
4537 */
4538 udelay(500);
4539
4540 /*
4541 * Read the current state of the power control register.
4542 */
4543 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4544 CS_AC97_POWER_CONTROL_ADC_ON)
4545 break;
4546 }
4547
4548 /*
4549 * Check the status..
4550 */
4551 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004552 CS_AC97_POWER_CONTROL_ADC_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4554 "cs46xx: powerup ADC failed\n"));
4555 return 1;
4556 }
4557 }
4558 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004559 if (type & CS_POWER_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 /*
4561 * Power up the DAC on the AC97 card.
4562 */
4563
4564 CS_DBGOUT(CS_FUNCTION, 4,
4565 printk(KERN_INFO "cs46xx: cs46xx_powerup()+ DAC\n"));
4566 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004567 if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON)) {
4568 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004570 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 }
4572 tmp &= ~CS_AC97_POWER_CONTROL_DAC;
4573 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4574 /*
4575 * Now, we wait until we sample a ready state.
4576 */
4577 for (count = 0; count < 32; count++) {
4578 /*
4579 * First, lets wait a short while to let things settle out a
4580 * bit, and to prevent retrying the read too quickly.
4581 */
4582 udelay(500);
4583
4584 /*
4585 * Read the current state of the power control register.
4586 */
4587 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4588 CS_AC97_POWER_CONTROL_DAC_ON)
4589 break;
4590 }
4591
4592 /*
4593 * Check the status..
4594 */
4595 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004596 CS_AC97_POWER_CONTROL_DAC_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4598 "cs46xx: powerup DAC failed\n"));
4599 return 1;
4600 }
4601 }
4602 }
4603 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004604 if (muted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 cs_mute(card, CS_FALSE);
4606 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
4607 "cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp));
4608 return 0;
4609}
4610
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611static void cs461x_proc_start(struct cs_card *card)
4612{
4613 int cnt;
4614
4615 /*
4616 * Set the frame timer to reflect the number of cycles per frame.
4617 */
4618 cs461x_poke(card, BA1_FRMT, 0xadf);
4619 /*
4620 * Turn on the run, run at frame, and DMA enable bits in the local copy of
4621 * the SP control register.
4622 */
4623 cs461x_poke(card, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN);
4624 /*
4625 * Wait until the run at frame bit resets itself in the SP control
4626 * register.
4627 */
4628 for (cnt = 0; cnt < 25; cnt++) {
4629 udelay(50);
4630 if (!(cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR))
4631 break;
4632 }
4633
4634 if (cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR)
4635 printk(KERN_WARNING "cs46xx: SPCR_RUNFR never reset\n");
4636}
4637
4638static void cs461x_proc_stop(struct cs_card *card)
4639{
4640 /*
4641 * Turn off the run, run at frame, and DMA enable bits in the local copy of
4642 * the SP control register.
4643 */
4644 cs461x_poke(card, BA1_SPCR, 0);
4645}
4646
4647static int cs_hardware_init(struct cs_card *card)
4648{
4649 unsigned long end_time;
4650 unsigned int tmp,count;
4651
4652 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4653 "cs46xx: cs_hardware_init()+\n") );
4654 /*
4655 * First, blast the clock control register to zero so that the PLL starts
4656 * out in a known state, and blast the master serial port control register
4657 * to zero so that the serial ports also start out in a known state.
4658 */
4659 cs461x_pokeBA0(card, BA0_CLKCR1, 0);
4660 cs461x_pokeBA0(card, BA0_SERMC1, 0);
4661
4662 /*
4663 * If we are in AC97 mode, then we must set the part to a host controlled
4664 * AC-link. Otherwise, we won't be able to bring up the link.
4665 */
4666 cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_1_03); /* 1.03 card */
4667 /* cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_2_0); */ /* 2.00 card */
4668
4669 /*
4670 * Drive the ARST# pin low for a minimum of 1uS (as defined in the AC97
4671 * spec) and then drive it high. This is done for non AC97 modes since
4672 * there might be logic external to the CS461x that uses the ARST# line
4673 * for a reset.
4674 */
4675 cs461x_pokeBA0(card, BA0_ACCTL, 1);
4676 udelay(50);
4677 cs461x_pokeBA0(card, BA0_ACCTL, 0);
4678 udelay(50);
4679 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN);
4680
4681 /*
4682 * The first thing we do here is to enable sync generation. As soon
4683 * as we start receiving bit clock, we'll start producing the SYNC
4684 * signal.
4685 */
4686 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_ESYN | ACCTL_RSTN);
4687
4688 /*
4689 * Now wait for a short while to allow the AC97 part to start
4690 * generating bit clock (so we don't try to start the PLL without an
4691 * input clock).
4692 */
4693 mdelay(5 * cs_laptop_wait); /* 1 should be enough ?? (and pigs might fly) */
4694
4695 /*
4696 * Set the serial port timing configuration, so that
4697 * the clock control circuit gets its clock from the correct place.
4698 */
4699 cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97);
4700
4701 /*
4702 * The part seems to not be ready for a while after a resume.
4703 * so, if we are resuming, then wait for 700 mils. Note that 600 mils
4704 * is not enough for some platforms! tested on an IBM Thinkpads and
4705 * reference cards.
4706 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004707 if (!(card->pm.flags & CS46XX_PM_IDLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 mdelay(initdelay);
4709 /*
4710 * Write the selected clock control setup to the hardware. Do not turn on
4711 * SWCE yet (if requested), so that the devices clocked by the output of
4712 * PLL are not clocked until the PLL is stable.
4713 */
4714 cs461x_pokeBA0(card, BA0_PLLCC, PLLCC_LPF_1050_2780_KHZ | PLLCC_CDR_73_104_MHZ);
4715 cs461x_pokeBA0(card, BA0_PLLM, 0x3a);
4716 cs461x_pokeBA0(card, BA0_CLKCR2, CLKCR2_PDIVS_8);
4717
4718 /*
4719 * Power up the PLL.
4720 */
4721 cs461x_pokeBA0(card, BA0_CLKCR1, CLKCR1_PLLP);
4722
4723 /*
4724 * Wait until the PLL has stabilized.
4725 */
4726 mdelay(5 * cs_laptop_wait); /* Again 1 should be enough ?? */
4727
4728 /*
4729 * Turn on clocking of the core so that we can setup the serial ports.
4730 */
4731 tmp = cs461x_peekBA0(card, BA0_CLKCR1) | CLKCR1_SWCE;
4732 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
4733
4734 /*
4735 * Fill the serial port FIFOs with silence.
4736 */
4737 cs461x_clear_serial_FIFOs(card,CS_TYPE_DAC | CS_TYPE_ADC);
4738
4739 /*
4740 * Set the serial port FIFO pointer to the first sample in the FIFO.
4741 */
4742 /* cs461x_pokeBA0(card, BA0_SERBSP, 0); */
4743
4744 /*
4745 * Write the serial port configuration to the part. The master
4746 * enable bit is not set until all other values have been written.
4747 */
4748 cs461x_pokeBA0(card, BA0_SERC1, SERC1_SO1F_AC97 | SERC1_SO1EN);
4749 cs461x_pokeBA0(card, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN);
4750 cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
4751
4752
4753 mdelay(5 * cs_laptop_wait); /* Shouldnt be needed ?? */
4754
4755/*
4756* If we are resuming under 2.2.x then we can not schedule a timeout.
4757* so, just spin the CPU.
4758*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07004759 if (card->pm.flags & CS46XX_PM_IDLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 /*
4761 * Wait for the card ready signal from the AC97 card.
4762 */
4763 end_time = jiffies + 3 * (HZ >> 2);
4764 do {
4765 /*
4766 * Read the AC97 status register to see if we've seen a CODEC READY
4767 * signal from the AC97 card.
4768 */
4769 if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
4770 break;
4771 current->state = TASK_UNINTERRUPTIBLE;
4772 schedule_timeout(1);
4773 } while (time_before(jiffies, end_time));
Jesper Juhl2eebb192006-06-23 02:05:26 -07004774 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 for (count = 0; count < 100; count++) {
4776 // First, we want to wait for a short time.
4777 udelay(25 * cs_laptop_wait);
4778
4779 if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
4780 break;
4781 }
4782 }
4783
4784 /*
4785 * Make sure CODEC is READY.
4786 */
4787 if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)) {
4788 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
4789 "cs46xx: create - never read card ready from AC'97\n"));
4790 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
4791 "cs46xx: probably not a bug, try using the CS4232 driver,\n"));
4792 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
4793 "cs46xx: or turn off any automatic Power Management support in the BIOS.\n"));
4794 return -EIO;
4795 }
4796
4797 /*
4798 * Assert the vaid frame signal so that we can start sending commands
4799 * to the AC97 card.
4800 */
4801 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
4802
Jesper Juhl2eebb192006-06-23 02:05:26 -07004803 if (card->pm.flags & CS46XX_PM_IDLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 /*
4805 * Wait until we've sampled input slots 3 and 4 as valid, meaning that
4806 * the card is pumping ADC data across the AC-link.
4807 */
4808 end_time = jiffies + 3 * (HZ >> 2);
4809 do {
4810 /*
4811 * Read the input slot valid register and see if input slots 3 and
4812 * 4 are valid yet.
4813 */
4814 if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
4815 break;
4816 current->state = TASK_UNINTERRUPTIBLE;
4817 schedule_timeout(1);
4818 } while (time_before(jiffies, end_time));
Jesper Juhl2eebb192006-06-23 02:05:26 -07004819 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 for (count = 0; count < 100; count++) {
4821 // First, we want to wait for a short time.
4822 udelay(25 * cs_laptop_wait);
4823
4824 if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
4825 break;
4826 }
4827 }
4828 /*
4829 * Make sure input slots 3 and 4 are valid. If not, then return
4830 * an error.
4831 */
4832 if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) != (ACISV_ISV3 | ACISV_ISV4)) {
4833 printk(KERN_WARNING "cs46xx: create - never read ISV3 & ISV4 from AC'97\n");
4834 return -EIO;
4835 }
4836
4837 /*
4838 * Now, assert valid frame and the slot 3 and 4 valid bits. This will
4839 * commense the transfer of digital audio data to the AC97 card.
4840 */
4841 cs461x_pokeBA0(card, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4);
4842
4843 /*
4844 * Turn off the Processor by turning off the software clock enable flag in
4845 * the clock control register.
4846 */
4847 /* tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE; */
4848 /* cs461x_pokeBA0(card, BA0_CLKCR1, tmp); */
4849
4850 /*
4851 * Reset the processor.
4852 */
4853 cs461x_reset(card);
4854
4855 /*
4856 * Download the image to the processor.
4857 */
4858
4859 cs461x_download_image(card);
4860
4861 /*
4862 * Stop playback DMA.
4863 */
4864 tmp = cs461x_peek(card, BA1_PCTL);
4865 card->pctl = tmp & 0xffff0000;
4866 cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
4867
4868 /*
4869 * Stop capture DMA.
4870 */
4871 tmp = cs461x_peek(card, BA1_CCTL);
4872 card->cctl = tmp & 0x0000ffff;
4873 cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
4874
4875 /* initialize AC97 codec and register /dev/mixer */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004876 if (card->pm.flags & CS46XX_PM_IDLE) {
4877 if (cs_ac97_init(card) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07004879 "cs46xx: cs_ac97_init() failure\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 return -EIO;
4881 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004882 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 cs46xx_ac97_resume(card);
4884 }
4885
4886 cs461x_proc_start(card);
4887
4888 /*
4889 * Enable interrupts on the part.
4890 */
4891 cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM);
4892
4893 tmp = cs461x_peek(card, BA1_PFIE);
4894 tmp &= ~0x0000f03f;
4895 cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt enable */
4896
4897 tmp = cs461x_peek(card, BA1_CIE);
4898 tmp &= ~0x0000003f;
4899 tmp |= 0x00000001;
4900 cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt enable */
4901
4902 /*
4903 * If IDLE then Power down the part. We will power components up
4904 * when we need them.
4905 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004906 if (card->pm.flags & CS46XX_PM_IDLE) {
4907 if (!cs_powerdown) {
4908 if ((tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC |
4909 CS_POWER_MIXVON))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
4911 "cs46xx: cs461x_powerup() failure (0x%x)\n",tmp) );
4912 return -EIO;
4913 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004914 } else {
4915 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
4916 CS_POWER_MIXVON, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
4918 "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
4919 return -EIO;
4920 }
4921 }
4922 }
4923 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4924 "cs46xx: cs_hardware_init()- 0\n"));
4925 return 0;
4926}
4927
4928/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered
4929 until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
4930
4931/*
4932 * Card subid table
4933 */
4934
4935struct cs_card_type
4936{
4937 u16 vendor;
4938 u16 id;
4939 char *name;
4940 void (*amp)(struct cs_card *, int);
4941 void (*amp_init)(struct cs_card *);
4942 void (*active)(struct cs_card *, int);
4943};
4944
4945static struct cs_card_type cards[] = {
4946 {
4947 .vendor = 0x1489,
4948 .id = 0x7001,
4949 .name = "Genius Soundmaker 128 value",
4950 .amp = amp_none,
4951 },
4952 {
4953 .vendor = 0x5053,
4954 .id = 0x3357,
4955 .name = "Voyetra",
4956 .amp = amp_voyetra,
4957 },
4958 {
4959 .vendor = 0x1071,
4960 .id = 0x6003,
4961 .name = "Mitac MI6020/21",
4962 .amp = amp_voyetra,
4963 },
4964 {
4965 .vendor = 0x14AF,
4966 .id = 0x0050,
4967 .name = "Hercules Game Theatre XP",
4968 .amp = amp_hercules,
4969 },
4970 {
4971 .vendor = 0x1681,
4972 .id = 0x0050,
4973 .name = "Hercules Game Theatre XP",
4974 .amp = amp_hercules,
4975 },
4976 {
4977 .vendor = 0x1681,
4978 .id = 0x0051,
4979 .name = "Hercules Game Theatre XP",
4980 .amp = amp_hercules,
4981 },
4982 {
4983 .vendor = 0x1681,
4984 .id = 0x0052,
4985 .name = "Hercules Game Theatre XP",
4986 .amp = amp_hercules,
4987 },
4988 {
4989 .vendor = 0x1681,
4990 .id = 0x0053,
4991 .name = "Hercules Game Theatre XP",
4992 .amp = amp_hercules,
4993 },
4994 {
4995 .vendor = 0x1681,
4996 .id = 0x0054,
4997 .name = "Hercules Game Theatre XP",
4998 .amp = amp_hercules,
4999 },
5000 {
5001 .vendor = 0x1681,
5002 .id = 0xa010,
5003 .name = "Hercules Fortissimo II",
5004 .amp = amp_none,
5005 },
5006 /* Not sure if the 570 needs the clkrun hack */
5007 {
5008 .vendor = PCI_VENDOR_ID_IBM,
5009 .id = 0x0132,
5010 .name = "Thinkpad 570",
5011 .amp = amp_none,
5012 .active = clkrun_hack,
5013 },
5014 {
5015 .vendor = PCI_VENDOR_ID_IBM,
5016 .id = 0x0153,
5017 .name = "Thinkpad 600X/A20/T20",
5018 .amp = amp_none,
5019 .active = clkrun_hack,
5020 },
5021 {
5022 .vendor = PCI_VENDOR_ID_IBM,
5023 .id = 0x1010,
5024 .name = "Thinkpad 600E (unsupported)",
5025 },
5026 {
5027 .name = "Card without SSID set",
5028 },
5029 { 0, },
5030};
5031
5032MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <pcaudio@crystal.cirrus.com>");
5033MODULE_DESCRIPTION("Crystal SoundFusion Audio Support");
5034MODULE_LICENSE("GPL");
5035
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036static const char cs46xx_banner[] = KERN_INFO "Crystal 4280/46xx + AC97 Audio, version " CS46XX_MAJOR_VERSION "." CS46XX_MINOR_VERSION "." CS46XX_ARCH ", " __TIME__ " " __DATE__ "\n";
5037static const char fndmsg[] = KERN_INFO "cs46xx: Found %d audio device(s).\n";
5038
5039static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
5040 const struct pci_device_id *pciid)
5041{
Jesper Juhl2eebb192006-06-23 02:05:26 -07005042 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 u16 ss_card, ss_vendor;
5044 struct cs_card *card;
5045 dma_addr_t dma_mask;
5046 struct cs_card_type *cp = &cards[0];
5047
5048 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
5049 printk(KERN_INFO "cs46xx: probe()+\n"));
5050
5051 dma_mask = 0xffffffff; /* this enables playback and recording */
5052 if (pci_enable_device(pci_dev)) {
5053 CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
5054 "cs46xx: pci_enable_device() failed\n"));
5055 return -1;
5056 }
5057 if (!RSRCISMEMORYREGION(pci_dev, 0) ||
5058 !RSRCISMEMORYREGION(pci_dev, 1)) {
5059 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
5060 "cs46xx: probe()- Memory region not assigned\n"));
5061 return -1;
5062 }
5063 if (pci_dev->irq == 0) {
5064 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
5065 "cs46xx: probe() IRQ not assigned\n"));
5066 return -1;
5067 }
5068 if (!pci_dma_supported(pci_dev, 0xffffffff)) {
5069 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
5070 "cs46xx: probe() architecture does not support 32bit PCI busmaster DMA\n"));
5071 return -1;
5072 }
5073 pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
5074 pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card);
5075
5076 if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) {
5077 printk(KERN_ERR "cs46xx: out of memory\n");
5078 return -ENOMEM;
5079 }
5080 memset(card, 0, sizeof(*card));
5081 card->ba0_addr = RSRCADDRESS(pci_dev, 0);
5082 card->ba1_addr = RSRCADDRESS(pci_dev, 1);
5083 card->pci_dev = pci_dev;
5084 card->irq = pci_dev->irq;
5085 card->magic = CS_CARD_MAGIC;
5086 spin_lock_init(&card->lock);
5087 spin_lock_init(&card->ac97_lock);
5088
5089 pci_set_master(pci_dev);
5090
5091 printk(cs46xx_banner);
5092 printk(KERN_INFO "cs46xx: Card found at 0x%08lx and 0x%08lx, IRQ %d\n",
5093 card->ba0_addr, card->ba1_addr, card->irq);
5094
5095 card->alloc_pcm_channel = cs_alloc_pcm_channel;
5096 card->alloc_rec_pcm_channel = cs_alloc_rec_pcm_channel;
5097 card->free_pcm_channel = cs_free_pcm_channel;
5098 card->amplifier_ctrl = amp_none;
5099 card->active_ctrl = amp_none;
5100
5101 while (cp->name)
5102 {
Jesper Juhl2eebb192006-06-23 02:05:26 -07005103 if (cp->vendor == ss_vendor && cp->id == ss_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 card->amplifier_ctrl = cp->amp;
Jesper Juhl2eebb192006-06-23 02:05:26 -07005105 if (cp->active)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 card->active_ctrl = cp->active;
Jesper Juhl2eebb192006-06-23 02:05:26 -07005107 if (cp->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 card->amp_init = cp->amp_init;
5109 break;
5110 }
5111 cp++;
5112 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005113 if (cp->name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 printk(KERN_INFO "cs46xx: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
5115 ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005116 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 printk(KERN_INFO "cs46xx: %s (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
5118 cp->name, ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
5119 }
5120
Jesper Juhl2eebb192006-06-23 02:05:26 -07005121 if (card->amplifier_ctrl == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 card->amplifier_ctrl = amp_none;
5123 card->active_ctrl = clkrun_hack;
5124 }
5125
Jesper Juhl2eebb192006-06-23 02:05:26 -07005126 if (external_amp == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 printk(KERN_INFO "cs46xx: Crystal EAPD support forced on.\n");
5128 card->amplifier_ctrl = amp_voyetra;
5129 }
5130
Jesper Juhl2eebb192006-06-23 02:05:26 -07005131 if (thinkpad == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n");
5133 card->active_ctrl = clkrun_hack;
5134 }
5135/*
5136* The thinkpads don't work well without runtime updating on their kernel
5137* delay values (or any laptop with variable CPU speeds really).
5138* so, just to be safe set the init delay to 2100. Eliminates
5139* failures on T21 Thinkpads. remove this code when the udelay
5140* and mdelay kernel code is replaced by a pm timer, or the delays
5141* work well for battery and/or AC power both.
5142*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07005143 if (card->active_ctrl == clkrun_hack) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 initdelay = 2100;
5145 cs_laptop_wait = 5;
5146 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005147 if ((card->active_ctrl == clkrun_hack) && !(powerdown == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148/*
5149* for some currently unknown reason, powering down the DAC and ADC component
5150* blocks on thinkpads causes some funky behavior... distoorrrtion and ac97
5151* codec access problems. probably the serial clock becomes unsynced.
5152* added code to sync the chips back up, but only helped about 70% the time.
5153*/
5154 cs_powerdown = 0;
5155 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005156 if (powerdown == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 cs_powerdown = 0;
5158 card->active_ctrl(card, 1);
5159
5160 /* claim our iospace and irq */
5161
5162 card->ba0 = ioremap_nocache(card->ba0_addr, CS461X_BA0_SIZE);
5163 card->ba1.name.data0 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
5164 card->ba1.name.data1 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
5165 card->ba1.name.pmem = ioremap_nocache(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
5166 card->ba1.name.reg = ioremap_nocache(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
5167
5168 CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO
5169 "cs46xx: card=%p card->ba0=%p\n",card,card->ba0) );
5170 CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO
5171 "cs46xx: card->ba1=%p %p %p %p\n",
5172 card->ba1.name.data0,
5173 card->ba1.name.data1,
5174 card->ba1.name.pmem,
5175 card->ba1.name.reg) );
5176
Jesper Juhl2eebb192006-06-23 02:05:26 -07005177 if (card->ba0 == 0 || card->ba1.name.data0 == 0 ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 card->ba1.name.data1 == 0 || card->ba1.name.pmem == 0 ||
5179 card->ba1.name.reg == 0)
5180 goto fail2;
5181
Thomas Gleixner65ca68b2006-07-01 19:29:46 -07005182 if (request_irq(card->irq, &cs_interrupt, IRQF_SHARED, "cs46xx", card)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 printk(KERN_ERR "cs46xx: unable to allocate irq %d\n", card->irq);
5184 goto fail2;
5185 }
5186 /* register /dev/dsp */
5187 if ((card->dev_audio = register_sound_dsp(&cs461x_fops, -1)) < 0) {
5188 printk(KERN_ERR "cs46xx: unable to register dsp\n");
5189 goto fail;
5190 }
5191
5192 /* register /dev/midi */
Jesper Juhl2eebb192006-06-23 02:05:26 -07005193 if ((card->dev_midi = register_sound_midi(&cs_midi_fops, -1)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 printk(KERN_ERR "cs46xx: unable to register midi\n");
5195
5196 card->pm.flags |= CS46XX_PM_IDLE;
Jesper Juhl2eebb192006-06-23 02:05:26 -07005197 for (i = 0; i < 5; i++) {
5198 if (cs_hardware_init(card) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 CS_DBGOUT(CS_ERROR, 4, printk(
5200 "cs46xx: ERROR in cs_hardware_init()... retrying\n"));
5201 for (j = 0; j < NR_AC97; j++)
5202 if (card->ac97_codec[j] != NULL) {
5203 unregister_sound_mixer(card->ac97_codec[j]->dev_mixer);
5204 ac97_release_codec(card->ac97_codec[j]);
5205 }
5206 mdelay(10 * cs_laptop_wait);
5207 continue;
5208 }
5209 break;
5210 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005211 if(i >= 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
5213 "cs46xx: cs46xx_probe()- cs_hardware_init() failed, retried %d times.\n",i));
5214 unregister_sound_dsp(card->dev_audio);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005215 if (card->dev_midi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 unregister_sound_midi(card->dev_midi);
5217 goto fail;
5218 }
5219
5220 init_waitqueue_head(&card->midi.open_wait);
Ingo Molnar910f5d22006-03-23 03:00:39 -08005221 mutex_init(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 init_waitqueue_head(&card->midi.iwait);
5223 init_waitqueue_head(&card->midi.owait);
5224 cs461x_pokeBA0(card, BA0_MIDCR, MIDCR_MRST);
5225 cs461x_pokeBA0(card, BA0_MIDCR, 0);
5226
5227 /*
5228 * Check if we have to init the amplifier, but probably already done
5229 * since the CD logic in the ac97 init code will turn on the ext amp.
5230 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07005231 if (cp->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 cp->amp_init(card);
5233 card->active_ctrl(card, -1);
5234
5235 PCI_SET_DRIVER_DATA(pci_dev, card);
5236 PCI_SET_DMA_MASK(pci_dev, dma_mask);
5237 list_add(&card->list, &cs46xx_devs);
5238
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 CS_DBGOUT(CS_PM, 9, printk(KERN_INFO "cs46xx: pm.flags=0x%x card=%p\n",
5240 (unsigned)card->pm.flags,card));
5241
5242 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5243 "cs46xx: probe()- device allocated successfully\n"));
5244 return 0;
5245
5246fail:
5247 free_irq(card->irq, card);
5248fail2:
Jesper Juhl2eebb192006-06-23 02:05:26 -07005249 if (card->ba0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 iounmap(card->ba0);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005251 if (card->ba1.name.data0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 iounmap(card->ba1.name.data0);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005253 if (card->ba1.name.data1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 iounmap(card->ba1.name.data1);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005255 if (card->ba1.name.pmem)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 iounmap(card->ba1.name.pmem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005257 if (card->ba1.name.reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258 iounmap(card->ba1.name.reg);
5259 kfree(card);
5260 CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
5261 "cs46xx: probe()- no device allocated\n"));
5262 return -ENODEV;
5263} // probe_cs46xx
5264
5265// ---------------------------------------------------------------------
5266
5267static void __devexit cs46xx_remove(struct pci_dev *pci_dev)
5268{
5269 struct cs_card *card = PCI_GET_DRIVER_DATA(pci_dev);
5270 int i;
5271 unsigned int tmp;
5272
5273 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5274 "cs46xx: cs46xx_remove()+\n"));
5275
5276 card->active_ctrl(card,1);
5277
5278 tmp = cs461x_peek(card, BA1_PFIE);
5279 tmp &= ~0x0000f03f;
5280 tmp |= 0x00000010;
5281 cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */
5282
5283 tmp = cs461x_peek(card, BA1_CIE);
5284 tmp &= ~0x0000003f;
5285 tmp |= 0x00000011;
5286 cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */
5287
5288 /*
5289 * Stop playback DMA.
5290 */
5291 tmp = cs461x_peek(card, BA1_PCTL);
5292 cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
5293
5294 /*
5295 * Stop capture DMA.
5296 */
5297 tmp = cs461x_peek(card, BA1_CCTL);
5298 cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
5299
5300 /*
5301 * Reset the processor.
5302 */
5303 cs461x_reset(card);
5304
5305 cs461x_proc_stop(card);
5306
5307 /*
5308 * Power down the DAC and ADC. We will power them up (if) when we need
5309 * them.
5310 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07005311 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
5312 CS_POWER_MIXVON, CS_TRUE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
5314 "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
5315 }
5316
5317 /*
5318 * Power down the PLL.
5319 */
5320 cs461x_pokeBA0(card, BA0_CLKCR1, 0);
5321
5322 /*
5323 * Turn off the Processor by turning off the software clock enable flag in
5324 * the clock control register.
5325 */
5326 tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE;
5327 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
5328
5329 card->active_ctrl(card,-1);
5330
5331 /* free hardware resources */
5332 free_irq(card->irq, card);
5333 iounmap(card->ba0);
5334 iounmap(card->ba1.name.data0);
5335 iounmap(card->ba1.name.data1);
5336 iounmap(card->ba1.name.pmem);
5337 iounmap(card->ba1.name.reg);
5338
5339 /* unregister audio devices */
5340 for (i = 0; i < NR_AC97; i++)
5341 if (card->ac97_codec[i] != NULL) {
5342 unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
5343 ac97_release_codec(card->ac97_codec[i]);
5344 }
5345 unregister_sound_dsp(card->dev_audio);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005346 if (card->dev_midi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 unregister_sound_midi(card->dev_midi);
5348 list_del(&card->list);
5349 kfree(card);
5350 PCI_SET_DRIVER_DATA(pci_dev,NULL);
5351
5352 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5353 "cs46xx: cs46xx_remove()-: remove successful\n"));
5354}
5355
5356enum {
5357 CS46XX_4610 = 0,
5358 CS46XX_4612, /* same as 4630 */
5359 CS46XX_4615, /* same as 4624 */
5360};
5361
5362static struct pci_device_id cs46xx_pci_tbl[] = {
5363 {
5364 .vendor = PCI_VENDOR_ID_CIRRUS,
5365 .device = PCI_DEVICE_ID_CIRRUS_4610,
5366 .subvendor = PCI_ANY_ID,
5367 .subdevice = PCI_ANY_ID,
5368 .driver_data = CS46XX_4610,
5369 },
5370 {
5371 .vendor = PCI_VENDOR_ID_CIRRUS,
5372 .device = PCI_DEVICE_ID_CIRRUS_4612,
5373 .subvendor = PCI_ANY_ID,
5374 .subdevice = PCI_ANY_ID,
5375 .driver_data = CS46XX_4612,
5376 },
5377 {
5378 .vendor = PCI_VENDOR_ID_CIRRUS,
5379 .device = PCI_DEVICE_ID_CIRRUS_4615,
5380 .subvendor = PCI_ANY_ID,
5381 .subdevice = PCI_ANY_ID,
5382 .driver_data = CS46XX_4615,
5383 },
5384 { 0, },
5385};
5386
5387MODULE_DEVICE_TABLE(pci, cs46xx_pci_tbl);
5388
5389static struct pci_driver cs46xx_pci_driver = {
5390 .name = "cs46xx",
5391 .id_table = cs46xx_pci_tbl,
5392 .probe = cs46xx_probe,
5393 .remove = __devexit_p(cs46xx_remove),
Alexey Dobriyan99f932f2006-09-29 02:00:18 -07005394#ifdef CONFIG_PM
5395 .suspend = cs46xx_suspend_tbl,
5396 .resume = cs46xx_resume_tbl,
5397#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398};
5399
5400static int __init cs46xx_init_module(void)
5401{
5402 int rtn = 0;
5403 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5404 "cs46xx: cs46xx_init_module()+ \n"));
Greg Kroah-Hartman46654722005-12-06 15:33:15 -08005405 rtn = pci_register_driver(&cs46xx_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406
Jesper Juhl2eebb192006-06-23 02:05:26 -07005407 if (rtn == -ENODEV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(
5409 "cs46xx: Unable to detect valid cs46xx device\n"));
5410 }
5411
5412 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
5413 printk(KERN_INFO "cs46xx: cs46xx_init_module()- (%d)\n",rtn));
5414 return rtn;
5415}
5416
5417static void __exit cs46xx_cleanup_module(void)
5418{
5419 pci_unregister_driver(&cs46xx_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
5421 printk(KERN_INFO "cs46xx: cleanup_cs46xx() finished\n"));
5422}
5423
5424module_init(cs46xx_init_module);
5425module_exit(cs46xx_cleanup_module);
5426
Alexey Dobriyan99f932f2006-09-29 02:00:18 -07005427#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state)
5429{
5430 struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
5431 CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
5432 printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
Pavel Machek2a569572005-07-07 17:56:40 -07005433 cs46xx_suspend(s, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 return 0;
5435}
5436
5437static int cs46xx_resume_tbl(struct pci_dev *pcidev)
5438{
5439 struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
5440 CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
5441 printk(KERN_INFO "cs46xx: cs46xx_resume_tbl request\n"));
5442 cs46xx_resume(s);
5443 return 0;
5444}
5445#endif