blob: 5195bf933cb893dffb481ae646329cc11ce9a46c [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
99#include "cs46xxpm-24.h"
100#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);
392static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state);
393static int cs46xx_resume_tbl(struct pci_dev *pcidev);
394
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395#if CSDEBUG
396
397/* DEBUG ROUTINES */
398
399#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int)
400#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int)
401#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int)
402#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int)
403#define SOUND_MIXER_CS_APM _SIOWR('M',124, int)
404
405static void printioctl(unsigned int x)
406{
407 unsigned int i;
408 unsigned char vidx;
409 /* these values are incorrect for the ac97 driver, fix.
410 * Index of mixtable1[] member is Device ID
411 * and must be <= SOUND_MIXER_NRDEVICES.
412 * Value of array member is index into s->mix.vol[]
413 */
414 static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
415 [SOUND_MIXER_PCM] = 1, /* voice */
416 [SOUND_MIXER_LINE1] = 2, /* AUX */
417 [SOUND_MIXER_CD] = 3, /* CD */
418 [SOUND_MIXER_LINE] = 4, /* Line */
419 [SOUND_MIXER_SYNTH] = 5, /* FM */
420 [SOUND_MIXER_MIC] = 6, /* Mic */
421 [SOUND_MIXER_SPEAKER] = 7, /* Speaker */
422 [SOUND_MIXER_RECLEV] = 8, /* Recording level */
423 [SOUND_MIXER_VOLUME] = 9 /* Master Volume */
424 };
425
Jesper Juhl2eebb192006-06-23 02:05:26 -0700426 switch (x) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 case SOUND_MIXER_CS_GETDBGMASK:
428 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGMASK: ") );
429 break;
430 case SOUND_MIXER_CS_GETDBGLEVEL:
431 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGLEVEL: ") );
432 break;
433 case SOUND_MIXER_CS_SETDBGMASK:
434 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGMASK: ") );
435 break;
436 case SOUND_MIXER_CS_SETDBGLEVEL:
437 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGLEVEL: ") );
438 break;
439 case OSS_GETVERSION:
440 CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION: ") );
441 break;
442 case SNDCTL_DSP_SYNC:
443 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC: ") );
444 break;
445 case SNDCTL_DSP_SETDUPLEX:
446 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX: ") );
447 break;
448 case SNDCTL_DSP_GETCAPS:
449 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS: ") );
450 break;
451 case SNDCTL_DSP_RESET:
452 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET: ") );
453 break;
454 case SNDCTL_DSP_SPEED:
455 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED: ") );
456 break;
457 case SNDCTL_DSP_STEREO:
458 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO: ") );
459 break;
460 case SNDCTL_DSP_CHANNELS:
461 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS: ") );
462 break;
463 case SNDCTL_DSP_GETFMTS:
464 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS: ") );
465 break;
466 case SNDCTL_DSP_SETFMT:
467 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT: ") );
468 break;
469 case SNDCTL_DSP_POST:
470 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST: ") );
471 break;
472 case SNDCTL_DSP_GETTRIGGER:
473 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER: ") );
474 break;
475 case SNDCTL_DSP_SETTRIGGER:
476 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER: ") );
477 break;
478 case SNDCTL_DSP_GETOSPACE:
479 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE: ") );
480 break;
481 case SNDCTL_DSP_GETISPACE:
482 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE: ") );
483 break;
484 case SNDCTL_DSP_NONBLOCK:
485 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK: ") );
486 break;
487 case SNDCTL_DSP_GETODELAY:
488 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY: ") );
489 break;
490 case SNDCTL_DSP_GETIPTR:
491 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR: ") );
492 break;
493 case SNDCTL_DSP_GETOPTR:
494 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR: ") );
495 break;
496 case SNDCTL_DSP_GETBLKSIZE:
497 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE: ") );
498 break;
499 case SNDCTL_DSP_SETFRAGMENT:
500 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFRAGMENT: ") );
501 break;
502 case SNDCTL_DSP_SUBDIVIDE:
503 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE: ") );
504 break;
505 case SOUND_PCM_READ_RATE:
506 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE: ") );
507 break;
508 case SOUND_PCM_READ_CHANNELS:
509 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_CHANNELS: ") );
510 break;
511 case SOUND_PCM_READ_BITS:
512 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS: ") );
513 break;
514 case SOUND_PCM_WRITE_FILTER:
515 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_WRITE_FILTER: ") );
516 break;
517 case SNDCTL_DSP_SETSYNCRO:
518 CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO: ") );
519 break;
520 case SOUND_PCM_READ_FILTER:
521 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER: ") );
522 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 case SOUND_MIXER_PRIVATE1:
524 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1: ") );
525 break;
526 case SOUND_MIXER_PRIVATE2:
527 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2: ") );
528 break;
529 case SOUND_MIXER_PRIVATE3:
530 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3: ") );
531 break;
532 case SOUND_MIXER_PRIVATE4:
533 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4: ") );
534 break;
535 case SOUND_MIXER_PRIVATE5:
536 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5: ") );
537 break;
538 case SOUND_MIXER_INFO:
539 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO: ") );
540 break;
541 case SOUND_OLD_MIXER_INFO:
542 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO: ") );
543 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 default:
Jesper Juhl2eebb192006-06-23 02:05:26 -0700545 switch (_IOC_NR(x)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 case SOUND_MIXER_VOLUME:
547 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_VOLUME: ") );
548 break;
549 case SOUND_MIXER_SPEAKER:
550 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SPEAKER: ") );
551 break;
552 case SOUND_MIXER_RECLEV:
553 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECLEV: ") );
554 break;
555 case SOUND_MIXER_MIC:
556 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_MIC: ") );
557 break;
558 case SOUND_MIXER_SYNTH:
559 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SYNTH: ") );
560 break;
561 case SOUND_MIXER_RECSRC:
562 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECSRC: ") );
563 break;
564 case SOUND_MIXER_DEVMASK:
565 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_DEVMASK: ") );
566 break;
567 case SOUND_MIXER_RECMASK:
568 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECMASK: ") );
569 break;
570 case SOUND_MIXER_STEREODEVS:
571 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_STEREODEVS: ") );
572 break;
573 case SOUND_MIXER_CAPS:
574 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:") );
575 break;
576 default:
577 i = _IOC_NR(x);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700578 if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 CS_DBGOUT(CS_IOCTL, 4, printk("UNKNOWN IOCTL: 0x%.8x NR=%d ",x,i) );
Jesper Juhl2eebb192006-06-23 02:05:26 -0700580 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d ",
Jesper Juhl2eebb192006-06-23 02:05:26 -0700582 x,i));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 }
584 break;
585 }
586 }
587 CS_DBGOUT(CS_IOCTL, 4, printk("command = 0x%x IOC_NR=%d\n",x, _IOC_NR(x)) );
588}
589#endif
590
591/*
592 * common I/O routines
593 */
594
595static void cs461x_poke(struct cs_card *codec, unsigned long reg, unsigned int val)
596{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700597 writel(val, codec->ba1.idx[(reg >> 16) & 3] + (reg & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598}
599
600static unsigned int cs461x_peek(struct cs_card *codec, unsigned long reg)
601{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700602 return readl(codec->ba1.idx[(reg >> 16) & 3] + (reg & 0xffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603}
604
605static void cs461x_pokeBA0(struct cs_card *codec, unsigned long reg, unsigned int val)
606{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700607 writel(val, codec->ba0 + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608}
609
610static unsigned int cs461x_peekBA0(struct cs_card *codec, unsigned long reg)
611{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700612 return readl(codec->ba0 + reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613}
614
615
616static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg);
617static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
618
619static struct cs_channel *cs_alloc_pcm_channel(struct cs_card *card)
620{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700621 if (card->channel[1].used == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 return NULL;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700623 card->channel[1].used = 1;
624 card->channel[1].num = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 return &card->channel[1];
626}
627
628static struct cs_channel *cs_alloc_rec_pcm_channel(struct cs_card *card)
629{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700630 if (card->channel[0].used == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 return NULL;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700632 card->channel[0].used = 1;
633 card->channel[0].num = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 return &card->channel[0];
635}
636
637static void cs_free_pcm_channel(struct cs_card *card, int channel)
638{
639 card->channel[channel].state = NULL;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700640 card->channel[channel].used = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641}
642
643/*
644 * setup a divisor value to help with conversion from
645 * 16bit Stereo, down to 8bit stereo/mono or 16bit mono.
646 * assign a divisor of 1 if using 16bit Stereo as that is
647 * the only format that the static image will capture.
648 */
649static void cs_set_divisor(struct dmabuf *dmabuf)
650{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700651 if (dmabuf->type == CS_TYPE_DAC)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 dmabuf->divisor = 1;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700653 else if (!(dmabuf->fmt & CS_FMT_STEREO) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 (dmabuf->fmt & CS_FMT_16BIT))
655 dmabuf->divisor = 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700656 else if ((dmabuf->fmt & CS_FMT_STEREO) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 !(dmabuf->fmt & CS_FMT_16BIT))
658 dmabuf->divisor = 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700659 else if (!(dmabuf->fmt & CS_FMT_STEREO) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 !(dmabuf->fmt & CS_FMT_16BIT))
661 dmabuf->divisor = 4;
662 else
663 dmabuf->divisor = 1;
664
665 CS_DBGOUT(CS_PARMS | CS_FUNCTION, 8, printk(
666 "cs46xx: cs_set_divisor()- %s %d\n",
667 (dmabuf->type == CS_TYPE_ADC) ? "ADC" : "DAC",
668 dmabuf->divisor) );
669}
670
671/*
672* mute some of the more prevalent registers to avoid popping.
673*/
674static void cs_mute(struct cs_card *card, int state)
675{
Jesper Juhl2eebb192006-06-23 02:05:26 -0700676 struct ac97_codec *dev = card->ac97_codec[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
678 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()+ %s\n",
Jesper Juhl2eebb192006-06-23 02:05:26 -0700679 (state == CS_TRUE) ? "Muting" : "UnMuting"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Jesper Juhl2eebb192006-06-23 02:05:26 -0700681 if (state == CS_TRUE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 /*
683 * fix pops when powering up on thinkpads
684 */
685 card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev,
686 (u8)BA0_AC97_MASTER_VOLUME);
687 card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev,
688 (u8)BA0_AC97_HEADPHONE_VOLUME);
689 card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev,
690 (u8)BA0_AC97_MASTER_VOLUME_MONO);
691 card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev,
692 (u8)BA0_AC97_PCM_OUT_VOLUME);
693
694 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
695 cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
696 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
697 cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700698 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, card->pm.u32AC97_master_volume);
700 cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, card->pm.u32AC97_headphone_volume);
701 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, card->pm.u32AC97_master_volume_mono);
702 cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, card->pm.u32AC97_pcm_out_volume);
703 }
704 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()-\n"));
705}
706
707/* set playback sample rate */
708static unsigned int cs_set_dac_rate(struct cs_state * state, unsigned int rate)
709{
710 struct dmabuf *dmabuf = &state->dmabuf;
711 unsigned int tmp1, tmp2;
712 unsigned int phiIncr;
713 unsigned int correctionPerGOF, correctionPerSec;
714 unsigned long flags;
715
716 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()+ %d\n",rate) );
717
718 /*
719 * Compute the values used to drive the actual sample rate conversion.
720 * The following formulas are being computed, using inline assembly
721 * since we need to use 64 bit arithmetic to compute the values:
722 *
723 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
724 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
725 * GOF_PER_SEC)
726 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
727 * GOF_PER_SEC * correctionPerGOF
728 *
729 * i.e.
730 *
731 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
732 * correctionPerGOF:correctionPerSec =
733 * dividend:remainder(ulOther / GOF_PER_SEC)
734 */
735 tmp1 = rate << 16;
736 phiIncr = tmp1 / 48000;
737 tmp1 -= phiIncr * 48000;
738 tmp1 <<= 10;
739 phiIncr <<= 10;
740 tmp2 = tmp1 / 48000;
741 phiIncr += tmp2;
742 tmp1 -= tmp2 * 48000;
743 correctionPerGOF = tmp1 / GOF_PER_SEC;
744 tmp1 -= correctionPerGOF * GOF_PER_SEC;
745 correctionPerSec = tmp1;
746
747 /*
748 * Fill in the SampleRateConverter control block.
749 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 spin_lock_irqsave(&state->card->lock, flags);
751 cs461x_poke(state->card, BA1_PSRC,
752 ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
753 cs461x_poke(state->card, BA1_PPI, phiIncr);
754 spin_unlock_irqrestore(&state->card->lock, flags);
755 dmabuf->rate = rate;
756
757 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()- %d\n",rate) );
758 return rate;
759}
760
761/* set recording sample rate */
Jesper Juhl2eebb192006-06-23 02:05:26 -0700762static unsigned int cs_set_adc_rate(struct cs_state *state, unsigned int rate)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763{
764 struct dmabuf *dmabuf = &state->dmabuf;
765 struct cs_card *card = state->card;
766 unsigned int phiIncr, coeffIncr, tmp1, tmp2;
767 unsigned int correctionPerGOF, correctionPerSec, initialDelay;
768 unsigned int frameGroupLength, cnt;
769 unsigned long flags;
770 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()+ %d\n",rate) );
771
772 /*
773 * We can only decimate by up to a factor of 1/9th the hardware rate.
774 * Correct the value if an attempt is made to stray outside that limit.
775 */
776 if ((rate * 9) < 48000)
777 rate = 48000 / 9;
778
779 /*
780 * We can not capture at at rate greater than the Input Rate (48000).
781 * Return an error if an attempt is made to stray outside that limit.
782 */
783 if (rate > 48000)
784 rate = 48000;
785
786 /*
787 * Compute the values used to drive the actual sample rate conversion.
788 * The following formulas are being computed, using inline assembly
789 * since we need to use 64 bit arithmetic to compute the values:
790 *
791 * coeffIncr = -floor((Fs,out * 2^23) / Fs,in)
792 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
793 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
794 * GOF_PER_SEC)
795 * correctionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -
796 * GOF_PER_SEC * correctionPerGOF
797 * initialDelay = ceil((24 * Fs,in) / Fs,out)
798 *
799 * i.e.
800 *
801 * coeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in))
802 * phiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out)
803 * correctionPerGOF:correctionPerSec =
804 * dividend:remainder(ulOther / GOF_PER_SEC)
805 * initialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out)
806 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 tmp1 = rate << 16;
808 coeffIncr = tmp1 / 48000;
809 tmp1 -= coeffIncr * 48000;
810 tmp1 <<= 7;
811 coeffIncr <<= 7;
812 coeffIncr += tmp1 / 48000;
813 coeffIncr ^= 0xFFFFFFFF;
814 coeffIncr++;
815 tmp1 = 48000 << 16;
816 phiIncr = tmp1 / rate;
817 tmp1 -= phiIncr * rate;
818 tmp1 <<= 10;
819 phiIncr <<= 10;
820 tmp2 = tmp1 / rate;
821 phiIncr += tmp2;
822 tmp1 -= tmp2 * rate;
823 correctionPerGOF = tmp1 / GOF_PER_SEC;
824 tmp1 -= correctionPerGOF * GOF_PER_SEC;
825 correctionPerSec = tmp1;
826 initialDelay = ((48000 * 24) + rate - 1) / rate;
827
828 /*
829 * Fill in the VariDecimate control block.
830 */
831 spin_lock_irqsave(&card->lock, flags);
832 cs461x_poke(card, BA1_CSRC,
833 ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
834 cs461x_poke(card, BA1_CCI, coeffIncr);
835 cs461x_poke(card, BA1_CD,
836 (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80);
837 cs461x_poke(card, BA1_CPI, phiIncr);
838 spin_unlock_irqrestore(&card->lock, flags);
839
840 /*
841 * Figure out the frame group length for the write back task. Basically,
842 * this is just the factors of 24000 (2^6*3*5^3) that are not present in
843 * the output sample rate.
844 */
845 frameGroupLength = 1;
846 for (cnt = 2; cnt <= 64; cnt *= 2) {
847 if (((rate / cnt) * cnt) != rate)
848 frameGroupLength *= 2;
849 }
850 if (((rate / 3) * 3) != rate) {
851 frameGroupLength *= 3;
852 }
853 for (cnt = 5; cnt <= 125; cnt *= 5) {
854 if (((rate / cnt) * cnt) != rate)
855 frameGroupLength *= 5;
856 }
857
858 /*
859 * Fill in the WriteBack control block.
860 */
861 spin_lock_irqsave(&card->lock, flags);
862 cs461x_poke(card, BA1_CFG1, frameGroupLength);
863 cs461x_poke(card, BA1_CFG2, (0x00800000 | frameGroupLength));
864 cs461x_poke(card, BA1_CCST, 0x0000FFFF);
865 cs461x_poke(card, BA1_CSPB, ((65536 * rate) / 24000));
866 cs461x_poke(card, (BA1_CSPB + 4), 0x0000FFFF);
867 spin_unlock_irqrestore(&card->lock, flags);
868 dmabuf->rate = rate;
869 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()- %d\n",rate) );
870 return rate;
871}
872
873/* prepare channel attributes for playback */
874static void cs_play_setup(struct cs_state *state)
875{
876 struct dmabuf *dmabuf = &state->dmabuf;
877 struct cs_card *card = state->card;
878 unsigned int tmp, Count, playFormat;
879
880 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()+\n") );
881 cs461x_poke(card, BA1_PVOL, 0x80008000);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700882 if (!dmabuf->SGok)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 cs461x_poke(card, BA1_PBA, virt_to_bus(dmabuf->pbuf));
884
885 Count = 4;
886 playFormat=cs461x_peek(card, BA1_PFIE);
887 if ((dmabuf->fmt & CS_FMT_STEREO)) {
888 playFormat &= ~DMA_RQ_C2_AC_MONO_TO_STEREO;
889 Count *= 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700890 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 playFormat |= DMA_RQ_C2_AC_MONO_TO_STEREO;
892
893 if ((dmabuf->fmt & CS_FMT_16BIT)) {
894 playFormat &= ~(DMA_RQ_C2_AC_8_TO_16_BIT
895 | DMA_RQ_C2_AC_SIGNED_CONVERT);
896 Count *= 2;
Jesper Juhl2eebb192006-06-23 02:05:26 -0700897 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 playFormat |= (DMA_RQ_C2_AC_8_TO_16_BIT
899 | DMA_RQ_C2_AC_SIGNED_CONVERT);
900
901 cs461x_poke(card, BA1_PFIE, playFormat);
902
903 tmp = cs461x_peek(card, BA1_PDTC);
904 tmp &= 0xfffffe00;
905 cs461x_poke(card, BA1_PDTC, tmp | --Count);
906
907 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()-\n") );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908}
909
910static struct InitStruct
911{
912 u32 off;
913 u32 val;
914} InitArray[] = { {0x00000040, 0x3fc0000f},
915 {0x0000004c, 0x04800000},
916
917 {0x000000b3, 0x00000780},
918 {0x000000b7, 0x00000000},
919 {0x000000bc, 0x07800000},
920
921 {0x000000cd, 0x00800000},
922 };
923
924/*
925 * "SetCaptureSPValues()" -- Initialize record task values before each
926 * capture startup.
927 */
928static void SetCaptureSPValues(struct cs_card *card)
929{
930 unsigned i, offset;
931 CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()+\n") );
Jesper Juhl2eebb192006-06-23 02:05:26 -0700932 for (i = 0; i < sizeof(InitArray) / sizeof(struct InitStruct); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 offset = InitArray[i].off*4; /* 8bit to 32bit offset value */
934 cs461x_poke(card, offset, InitArray[i].val );
935 }
936 CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()-\n") );
937}
938
939/* prepare channel attributes for recording */
940static void cs_rec_setup(struct cs_state *state)
941{
942 struct cs_card *card = state->card;
943 struct dmabuf *dmabuf = &state->dmabuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
Jesper Juhl2eebb192006-06-23 02:05:26 -0700945 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()+\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 SetCaptureSPValues(card);
947
948 /*
949 * set the attenuation to 0dB
950 */
951 cs461x_poke(card, BA1_CVOL, 0x80008000);
952
953 /*
954 * set the physical address of the capture buffer into the SP
955 */
956 cs461x_poke(card, BA1_CBA, virt_to_bus(dmabuf->rawbuf));
957
958 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()-\n") );
959}
960
961
962/* get current playback/recording dma buffer pointer (byte offset from LBA),
963 called with spinlock held! */
964
965static inline unsigned cs_get_dma_addr(struct cs_state *state)
966{
967 struct dmabuf *dmabuf = &state->dmabuf;
968 u32 offset;
969
970 if ( (!(dmabuf->enable & DAC_RUNNING)) &&
971 (!(dmabuf->enable & ADC_RUNNING) ) )
972 {
973 CS_DBGOUT(CS_ERROR, 2, printk(
974 "cs46xx: ERROR cs_get_dma_addr(): not enabled \n") );
975 return 0;
976 }
977
978 /*
979 * granularity is byte boundary, good part.
980 */
Jesper Juhl2eebb192006-06-23 02:05:26 -0700981 if (dmabuf->enable & DAC_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 offset = cs461x_peek(state->card, BA1_PBA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 else /* ADC_RUNNING must be set */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 offset = cs461x_peek(state->card, BA1_CBA);
Jesper Juhl2eebb192006-06-23 02:05:26 -0700985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 CS_DBGOUT(CS_PARMS | CS_FUNCTION, 9,
987 printk("cs46xx: cs_get_dma_addr() %d\n",offset) );
988 offset = (u32)bus_to_virt((unsigned long)offset) - (u32)dmabuf->rawbuf;
989 CS_DBGOUT(CS_PARMS | CS_FUNCTION, 8,
990 printk("cs46xx: cs_get_dma_addr()- %d\n",offset) );
991 return offset;
992}
993
994static void resync_dma_ptrs(struct cs_state *state)
995{
996 struct dmabuf *dmabuf;
997
998 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()+ \n") );
Jesper Juhl2eebb192006-06-23 02:05:26 -0700999 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 dmabuf = &state->dmabuf;
1001 dmabuf->hwptr=dmabuf->swptr = 0;
1002 dmabuf->pringbuf = 0;
1003 }
1004 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()- \n") );
1005}
1006
1007/* Stop recording (lock held) */
1008static inline void __stop_adc(struct cs_state *state)
1009{
1010 struct dmabuf *dmabuf = &state->dmabuf;
1011 struct cs_card *card = state->card;
1012 unsigned int tmp;
1013
1014 dmabuf->enable &= ~ADC_RUNNING;
1015
1016 tmp = cs461x_peek(card, BA1_CCTL);
1017 tmp &= 0xFFFF0000;
1018 cs461x_poke(card, BA1_CCTL, tmp );
1019}
1020
1021static void stop_adc(struct cs_state *state)
1022{
1023 unsigned long flags;
1024
1025 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_adc()+ \n") );
1026 spin_lock_irqsave(&state->card->lock, flags);
1027 __stop_adc(state);
1028 spin_unlock_irqrestore(&state->card->lock, flags);
1029 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_adc()- \n") );
1030}
1031
1032static void start_adc(struct cs_state *state)
1033{
1034 struct dmabuf *dmabuf = &state->dmabuf;
1035 struct cs_card *card = state->card;
1036 unsigned long flags;
1037 unsigned int tmp;
1038
1039 spin_lock_irqsave(&card->lock, flags);
1040 if (!(dmabuf->enable & ADC_RUNNING) &&
1041 ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize)
1042 && dmabuf->ready) &&
1043 ((card->pm.flags & CS46XX_PM_IDLE) ||
1044 (card->pm.flags & CS46XX_PM_RESUMED)) )
1045 {
1046 dmabuf->enable |= ADC_RUNNING;
1047 cs_set_divisor(dmabuf);
1048 tmp = cs461x_peek(card, BA1_CCTL);
1049 tmp &= 0xFFFF0000;
1050 tmp |= card->cctl;
1051 CS_DBGOUT(CS_FUNCTION, 2, printk(
1052 "cs46xx: start_adc() poke 0x%x \n",tmp) );
1053 cs461x_poke(card, BA1_CCTL, tmp);
1054 }
1055 spin_unlock_irqrestore(&card->lock, flags);
1056}
1057
1058/* stop playback (lock held) */
1059static inline void __stop_dac(struct cs_state *state)
1060{
1061 struct dmabuf *dmabuf = &state->dmabuf;
1062 struct cs_card *card = state->card;
1063 unsigned int tmp;
1064
1065 dmabuf->enable &= ~DAC_RUNNING;
1066
1067 tmp=cs461x_peek(card, BA1_PCTL);
1068 tmp&=0xFFFF;
1069 cs461x_poke(card, BA1_PCTL, tmp);
1070}
1071
1072static void stop_dac(struct cs_state *state)
1073{
1074 unsigned long flags;
1075
1076 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_dac()+ \n") );
1077 spin_lock_irqsave(&state->card->lock, flags);
1078 __stop_dac(state);
1079 spin_unlock_irqrestore(&state->card->lock, flags);
1080 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_dac()- \n") );
1081}
1082
1083static void start_dac(struct cs_state *state)
1084{
1085 struct dmabuf *dmabuf = &state->dmabuf;
1086 struct cs_card *card = state->card;
1087 unsigned long flags;
1088 int tmp;
1089
1090 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()+ \n") );
1091 spin_lock_irqsave(&card->lock, flags);
1092 if (!(dmabuf->enable & DAC_RUNNING) &&
1093 ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) &&
1094 ((card->pm.flags & CS46XX_PM_IDLE) ||
1095 (card->pm.flags & CS46XX_PM_RESUMED)) )
1096 {
1097 dmabuf->enable |= DAC_RUNNING;
1098 tmp = cs461x_peek(card, BA1_PCTL);
1099 tmp &= 0xFFFF;
1100 tmp |= card->pctl;
1101 CS_DBGOUT(CS_PARMS, 6, printk(
1102 "cs46xx: start_dac() poke card=%p tmp=0x%.08x addr=%p \n",
1103 card, (unsigned)tmp,
1104 card->ba1.idx[(BA1_PCTL >> 16) & 3]+(BA1_PCTL&0xffff) ) );
1105 cs461x_poke(card, BA1_PCTL, tmp);
1106 }
1107 spin_unlock_irqrestore(&card->lock, flags);
1108 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()- \n") );
1109}
1110
1111#define DMABUF_MINORDER 1
1112
1113/*
1114 * allocate DMA buffer, playback and recording buffers are separate.
1115 */
1116static int alloc_dmabuf(struct cs_state *state)
1117{
1118
1119 struct cs_card *card=state->card;
1120 struct dmabuf *dmabuf = &state->dmabuf;
1121 void *rawbuf = NULL;
1122 void *tmpbuff = NULL;
1123 int order;
1124 struct page *map, *mapend;
1125 unsigned long df;
1126
1127 dmabuf->ready = dmabuf->mapped = 0;
1128 dmabuf->SGok = 0;
1129/*
1130* check for order within limits, but do not overwrite value.
1131*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07001132 if ((defaultorder > 1) && (defaultorder < 12))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 df = defaultorder;
1134 else
1135 df = 2;
1136
1137 for (order = df; order >= DMABUF_MINORDER; order--)
Jesper Juhl2eebb192006-06-23 02:05:26 -07001138 if ((rawbuf = (void *)pci_alloc_consistent(
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr)))
1140 break;
1141 if (!rawbuf) {
1142 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
1143 "cs46xx: alloc_dmabuf(): unable to allocate rawbuf\n"));
1144 return -ENOMEM;
1145 }
1146 dmabuf->buforder = order;
1147 dmabuf->rawbuf = rawbuf;
1148 // Now mark the pages as reserved; otherwise the
1149 // remap_pfn_range() in cs46xx_mmap doesn't work.
1150 // 1. get index to last page in mem_map array for rawbuf.
1151 mapend = virt_to_page(dmabuf->rawbuf +
1152 (PAGE_SIZE << dmabuf->buforder) - 1);
1153
1154 // 2. mark each physical page in range as 'reserved'.
1155 for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
1156 cs4x_mem_map_reserve(map);
1157
1158 CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: alloc_dmabuf(): allocated %ld (order = %d) bytes at %p\n",
1159 PAGE_SIZE << order, order, rawbuf) );
1160
1161/*
1162* only allocate the conversion buffer for the ADC
1163*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07001164 if (dmabuf->type == CS_TYPE_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 dmabuf->tmpbuff = NULL;
1166 dmabuf->buforder_tmpbuff = 0;
1167 return 0;
1168 }
1169/*
1170 * now the temp buffer for 16/8 conversions
1171 */
1172
1173 tmpbuff = (void *) pci_alloc_consistent(
1174 card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr_tmpbuff);
1175
1176 if (!tmpbuff)
1177 return -ENOMEM;
1178 CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: allocated %ld (order = %d) bytes at %p\n",
1179 PAGE_SIZE << order, order, tmpbuff) );
1180
1181 dmabuf->tmpbuff = tmpbuff;
1182 dmabuf->buforder_tmpbuff = order;
1183
1184 // Now mark the pages as reserved; otherwise the
1185 // remap_pfn_range() in cs46xx_mmap doesn't work.
1186 // 1. get index to last page in mem_map array for rawbuf.
1187 mapend = virt_to_page(dmabuf->tmpbuff +
1188 (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
1189
1190 // 2. mark each physical page in range as 'reserved'.
1191 for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++)
1192 cs4x_mem_map_reserve(map);
1193 return 0;
1194}
1195
1196/* free DMA buffer */
1197static void dealloc_dmabuf(struct cs_state *state)
1198{
1199 struct dmabuf *dmabuf = &state->dmabuf;
1200 struct page *map, *mapend;
1201
1202 if (dmabuf->rawbuf) {
1203 // Undo prog_dmabuf()'s marking the pages as reserved
1204 mapend = virt_to_page(dmabuf->rawbuf +
1205 (PAGE_SIZE << dmabuf->buforder) - 1);
1206 for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
1207 cs4x_mem_map_unreserve(map);
1208 free_dmabuf(state->card, dmabuf);
1209 }
1210
1211 if (dmabuf->tmpbuff) {
1212 // Undo prog_dmabuf()'s marking the pages as reserved
1213 mapend = virt_to_page(dmabuf->tmpbuff +
1214 (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
1215 for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++)
1216 cs4x_mem_map_unreserve(map);
1217 free_dmabuf2(state->card, dmabuf);
1218 }
1219
1220 dmabuf->rawbuf = NULL;
1221 dmabuf->tmpbuff = NULL;
1222 dmabuf->mapped = dmabuf->ready = 0;
1223 dmabuf->SGok = 0;
1224}
1225
1226static int __prog_dmabuf(struct cs_state *state)
1227{
1228 struct dmabuf *dmabuf = &state->dmabuf;
1229 unsigned long flags;
1230 unsigned long allocated_pages, allocated_bytes;
1231 unsigned long tmp1, tmp2, fmt=0;
1232 unsigned long *ptmp = (unsigned long *) dmabuf->pbuf;
1233 unsigned long SGarray[9], nSGpages=0;
1234 int ret;
1235
1236 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()+ \n"));
1237/*
1238 * check for CAPTURE and use only non-sg for initial release
1239 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001240 if (dmabuf->type == CS_TYPE_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf() ADC\n"));
1242 /*
1243 * add in non-sg support for capture.
1244 */
1245 spin_lock_irqsave(&state->card->lock, flags);
1246 /* add code to reset the rawbuf memory. TRW */
1247 resync_dma_ptrs(state);
1248 dmabuf->total_bytes = dmabuf->blocks = 0;
1249 dmabuf->count = dmabuf->error = dmabuf->underrun = 0;
1250
1251 dmabuf->SGok = 0;
1252
1253 spin_unlock_irqrestore(&state->card->lock, flags);
1254
1255 /* allocate DMA buffer if not allocated yet */
1256 if (!dmabuf->rawbuf || !dmabuf->tmpbuff)
1257 if ((ret = alloc_dmabuf(state)))
1258 return ret;
1259 /*
1260 * static image only supports 16Bit signed, stereo - hard code fmt
1261 */
1262 fmt = CS_FMT_16BIT | CS_FMT_STEREO;
1263
1264 dmabuf->numfrag = 2;
1265 dmabuf->fragsize = 2048;
1266 dmabuf->fragsamples = 2048 >> sample_shift[fmt];
1267 dmabuf->dmasize = 4096;
1268 dmabuf->fragshift = 11;
1269
1270 memset(dmabuf->rawbuf, (fmt & CS_FMT_16BIT) ? 0 : 0x80,
1271 dmabuf->dmasize);
1272 memset(dmabuf->tmpbuff, (fmt & CS_FMT_16BIT) ? 0 : 0x80,
1273 PAGE_SIZE<<dmabuf->buforder_tmpbuff);
1274
1275 /*
1276 * Now set up the ring
1277 */
1278
1279 spin_lock_irqsave(&state->card->lock, flags);
1280 cs_rec_setup(state);
1281 spin_unlock_irqrestore(&state->card->lock, flags);
1282
1283 /* set the ready flag for the dma buffer */
1284 dmabuf->ready = 1;
1285
1286 CS_DBGOUT(CS_PARMS, 4, printk(
1287 "cs46xx: prog_dmabuf(): CAPTURE rate=%d fmt=0x%x numfrag=%d "
1288 "fragsize=%d dmasize=%d\n",
1289 dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
1290 dmabuf->fragsize, dmabuf->dmasize) );
1291
1292 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- 0 \n"));
1293 return 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001294 } else if (dmabuf->type == CS_TYPE_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 /*
1296 * Must be DAC
1297 */
1298 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf() DAC\n"));
1299 spin_lock_irqsave(&state->card->lock, flags);
1300 resync_dma_ptrs(state);
1301 dmabuf->total_bytes = dmabuf->blocks = 0;
1302 dmabuf->count = dmabuf->error = dmabuf->underrun = 0;
1303
1304 dmabuf->SGok = 0;
1305
1306 spin_unlock_irqrestore(&state->card->lock, flags);
1307
1308 /* allocate DMA buffer if not allocated yet */
1309 if (!dmabuf->rawbuf)
1310 if ((ret = alloc_dmabuf(state)))
1311 return ret;
1312
1313 allocated_pages = 1 << dmabuf->buforder;
1314 allocated_bytes = allocated_pages*PAGE_SIZE;
1315
Jesper Juhl2eebb192006-06-23 02:05:26 -07001316 if (allocated_pages < 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 CS_DBGOUT(CS_FUNCTION, 4, printk(
1318 "cs46xx: prog_dmabuf() Error: allocated_pages too small (%d)\n",
1319 (unsigned)allocated_pages));
1320 return -ENOMEM;
1321 }
1322
1323 /* Use all the pages allocated, fragsize 4k. */
1324 /* Use 'pbuf' for S/G page map table. */
1325 dmabuf->SGok = 1; /* Use S/G. */
1326
1327 nSGpages = allocated_bytes/4096; /* S/G pages always 4k. */
1328
1329 /* Set up S/G variables. */
1330 *ptmp = virt_to_bus(dmabuf->rawbuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001331 *(ptmp + 1) = 0x00000008;
1332 for (tmp1 = 1; tmp1 < nSGpages; tmp1++) {
1333 *(ptmp + 2 * tmp1) = virt_to_bus((dmabuf->rawbuf) + 4096 * tmp1);
1334 if (tmp1 == nSGpages - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 tmp2 = 0xbfff0000;
1336 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07001337 tmp2 = 0x80000000 + 8 * (tmp1 + 1);
1338 *(ptmp + 2 * tmp1 + 1) = tmp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 }
1340 SGarray[0] = 0x82c0200d;
1341 SGarray[1] = 0xffff0000;
1342 SGarray[2] = *ptmp;
1343 SGarray[3] = 0x00010600;
1344 SGarray[4] = *(ptmp+2);
1345 SGarray[5] = 0x80000010;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001346 SGarray[6] = *ptmp;
1347 SGarray[7] = *(ptmp+2);
1348 SGarray[8] = (virt_to_bus(dmabuf->pbuf) & 0xffff000) | 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Jesper Juhl2eebb192006-06-23 02:05:26 -07001350 if (dmabuf->SGok) {
1351 dmabuf->numfrag = nSGpages;
1352 dmabuf->fragsize = 4096;
1353 dmabuf->fragsamples = 4096 >> sample_shift[dmabuf->fmt];
1354 dmabuf->fragshift = 12;
1355 dmabuf->dmasize = dmabuf->numfrag * 4096;
1356 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 SGarray[0] = 0xf2c0000f;
1358 SGarray[1] = 0x00000200;
1359 SGarray[2] = 0;
1360 SGarray[3] = 0x00010600;
1361 SGarray[4]=SGarray[5]=SGarray[6]=SGarray[7]=SGarray[8] = 0;
1362 dmabuf->numfrag = 2;
1363 dmabuf->fragsize = 2048;
1364 dmabuf->fragsamples = 2048 >> sample_shift[dmabuf->fmt];
1365 dmabuf->dmasize = 4096;
1366 dmabuf->fragshift = 11;
1367 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001368 for (tmp1 = 0; tmp1 < sizeof(SGarray) / 4; tmp1++)
1369 cs461x_poke(state->card, BA1_PDTC+tmp1 * 4, SGarray[tmp1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
1371 memset(dmabuf->rawbuf, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
1372 dmabuf->dmasize);
1373
1374 /*
1375 * Now set up the ring
1376 */
1377
1378 spin_lock_irqsave(&state->card->lock, flags);
1379 cs_play_setup(state);
1380 spin_unlock_irqrestore(&state->card->lock, flags);
1381
1382 /* set the ready flag for the dma buffer */
1383 dmabuf->ready = 1;
1384
1385 CS_DBGOUT(CS_PARMS, 4, printk(
1386 "cs46xx: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d "
1387 "fragsize=%d dmasize=%d\n",
1388 dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
1389 dmabuf->fragsize, dmabuf->dmasize) );
1390
1391 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- \n"));
1392 return 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001393 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- Invalid Type %d\n",
1395 dmabuf->type));
1396 }
1397 return 1;
1398}
1399
1400static int prog_dmabuf(struct cs_state *state)
1401{
1402 int ret;
1403
Ingo Molnar910f5d22006-03-23 03:00:39 -08001404 mutex_lock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 ret = __prog_dmabuf(state);
Ingo Molnar910f5d22006-03-23 03:00:39 -08001406 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
1408 return ret;
1409}
1410
1411static void cs_clear_tail(struct cs_state *state)
1412{
1413}
1414
1415static int drain_dac(struct cs_state *state, int nonblock)
1416{
1417 DECLARE_WAITQUEUE(wait, current);
1418 struct dmabuf *dmabuf = &state->dmabuf;
1419 struct cs_card *card=state->card;
1420 unsigned long flags;
1421 unsigned long tmo;
1422 int count;
1423
1424 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()+ \n"));
1425 if (dmabuf->mapped || !dmabuf->ready)
1426 {
1427 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0, not ready\n"));
1428 return 0;
1429 }
1430
1431 add_wait_queue(&dmabuf->wait, &wait);
1432 for (;;) {
1433 /* It seems that we have to set the current state to TASK_INTERRUPTIBLE
1434 every time to make the process really go to sleep */
1435 current->state = TASK_INTERRUPTIBLE;
1436
1437 spin_lock_irqsave(&state->card->lock, flags);
1438 count = dmabuf->count;
1439 spin_unlock_irqrestore(&state->card->lock, flags);
1440
1441 if (count <= 0)
1442 break;
1443
1444 if (signal_pending(current))
1445 break;
1446
1447 if (nonblock) {
1448 remove_wait_queue(&dmabuf->wait, &wait);
1449 current->state = TASK_RUNNING;
1450 return -EBUSY;
1451 }
1452
1453 tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
1454 tmo >>= sample_shift[dmabuf->fmt];
1455 tmo += (2048*HZ)/dmabuf->rate;
1456
1457 if (!schedule_timeout(tmo ? tmo : 1) && tmo){
1458 printk(KERN_ERR "cs46xx: drain_dac, dma timeout? %d\n", count);
1459 break;
1460 }
1461 }
1462 remove_wait_queue(&dmabuf->wait, &wait);
1463 current->state = TASK_RUNNING;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001464 if (signal_pending(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- -ERESTARTSYS\n"));
1466 /*
1467 * set to silence and let that clear the fifos.
1468 */
1469 cs461x_clear_serial_FIFOs(card, CS_TYPE_DAC);
1470 return -ERESTARTSYS;
1471 }
1472
1473 CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0\n"));
1474 return 0;
1475}
1476
1477
1478/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
1479static void cs_update_ptr(struct cs_card *card, int wake)
1480{
1481 struct cs_state *state;
1482 struct dmabuf *dmabuf;
1483 unsigned hwptr;
1484 int diff;
1485
1486 /* error handling and process wake up for ADC */
1487 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07001488 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 dmabuf = &state->dmabuf;
1490 if (dmabuf->enable & ADC_RUNNING) {
1491 /* update hardware pointer */
1492 hwptr = cs_get_dma_addr(state);
1493
1494 diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
1495 CS_DBGOUT(CS_PARMS, 9, printk(
1496 "cs46xx: cs_update_ptr()+ ADC hwptr=%d diff=%d\n",
1497 hwptr,diff) );
1498 dmabuf->hwptr = hwptr;
1499 dmabuf->total_bytes += diff;
1500 dmabuf->count += diff;
1501 if (dmabuf->count > dmabuf->dmasize)
1502 dmabuf->count = dmabuf->dmasize;
1503
Jesper Juhl2eebb192006-06-23 02:05:26 -07001504 if (dmabuf->mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
1506 wake_up(&dmabuf->wait);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001507 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 if (wake && dmabuf->count > 0)
1509 wake_up(&dmabuf->wait);
1510 }
1511 }
1512 }
1513
1514/*
1515 * Now the DAC
1516 */
1517 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07001518 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 dmabuf = &state->dmabuf;
1520 /* error handling and process wake up for DAC */
1521 if (dmabuf->enable & DAC_RUNNING) {
1522 /* update hardware pointer */
1523 hwptr = cs_get_dma_addr(state);
1524
1525 diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
1526 CS_DBGOUT(CS_PARMS, 9, printk(
1527 "cs46xx: cs_update_ptr()+ DAC hwptr=%d diff=%d\n",
1528 hwptr,diff) );
1529 dmabuf->hwptr = hwptr;
1530 dmabuf->total_bytes += diff;
1531 if (dmabuf->mapped) {
1532 dmabuf->count += diff;
1533 if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
1534 wake_up(&dmabuf->wait);
1535 /*
1536 * other drivers use fragsize, but don't see any sense
1537 * in that, since dmasize is the buffer asked for
1538 * via mmap.
1539 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001540 if (dmabuf->count > dmabuf->dmasize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 dmabuf->count &= dmabuf->dmasize-1;
1542 } else {
1543 dmabuf->count -= diff;
1544 /*
1545 * backfill with silence and clear out the last
1546 * "diff" number of bytes.
1547 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001548 if (hwptr >= diff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 memset(dmabuf->rawbuf + hwptr - diff,
1550 (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, diff);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001551 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 memset(dmabuf->rawbuf,
1553 (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
1554 (unsigned)hwptr);
1555 memset((char *)dmabuf->rawbuf +
1556 dmabuf->dmasize + hwptr - diff,
1557 (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
1558 diff - hwptr);
1559 }
1560
1561 if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
1562 CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
1563 "cs46xx: ERROR DAC count<0 or count > dmasize (%d)\n",
1564 dmabuf->count));
1565 /*
1566 * buffer underrun or buffer overrun, reset the
1567 * count of bytes written back to 0.
1568 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001569 if (dmabuf->count < 0)
1570 dmabuf->underrun = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 dmabuf->count = 0;
1572 dmabuf->error++;
1573 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001574 if (wake && dmabuf->count < (signed)dmabuf->dmasize / 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 wake_up(&dmabuf->wait);
1576 }
1577 }
1578 }
1579}
1580
1581
1582/* hold spinlock for the following! */
1583static void cs_handle_midi(struct cs_card *card)
1584{
1585 unsigned char ch;
1586 int wake;
1587 unsigned temp1;
1588
1589 wake = 0;
1590 while (!(cs461x_peekBA0(card, BA0_MIDSR) & MIDSR_RBE)) {
1591 ch = cs461x_peekBA0(card, BA0_MIDRP);
1592 if (card->midi.icnt < CS_MIDIINBUF) {
1593 card->midi.ibuf[card->midi.iwr] = ch;
1594 card->midi.iwr = (card->midi.iwr + 1) % CS_MIDIINBUF;
1595 card->midi.icnt++;
1596 }
1597 wake = 1;
1598 }
1599 if (wake)
1600 wake_up(&card->midi.iwait);
1601 wake = 0;
1602 while (!(cs461x_peekBA0(card, BA0_MIDSR) & MIDSR_TBF) && card->midi.ocnt > 0) {
1603 temp1 = ( card->midi.obuf[card->midi.ord] ) & 0x000000ff;
1604 cs461x_pokeBA0(card, BA0_MIDWP,temp1);
1605 card->midi.ord = (card->midi.ord + 1) % CS_MIDIOUTBUF;
1606 card->midi.ocnt--;
1607 if (card->midi.ocnt < CS_MIDIOUTBUF-16)
1608 wake = 1;
1609 }
1610 if (wake)
1611 wake_up(&card->midi.owait);
1612}
1613
1614static irqreturn_t cs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
1615{
1616 struct cs_card *card = (struct cs_card *)dev_id;
1617 /* Single channel card */
1618 struct cs_state *recstate = card->channel[0].state;
1619 struct cs_state *playstate = card->channel[1].state;
1620 u32 status;
1621
1622 CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()+ \n"));
1623
1624 spin_lock(&card->lock);
1625
1626 status = cs461x_peekBA0(card, BA0_HISR);
1627
Jesper Juhl2eebb192006-06-23 02:05:26 -07001628 if ((status & 0x7fffffff) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV);
1630 spin_unlock(&card->lock);
1631 return IRQ_HANDLED; /* Might be IRQ_NONE.. */
1632 }
1633
1634 /*
1635 * check for playback or capture interrupt only
1636 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001637 if (((status & HISR_VC0) && playstate && playstate->dmabuf.ready) ||
1638 (((status & HISR_VC1) && recstate && recstate->dmabuf.ready))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 CS_DBGOUT(CS_INTERRUPT, 8, printk(
1640 "cs46xx: cs_interrupt() interrupt bit(s) set (0x%x)\n",status));
1641 cs_update_ptr(card, CS_TRUE);
1642 }
1643
Jesper Juhl2eebb192006-06-23 02:05:26 -07001644 if (status & HISR_MIDI)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 cs_handle_midi(card);
1646
1647 /* clear 'em */
1648 cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV);
1649 spin_unlock(&card->lock);
1650 CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()- \n"));
1651 return IRQ_HANDLED;
1652}
1653
1654
1655/**********************************************************************/
1656
1657static ssize_t cs_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
1658{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001659 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 ssize_t ret;
1661 unsigned long flags;
1662 unsigned ptr;
1663 int cnt;
1664
1665 if (!access_ok(VERIFY_WRITE, buffer, count))
1666 return -EFAULT;
1667 ret = 0;
1668 while (count > 0) {
1669 spin_lock_irqsave(&card->lock, flags);
1670 ptr = card->midi.ird;
1671 cnt = CS_MIDIINBUF - ptr;
1672 if (card->midi.icnt < cnt)
1673 cnt = card->midi.icnt;
1674 spin_unlock_irqrestore(&card->lock, flags);
1675 if (cnt > count)
1676 cnt = count;
1677 if (cnt <= 0) {
1678 if (file->f_flags & O_NONBLOCK)
1679 return ret ? ret : -EAGAIN;
1680 interruptible_sleep_on(&card->midi.iwait);
1681 if (signal_pending(current))
1682 return ret ? ret : -ERESTARTSYS;
1683 continue;
1684 }
1685 if (copy_to_user(buffer, card->midi.ibuf + ptr, cnt))
1686 return ret ? ret : -EFAULT;
1687 ptr = (ptr + cnt) % CS_MIDIINBUF;
1688 spin_lock_irqsave(&card->lock, flags);
1689 card->midi.ird = ptr;
1690 card->midi.icnt -= cnt;
1691 spin_unlock_irqrestore(&card->lock, flags);
1692 count -= cnt;
1693 buffer += cnt;
1694 ret += cnt;
1695 }
1696 return ret;
1697}
1698
1699
1700static ssize_t cs_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
1701{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001702 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 ssize_t ret;
1704 unsigned long flags;
1705 unsigned ptr;
1706 int cnt;
1707
1708 if (!access_ok(VERIFY_READ, buffer, count))
1709 return -EFAULT;
1710 ret = 0;
1711 while (count > 0) {
1712 spin_lock_irqsave(&card->lock, flags);
1713 ptr = card->midi.owr;
1714 cnt = CS_MIDIOUTBUF - ptr;
1715 if (card->midi.ocnt + cnt > CS_MIDIOUTBUF)
1716 cnt = CS_MIDIOUTBUF - card->midi.ocnt;
1717 if (cnt <= 0)
1718 cs_handle_midi(card);
1719 spin_unlock_irqrestore(&card->lock, flags);
1720 if (cnt > count)
1721 cnt = count;
1722 if (cnt <= 0) {
1723 if (file->f_flags & O_NONBLOCK)
1724 return ret ? ret : -EAGAIN;
1725 interruptible_sleep_on(&card->midi.owait);
1726 if (signal_pending(current))
1727 return ret ? ret : -ERESTARTSYS;
1728 continue;
1729 }
1730 if (copy_from_user(card->midi.obuf + ptr, buffer, cnt))
1731 return ret ? ret : -EFAULT;
1732 ptr = (ptr + cnt) % CS_MIDIOUTBUF;
1733 spin_lock_irqsave(&card->lock, flags);
1734 card->midi.owr = ptr;
1735 card->midi.ocnt += cnt;
1736 spin_unlock_irqrestore(&card->lock, flags);
1737 count -= cnt;
1738 buffer += cnt;
1739 ret += cnt;
1740 spin_lock_irqsave(&card->lock, flags);
1741 cs_handle_midi(card);
1742 spin_unlock_irqrestore(&card->lock, flags);
1743 }
1744 return ret;
1745}
1746
1747
1748static unsigned int cs_midi_poll(struct file *file, struct poll_table_struct *wait)
1749{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001750 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 unsigned long flags;
1752 unsigned int mask = 0;
1753
1754 if (file->f_flags & FMODE_WRITE)
1755 poll_wait(file, &card->midi.owait, wait);
1756 if (file->f_flags & FMODE_READ)
1757 poll_wait(file, &card->midi.iwait, wait);
1758 spin_lock_irqsave(&card->lock, flags);
1759 if (file->f_flags & FMODE_READ) {
1760 if (card->midi.icnt > 0)
1761 mask |= POLLIN | POLLRDNORM;
1762 }
1763 if (file->f_flags & FMODE_WRITE) {
1764 if (card->midi.ocnt < CS_MIDIOUTBUF)
1765 mask |= POLLOUT | POLLWRNORM;
1766 }
1767 spin_unlock_irqrestore(&card->lock, flags);
1768 return mask;
1769}
1770
1771
1772static int cs_midi_open(struct inode *inode, struct file *file)
1773{
1774 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07001775 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 unsigned long flags;
1777 struct list_head *entry;
1778
Jesper Juhl2eebb192006-06-23 02:05:26 -07001779 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 card = list_entry(entry, struct cs_card, list);
1781 if (card->dev_midi == minor)
1782 break;
1783 }
1784
1785 if (entry == &cs46xx_devs)
1786 return -ENODEV;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001787 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
1789 "cs46xx: cs46xx_midi_open(): Error - unable to find card struct\n"));
1790 return -ENODEV;
1791 }
1792
1793 file->private_data = card;
1794 /* wait for device to become free */
Ingo Molnar910f5d22006-03-23 03:00:39 -08001795 mutex_lock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 while (card->midi.open_mode & file->f_mode) {
1797 if (file->f_flags & O_NONBLOCK) {
Ingo Molnar910f5d22006-03-23 03:00:39 -08001798 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 return -EBUSY;
1800 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08001801 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 interruptible_sleep_on(&card->midi.open_wait);
1803 if (signal_pending(current))
1804 return -ERESTARTSYS;
Ingo Molnar910f5d22006-03-23 03:00:39 -08001805 mutex_lock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 }
1807 spin_lock_irqsave(&card->midi.lock, flags);
1808 if (!(card->midi.open_mode & (FMODE_READ | FMODE_WRITE))) {
1809 card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
1810 card->midi.ord = card->midi.owr = card->midi.ocnt = 0;
1811 card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
1812 cs461x_pokeBA0(card, BA0_MIDCR, 0x0000000f); /* Enable xmit, rcv. */
1813 cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM); /* Enable interrupts */
1814 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001815 if (file->f_mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001817 if (file->f_mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 card->midi.ord = card->midi.owr = card->midi.ocnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 spin_unlock_irqrestore(&card->midi.lock, flags);
1820 card->midi.open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE));
Ingo Molnar910f5d22006-03-23 03:00:39 -08001821 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 return 0;
1823}
1824
1825
1826static int cs_midi_release(struct inode *inode, struct file *file)
1827{
Jesper Juhl2eebb192006-06-23 02:05:26 -07001828 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 DECLARE_WAITQUEUE(wait, current);
1830 unsigned long flags;
1831 unsigned count, tmo;
1832
1833 if (file->f_mode & FMODE_WRITE) {
1834 current->state = TASK_INTERRUPTIBLE;
1835 add_wait_queue(&card->midi.owait, &wait);
1836 for (;;) {
1837 spin_lock_irqsave(&card->midi.lock, flags);
1838 count = card->midi.ocnt;
1839 spin_unlock_irqrestore(&card->midi.lock, flags);
1840 if (count <= 0)
1841 break;
1842 if (signal_pending(current))
1843 break;
1844 if (file->f_flags & O_NONBLOCK)
1845 break;
1846 tmo = (count * HZ) / 3100;
1847 if (!schedule_timeout(tmo ? : 1) && tmo)
1848 printk(KERN_DEBUG "cs46xx: midi timed out??\n");
1849 }
1850 remove_wait_queue(&card->midi.owait, &wait);
1851 current->state = TASK_RUNNING;
1852 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08001853 mutex_lock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 card->midi.open_mode &= (~(file->f_mode & (FMODE_READ | FMODE_WRITE)));
Ingo Molnar910f5d22006-03-23 03:00:39 -08001855 mutex_unlock(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 wake_up(&card->midi.open_wait);
1857 return 0;
1858}
1859
1860/*
1861 * Midi file operations struct.
1862 */
1863static /*const*/ struct file_operations cs_midi_fops = {
1864 CS_OWNER CS_THIS_MODULE
1865 .llseek = no_llseek,
1866 .read = cs_midi_read,
1867 .write = cs_midi_write,
1868 .poll = cs_midi_poll,
1869 .open = cs_midi_open,
1870 .release = cs_midi_release,
1871};
1872
1873/*
1874 *
1875 * CopySamples copies 16-bit stereo signed samples from the source to the
1876 * destination, possibly converting down to unsigned 8-bit and/or mono.
1877 * count specifies the number of output bytes to write.
1878 *
1879 * Arguments:
1880 *
1881 * dst - Pointer to a destination buffer.
1882 * src - Pointer to a source buffer
1883 * count - The number of bytes to copy into the destination buffer.
1884 * fmt - CS_FMT_16BIT and/or CS_FMT_STEREO bits
1885 * dmabuf - pointer to the dma buffer structure
1886 *
1887 * NOTES: only call this routine if the output desired is not 16 Signed Stereo
1888 *
1889 *
1890 */
1891static void CopySamples(char *dst, char *src, int count, unsigned fmt,
1892 struct dmabuf *dmabuf)
1893{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 s32 s32AudioSample;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001895 s16 *psSrc = (s16 *)src;
1896 s16 *psDst = (s16 *)dst;
1897 u8 *pucDst = (u8 *)dst;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: CopySamples()+ ") );
1900 CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
1901 " dst=%p src=%p count=%d fmt=0x%x\n",
1902 dst,src,count,fmt) );
1903
1904 /*
1905 * See if the data should be output as 8-bit unsigned stereo.
1906 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001907 if ((fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 /*
1909 * Convert each 16-bit signed stereo sample to 8-bit unsigned
1910 * stereo using rounding.
1911 */
1912 psSrc = (s16 *)src;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001913 count = count / 2;
1914 while (count--)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 *(pucDst++) = (u8)(((s16)(*psSrc++) + (s16)0x8000) >> 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 }
1917 /*
1918 * See if the data should be output at 8-bit unsigned mono.
1919 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001920 else if (!(fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 /*
1922 * Convert each 16-bit signed stereo sample to 8-bit unsigned
1923 * mono using averaging and rounding.
1924 */
1925 psSrc = (s16 *)src;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001926 count = count / 2;
1927 while (count--) {
1928 s32AudioSample = ((*psSrc) + (*(psSrc + 1))) / 2 + (s32)0x80;
1929 if (s32AudioSample > 0x7fff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 s32AudioSample = 0x7fff;
1931 *(pucDst++) = (u8)(((s16)s32AudioSample + (s16)0x8000) >> 8);
1932 psSrc += 2;
1933 }
1934 }
1935 /*
1936 * See if the data should be output at 16-bit signed mono.
1937 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07001938 else if (!(fmt & CS_FMT_STEREO) && (fmt & CS_FMT_16BIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 /*
1940 * Convert each 16-bit signed stereo sample to 16-bit signed
1941 * mono using averaging.
1942 */
1943 psSrc = (s16 *)src;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001944 count = count / 2;
1945 while (count--) {
1946 *(psDst++) = (s16)((*psSrc) + (*(psSrc + 1))) / 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 psSrc += 2;
1948 }
1949 }
1950}
1951
1952/*
1953 * cs_copy_to_user()
1954 * replacement for the standard copy_to_user, to allow for a conversion from
1955 * 16 bit to 8 bit and from stereo to mono, if the record conversion is active.
1956 * The current CS46xx/CS4280 static image only records in 16bit unsigned Stereo,
1957 * so we convert from any of the other format combinations.
1958 */
1959static unsigned cs_copy_to_user(
1960 struct cs_state *s,
1961 void __user *dest,
1962 void *hwsrc,
1963 unsigned cnt,
1964 unsigned *copied)
1965{
1966 struct dmabuf *dmabuf = &s->dmabuf;
1967 void *src = hwsrc; /* default to the standard destination buffer addr */
1968
1969 CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO
1970 "cs_copy_to_user()+ fmt=0x%x cnt=%d dest=%p\n",
1971 dmabuf->fmt,(unsigned)cnt,dest) );
1972
Jesper Juhl2eebb192006-06-23 02:05:26 -07001973 if (cnt > dmabuf->dmasize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 cnt = dmabuf->dmasize;
Jesper Juhl2eebb192006-06-23 02:05:26 -07001975 if (!cnt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 *copied = 0;
1977 return 0;
1978 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001979 if (dmabuf->divisor != 1) {
1980 if (!dmabuf->tmpbuff) {
1981 *copied = cnt / dmabuf->divisor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 return 0;
1983 }
1984
1985 CopySamples((char *)dmabuf->tmpbuff, (char *)hwsrc, cnt,
1986 dmabuf->fmt, dmabuf);
1987 src = dmabuf->tmpbuff;
1988 cnt = cnt/dmabuf->divisor;
1989 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07001990 if (copy_to_user(dest, src, cnt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
1992 "cs46xx: cs_copy_to_user()- fault dest=%p src=%p cnt=%d\n",
Jesper Juhl2eebb192006-06-23 02:05:26 -07001993 dest,src,cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 *copied = 0;
1995 return -EFAULT;
1996 }
1997 *copied = cnt;
1998 CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07001999 "cs46xx: cs_copy_to_user()- copied bytes is %d \n",cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 return 0;
2001}
2002
2003/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to
2004 the user's buffer. it is filled by the dma machine and drained by this loop. */
2005static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
2006{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002007 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 struct cs_state *state;
2009 DECLARE_WAITQUEUE(wait, current);
2010 struct dmabuf *dmabuf;
2011 ssize_t ret = 0;
2012 unsigned long flags;
2013 unsigned swptr;
2014 int cnt;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002015 unsigned copied = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
2017 CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
2018 printk("cs46xx: cs_read()+ %zd\n",count) );
Jesper Juhl2eebb192006-06-23 02:05:26 -07002019 state = card->states[0];
2020 if (!state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 return -ENODEV;
2022 dmabuf = &state->dmabuf;
2023
2024 if (dmabuf->mapped)
2025 return -ENXIO;
2026 if (!access_ok(VERIFY_WRITE, buffer, count))
2027 return -EFAULT;
2028
Ingo Molnar910f5d22006-03-23 03:00:39 -08002029 mutex_lock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
2031 goto out2;
2032
2033 add_wait_queue(&state->dmabuf.wait, &wait);
2034 while (count > 0) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002035 while (!(card->pm.flags & CS46XX_PM_IDLE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 schedule();
2037 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002038 if (!ret)
2039 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 goto out;
2041 }
2042 }
2043 spin_lock_irqsave(&state->card->lock, flags);
2044 swptr = dmabuf->swptr;
2045 cnt = dmabuf->dmasize - swptr;
2046 if (dmabuf->count < cnt)
2047 cnt = dmabuf->count;
2048 if (cnt <= 0)
2049 __set_current_state(TASK_INTERRUPTIBLE);
2050 spin_unlock_irqrestore(&state->card->lock, flags);
2051
2052 if (cnt > (count * dmabuf->divisor))
2053 cnt = count * dmabuf->divisor;
2054 if (cnt <= 0) {
2055 /* buffer is empty, start the dma machine and wait for data to be
2056 recorded */
2057 start_adc(state);
2058 if (file->f_flags & O_NONBLOCK) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002059 if (!ret)
2060 ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 goto out;
2062 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002063 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 schedule();
2065 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002066 if (!ret)
2067 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 goto out;
2069 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002070 mutex_lock(&state->sem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002071 if (dmabuf->mapped) {
2072 if (!ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 ret = -ENXIO;
2074 goto out;
2075 }
2076 continue;
2077 }
2078
2079 CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
2080 "_read() copy_to cnt=%d count=%zd ", cnt,count) );
2081 CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
2082 " .dmasize=%d .count=%d buffer=%p ret=%zd\n",
Jesper Juhl2eebb192006-06-23 02:05:26 -07002083 dmabuf->dmasize,dmabuf->count,buffer,ret));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
2085 if (cs_copy_to_user(state, buffer,
Jesper Juhl2eebb192006-06-23 02:05:26 -07002086 (char *)dmabuf->rawbuf + swptr, cnt, &copied)) {
2087 if (!ret)
2088 ret = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 goto out;
2090 }
2091 swptr = (swptr + cnt) % dmabuf->dmasize;
2092 spin_lock_irqsave(&card->lock, flags);
2093 dmabuf->swptr = swptr;
2094 dmabuf->count -= cnt;
2095 spin_unlock_irqrestore(&card->lock, flags);
2096 count -= copied;
2097 buffer += copied;
2098 ret += copied;
2099 start_adc(state);
2100 }
2101out:
2102 remove_wait_queue(&state->dmabuf.wait, &wait);
2103out2:
Ingo Molnar910f5d22006-03-23 03:00:39 -08002104 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 set_current_state(TASK_RUNNING);
2106 CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
2107 printk("cs46xx: cs_read()- %zd\n",ret) );
2108 return ret;
2109}
2110
2111/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
2112 the soundcard. it is drained by the dma machine and filled by this loop. */
2113static ssize_t cs_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
2114{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002115 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 struct cs_state *state;
2117 DECLARE_WAITQUEUE(wait, current);
2118 struct dmabuf *dmabuf;
2119 ssize_t ret;
2120 unsigned long flags;
2121 unsigned swptr;
2122 int cnt;
2123
2124 CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 4,
2125 printk("cs46xx: cs_write called, count = %zd\n", count) );
Jesper Juhl2eebb192006-06-23 02:05:26 -07002126 state = card->states[1];
2127 if (!state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 return -ENODEV;
2129 if (!access_ok(VERIFY_READ, buffer, count))
2130 return -EFAULT;
2131 dmabuf = &state->dmabuf;
2132
Ingo Molnar910f5d22006-03-23 03:00:39 -08002133 mutex_lock(&state->sem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002134 if (dmabuf->mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 ret = -ENXIO;
2136 goto out;
2137 }
2138
2139 if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
2140 goto out;
2141 add_wait_queue(&state->dmabuf.wait, &wait);
2142 ret = 0;
2143/*
2144* Start the loop to read from the user's buffer and write to the dma buffer.
2145* check for PM events and underrun/overrun in the loop.
2146*/
2147 while (count > 0) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002148 while (!(card->pm.flags & CS46XX_PM_IDLE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 schedule();
2150 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002151 if (!ret)
2152 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 goto out;
2154 }
2155 }
2156 spin_lock_irqsave(&state->card->lock, flags);
2157 if (dmabuf->count < 0) {
2158 /* buffer underrun, we are recovering from sleep_on_timeout,
2159 resync hwptr and swptr */
2160 dmabuf->count = 0;
2161 dmabuf->swptr = dmabuf->hwptr;
2162 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002163 if (dmabuf->underrun) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 dmabuf->underrun = 0;
2165 dmabuf->hwptr = cs_get_dma_addr(state);
2166 dmabuf->swptr = dmabuf->hwptr;
2167 }
2168
2169 swptr = dmabuf->swptr;
2170 cnt = dmabuf->dmasize - swptr;
2171 if (dmabuf->count + cnt > dmabuf->dmasize)
2172 cnt = dmabuf->dmasize - dmabuf->count;
2173 if (cnt <= 0)
2174 __set_current_state(TASK_INTERRUPTIBLE);
2175 spin_unlock_irqrestore(&state->card->lock, flags);
2176
2177 if (cnt > count)
2178 cnt = count;
2179 if (cnt <= 0) {
2180 /* buffer is full, start the dma machine and wait for data to be
2181 played */
2182 start_dac(state);
2183 if (file->f_flags & O_NONBLOCK) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002184 if (!ret)
2185 ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 goto out;
2187 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002188 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 schedule();
2190 if (signal_pending(current)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002191 if (!ret)
2192 ret = -ERESTARTSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 goto out;
2194 }
Ingo Molnar910f5d22006-03-23 03:00:39 -08002195 mutex_lock(&state->sem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002196 if (dmabuf->mapped) {
2197 if (!ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 ret = -ENXIO;
2199 goto out;
2200 }
2201 continue;
2202 }
2203 if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002204 if (!ret)
2205 ret = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 goto out;
2207 }
2208 spin_lock_irqsave(&state->card->lock, flags);
2209 swptr = (swptr + cnt) % dmabuf->dmasize;
2210 dmabuf->swptr = swptr;
2211 dmabuf->count += cnt;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002212 if (dmabuf->count > dmabuf->dmasize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 CS_DBGOUT(CS_WAVE_WRITE | CS_ERROR, 2, printk(
2214 "cs46xx: cs_write() d->count > dmasize - resetting\n"));
2215 dmabuf->count = dmabuf->dmasize;
2216 }
2217 dmabuf->endcleared = 0;
2218 spin_unlock_irqrestore(&state->card->lock, flags);
2219
2220 count -= cnt;
2221 buffer += cnt;
2222 ret += cnt;
2223 start_dac(state);
2224 }
2225out:
Ingo Molnar910f5d22006-03-23 03:00:39 -08002226 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 remove_wait_queue(&state->dmabuf.wait, &wait);
2228 set_current_state(TASK_RUNNING);
2229
2230 CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 2,
Jesper Juhl2eebb192006-06-23 02:05:26 -07002231 printk("cs46xx: cs_write()- ret=%zd\n", ret));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 return ret;
2233}
2234
2235static unsigned int cs_poll(struct file *file, struct poll_table_struct *wait)
2236{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002237 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 struct dmabuf *dmabuf;
2239 struct cs_state *state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 unsigned long flags;
2241 unsigned int mask = 0;
2242
2243 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()+ \n"));
Jesper Juhl2eebb192006-06-23 02:05:26 -07002244 if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 return -EINVAL;
2246 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002247 if (file->f_mode & FMODE_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002249 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 dmabuf = &state->dmabuf;
2251 poll_wait(file, &dmabuf->wait, wait);
2252 }
2253 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002254 if (file->f_mode & FMODE_READ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002256 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 dmabuf = &state->dmabuf;
2258 poll_wait(file, &dmabuf->wait, wait);
2259 }
2260 }
2261
2262 spin_lock_irqsave(&card->lock, flags);
2263 cs_update_ptr(card, CS_FALSE);
2264 if (file->f_mode & FMODE_READ) {
2265 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002266 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 dmabuf = &state->dmabuf;
2268 if (dmabuf->count >= (signed)dmabuf->fragsize)
2269 mask |= POLLIN | POLLRDNORM;
2270 }
2271 }
2272 if (file->f_mode & FMODE_WRITE) {
2273 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002274 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 dmabuf = &state->dmabuf;
2276 if (dmabuf->mapped) {
2277 if (dmabuf->count >= (signed)dmabuf->fragsize)
2278 mask |= POLLOUT | POLLWRNORM;
2279 } else {
2280 if ((signed)dmabuf->dmasize >= dmabuf->count
2281 + (signed)dmabuf->fragsize)
2282 mask |= POLLOUT | POLLWRNORM;
2283 }
2284 }
2285 }
2286 spin_unlock_irqrestore(&card->lock, flags);
2287
2288 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()- (0x%x) \n",
2289 mask));
2290 return mask;
2291}
2292
2293/*
2294 * We let users mmap the ring buffer. Its not the real DMA buffer but
2295 * that side of the code is hidden in the IRQ handling. We do a software
2296 * emulation of DMA from a 64K or so buffer into a 2K FIFO.
2297 * (the hardware probably deserves a moan here but Crystal send me nice
2298 * toys ;)).
2299 */
2300
2301static int cs_mmap(struct file *file, struct vm_area_struct *vma)
2302{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002303 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 struct cs_state *state;
2305 struct dmabuf *dmabuf;
2306 int ret = 0;
2307 unsigned long size;
2308
2309 CS_DBGOUT(CS_FUNCTION | CS_PARMS, 2, printk("cs46xx: cs_mmap()+ file=%p %s %s\n",
2310 file, vma->vm_flags & VM_WRITE ? "VM_WRITE" : "",
2311 vma->vm_flags & VM_READ ? "VM_READ" : "") );
2312
2313 if (vma->vm_flags & VM_WRITE) {
2314 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002315 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 CS_DBGOUT(CS_OPEN, 2, printk(
2317 "cs46xx: cs_mmap() VM_WRITE - state TRUE prog_dmabuf DAC\n") );
2318 if ((ret = prog_dmabuf(state)) != 0)
2319 return ret;
2320 }
2321 } else if (vma->vm_flags & VM_READ) {
2322 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07002323 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 CS_DBGOUT(CS_OPEN, 2, printk(
2325 "cs46xx: cs_mmap() VM_READ - state TRUE prog_dmabuf ADC\n") );
2326 if ((ret = prog_dmabuf(state)) != 0)
2327 return ret;
2328 }
2329 } else {
2330 CS_DBGOUT(CS_ERROR, 2, printk(
2331 "cs46xx: cs_mmap() return -EINVAL\n") );
2332 return -EINVAL;
2333 }
2334
2335/*
2336 * For now ONLY support playback, but seems like the only way to use
2337 * mmap() is to open an FD with RDWR, just read or just write access
2338 * does not function, get an error back from the kernel.
2339 * Also, QuakeIII opens with RDWR! So, there must be something
2340 * to needing read/write access mapping. So, allow read/write but
2341 * use the DAC only.
2342 */
2343 state = card->states[1];
2344 if (!state) {
2345 ret = -EINVAL;
2346 goto out;
2347 }
2348
Ingo Molnar910f5d22006-03-23 03:00:39 -08002349 mutex_lock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002351 if (cs4x_pgoff(vma) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 ret = -EINVAL;
2353 goto out;
2354 }
2355 size = vma->vm_end - vma->vm_start;
2356
2357 CS_DBGOUT(CS_PARMS, 2, printk("cs46xx: cs_mmap(): size=%d\n",(unsigned)size) );
2358
Jesper Juhl2eebb192006-06-23 02:05:26 -07002359 if (size > (PAGE_SIZE << dmabuf->buforder)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 ret = -EINVAL;
2361 goto out;
2362 }
2363 if (remap_pfn_range(vma, vma->vm_start,
2364 virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
Jesper Juhl2eebb192006-06-23 02:05:26 -07002365 size, vma->vm_page_prot)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 ret = -EAGAIN;
2367 goto out;
2368 }
2369 dmabuf->mapped = 1;
2370
2371 CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mmap()-\n") );
2372out:
Ingo Molnar910f5d22006-03-23 03:00:39 -08002373 mutex_unlock(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 return ret;
2375}
2376
2377static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
2378{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002379 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 struct cs_state *state;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002381 struct dmabuf *dmabuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 unsigned long flags;
2383 audio_buf_info abinfo;
2384 count_info cinfo;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002385 int val, valsave, ret;
2386 int mapped = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 void __user *argp = (void __user *)arg;
2388 int __user *p = argp;
2389
Jesper Juhl2eebb192006-06-23 02:05:26 -07002390 state = card->states[0];
2391 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 dmabuf = &state->dmabuf;
2393 mapped = (file->f_mode & FMODE_READ) && dmabuf->mapped;
2394 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002395 state = card->states[1];
2396 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 dmabuf = &state->dmabuf;
2398 mapped |= (file->f_mode & FMODE_WRITE) && dmabuf->mapped;
2399 }
2400
2401#if CSDEBUG
2402 printioctl(cmd);
2403#endif
2404
Jesper Juhl2eebb192006-06-23 02:05:26 -07002405 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 case OSS_GETVERSION:
2407 return put_user(SOUND_VERSION, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 case SNDCTL_DSP_RESET:
2409 /* FIXME: spin_lock ? */
2410 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002411 state = card->states[1];
2412 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 dmabuf = &state->dmabuf;
2414 stop_dac(state);
2415 synchronize_irq(card->irq);
2416 dmabuf->ready = 0;
2417 resync_dma_ptrs(state);
2418 dmabuf->swptr = dmabuf->hwptr = 0;
2419 dmabuf->count = dmabuf->total_bytes = 0;
2420 dmabuf->blocks = 0;
2421 dmabuf->SGok = 0;
2422 }
2423 }
2424 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002425 state = card->states[0];
2426 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 dmabuf = &state->dmabuf;
2428 stop_adc(state);
2429 synchronize_irq(card->irq);
2430 resync_dma_ptrs(state);
2431 dmabuf->ready = 0;
2432 dmabuf->swptr = dmabuf->hwptr = 0;
2433 dmabuf->count = dmabuf->total_bytes = 0;
2434 dmabuf->blocks = 0;
2435 dmabuf->SGok = 0;
2436 }
2437 }
2438 CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_RESET()-\n") );
2439 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 case SNDCTL_DSP_SYNC:
2441 if (file->f_mode & FMODE_WRITE)
2442 return drain_dac(state, file->f_flags & O_NONBLOCK);
2443 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 case SNDCTL_DSP_SPEED: /* set sample rate */
2445 if (get_user(val, p))
2446 return -EFAULT;
2447 if (val >= 0) {
2448 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002449 state = card->states[0];
2450 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 dmabuf = &state->dmabuf;
2452 stop_adc(state);
2453 dmabuf->ready = 0;
2454 dmabuf->SGok = 0;
2455 cs_set_adc_rate(state, val);
2456 cs_set_divisor(dmabuf);
2457 }
2458 }
2459 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002460 state = card->states[1];
2461 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 dmabuf = &state->dmabuf;
2463 stop_dac(state);
2464 dmabuf->ready = 0;
2465 dmabuf->SGok = 0;
2466 cs_set_dac_rate(state, val);
2467 cs_set_divisor(dmabuf);
2468 }
2469 }
2470 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2471 "cs46xx: cs_ioctl() DSP_SPEED %s %s %d\n",
2472 file->f_mode & FMODE_WRITE ? "DAC" : "",
2473 file->f_mode & FMODE_READ ? "ADC" : "",
2474 dmabuf->rate ) );
2475 return put_user(dmabuf->rate, p);
2476 }
2477 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
2479 if (get_user(val, p))
2480 return -EFAULT;
2481 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002482 state = card->states[1];
2483 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 dmabuf = &state->dmabuf;
2485 stop_dac(state);
2486 dmabuf->ready = 0;
2487 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002488 if (val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 dmabuf->fmt |= CS_FMT_STEREO;
2490 else
2491 dmabuf->fmt &= ~CS_FMT_STEREO;
2492 cs_set_divisor(dmabuf);
2493 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2494 "cs46xx: DSP_STEREO() DAC %s\n",
2495 (dmabuf->fmt & CS_FMT_STEREO) ?
2496 "STEREO":"MONO") );
2497 }
2498 }
2499 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002500 state = card->states[0];
2501 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 dmabuf = &state->dmabuf;
2503 stop_adc(state);
2504 dmabuf->ready = 0;
2505 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002506 if (val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 dmabuf->fmt |= CS_FMT_STEREO;
2508 else
2509 dmabuf->fmt &= ~CS_FMT_STEREO;
2510 cs_set_divisor(dmabuf);
2511 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2512 "cs46xx: DSP_STEREO() ADC %s\n",
2513 (dmabuf->fmt & CS_FMT_STEREO) ?
2514 "STEREO":"MONO") );
2515 }
2516 }
2517 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 case SNDCTL_DSP_GETBLKSIZE:
2519 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002520 state = card->states[1];
2521 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 dmabuf = &state->dmabuf;
2523 if ((val = prog_dmabuf(state)))
2524 return val;
2525 return put_user(dmabuf->fragsize, p);
2526 }
2527 }
2528 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002529 state = card->states[0];
2530 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 dmabuf = &state->dmabuf;
2532 if ((val = prog_dmabuf(state)))
2533 return val;
2534 return put_user(dmabuf->fragsize/dmabuf->divisor,
2535 p);
2536 }
2537 }
2538 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
2540 return put_user(AFMT_S16_LE | AFMT_U8, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 case SNDCTL_DSP_SETFMT: /* Select sample format */
2542 if (get_user(val, p))
2543 return -EFAULT;
2544 CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
2545 "cs46xx: cs_ioctl() DSP_SETFMT %s %s %s %s\n",
2546 file->f_mode & FMODE_WRITE ? "DAC" : "",
2547 file->f_mode & FMODE_READ ? "ADC" : "",
2548 val == AFMT_S16_LE ? "16Bit Signed" : "",
2549 val == AFMT_U8 ? "8Bit Unsigned" : "") );
2550 valsave = val;
2551 if (val != AFMT_QUERY) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002552 if (val==AFMT_S16_LE || val==AFMT_U8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002554 state = card->states[1];
2555 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 dmabuf = &state->dmabuf;
2557 stop_dac(state);
2558 dmabuf->ready = 0;
2559 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002560 if (val == AFMT_S16_LE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 dmabuf->fmt |= CS_FMT_16BIT;
2562 else
2563 dmabuf->fmt &= ~CS_FMT_16BIT;
2564 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002565 if ((ret = prog_dmabuf(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 return ret;
2567 }
2568 }
2569 if (file->f_mode & FMODE_READ) {
2570 val = valsave;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002571 state = card->states[0];
2572 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 dmabuf = &state->dmabuf;
2574 stop_adc(state);
2575 dmabuf->ready = 0;
2576 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002577 if (val == AFMT_S16_LE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 dmabuf->fmt |= CS_FMT_16BIT;
2579 else
2580 dmabuf->fmt &= ~CS_FMT_16BIT;
2581 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002582 if ((ret = prog_dmabuf(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 return ret;
2584 }
2585 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002586 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 CS_DBGOUT(CS_IOCTL | CS_ERROR, 2, printk(
2588 "cs46xx: DSP_SETFMT() Unsupported format (0x%x)\n",
2589 valsave) );
2590 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002591 } else {
2592 if (file->f_mode & FMODE_WRITE) {
2593 state = card->states[1];
2594 if (state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002596 } else if (file->f_mode & FMODE_READ) {
2597 state = card->states[0];
2598 if (state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 dmabuf = &state->dmabuf;
2600 }
2601 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002602 if (dmabuf) {
2603 if (dmabuf->fmt & CS_FMT_16BIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 return put_user(AFMT_S16_LE, p);
2605 else
2606 return put_user(AFMT_U8, p);
2607 }
2608 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 case SNDCTL_DSP_CHANNELS:
2610 if (get_user(val, p))
2611 return -EFAULT;
2612 if (val != 0) {
2613 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002614 state = card->states[1];
2615 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 dmabuf = &state->dmabuf;
2617 stop_dac(state);
2618 dmabuf->ready = 0;
2619 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002620 if (val > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 dmabuf->fmt |= CS_FMT_STEREO;
2622 else
2623 dmabuf->fmt &= ~CS_FMT_STEREO;
2624 cs_set_divisor(dmabuf);
2625 if (prog_dmabuf(state))
2626 return 0;
2627 }
2628 }
2629 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002630 state = card->states[0];
2631 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 dmabuf = &state->dmabuf;
2633 stop_adc(state);
2634 dmabuf->ready = 0;
2635 dmabuf->SGok = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002636 if (val > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 dmabuf->fmt |= CS_FMT_STEREO;
2638 else
2639 dmabuf->fmt &= ~CS_FMT_STEREO;
2640 cs_set_divisor(dmabuf);
2641 if (prog_dmabuf(state))
2642 return 0;
2643 }
2644 }
2645 }
2646 return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
2647 p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 case SNDCTL_DSP_POST:
2649 /*
2650 * There will be a longer than normal pause in the data.
2651 * so... do nothing, because there is nothing that we can do.
2652 */
2653 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 case SNDCTL_DSP_SUBDIVIDE:
2655 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002656 state = card->states[1];
2657 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 dmabuf = &state->dmabuf;
2659 if (dmabuf->subdivision)
2660 return -EINVAL;
2661 if (get_user(val, p))
2662 return -EFAULT;
2663 if (val != 1 && val != 2)
2664 return -EINVAL;
2665 dmabuf->subdivision = val;
2666 }
2667 }
2668 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002669 state = card->states[0];
2670 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 dmabuf = &state->dmabuf;
2672 if (dmabuf->subdivision)
2673 return -EINVAL;
2674 if (get_user(val, p))
2675 return -EFAULT;
2676 if (val != 1 && val != 2)
2677 return -EINVAL;
2678 dmabuf->subdivision = val;
2679 }
2680 }
2681 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 case SNDCTL_DSP_SETFRAGMENT:
2683 if (get_user(val, p))
2684 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002686 state = card->states[1];
2687 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 dmabuf = &state->dmabuf;
2689 dmabuf->ossfragshift = val & 0xffff;
2690 dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
2691 }
2692 }
2693 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002694 state = card->states[0];
2695 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 dmabuf = &state->dmabuf;
2697 dmabuf->ossfragshift = val & 0xffff;
2698 dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
2699 }
2700 }
2701 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 case SNDCTL_DSP_GETOSPACE:
2703 if (!(file->f_mode & FMODE_WRITE))
2704 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002705 state = card->states[1];
2706 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 dmabuf = &state->dmabuf;
2708 spin_lock_irqsave(&state->card->lock, flags);
2709 cs_update_ptr(card, CS_TRUE);
2710 abinfo.fragsize = dmabuf->fragsize;
2711 abinfo.fragstotal = dmabuf->numfrag;
2712 /*
2713 * for mmap we always have total space available
2714 */
2715 if (dmabuf->mapped)
2716 abinfo.bytes = dmabuf->dmasize;
2717 else
2718 abinfo.bytes = dmabuf->dmasize - dmabuf->count;
2719
2720 abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
2721 spin_unlock_irqrestore(&state->card->lock, flags);
2722 return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
2723 }
2724 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 case SNDCTL_DSP_GETISPACE:
2726 if (!(file->f_mode & FMODE_READ))
2727 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002728 state = card->states[0];
2729 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 dmabuf = &state->dmabuf;
2731 spin_lock_irqsave(&state->card->lock, flags);
2732 cs_update_ptr(card, CS_TRUE);
2733 abinfo.fragsize = dmabuf->fragsize/dmabuf->divisor;
2734 abinfo.bytes = dmabuf->count/dmabuf->divisor;
2735 abinfo.fragstotal = dmabuf->numfrag;
2736 abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
2737 spin_unlock_irqrestore(&state->card->lock, flags);
2738 return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
2739 }
2740 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 case SNDCTL_DSP_NONBLOCK:
2742 file->f_flags |= O_NONBLOCK;
2743 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 case SNDCTL_DSP_GETCAPS:
2745 return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
2746 p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 case SNDCTL_DSP_GETTRIGGER:
2748 val = 0;
2749 CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()+\n") );
Jesper Juhl2eebb192006-06-23 02:05:26 -07002750 if (file->f_mode & FMODE_WRITE) {
2751 state = card->states[1];
2752 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002754 if (dmabuf->enable & DAC_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 val |= PCM_ENABLE_INPUT;
2756 }
2757 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07002758 if (file->f_mode & FMODE_READ) {
2759 if (state) {
2760 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 dmabuf = &state->dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002762 if (dmabuf->enable & ADC_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 val |= PCM_ENABLE_OUTPUT;
2764 }
2765 }
2766 CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()- val=0x%x\n",val) );
2767 return put_user(val, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 case SNDCTL_DSP_SETTRIGGER:
2769 if (get_user(val, p))
2770 return -EFAULT;
2771 if (file->f_mode & FMODE_READ) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002772 state = card->states[0];
2773 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 dmabuf = &state->dmabuf;
2775 if (val & PCM_ENABLE_INPUT) {
2776 if (!dmabuf->ready && (ret = prog_dmabuf(state)))
2777 return ret;
2778 start_adc(state);
2779 } else
2780 stop_adc(state);
2781 }
2782 }
2783 if (file->f_mode & FMODE_WRITE) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07002784 state = card->states[1];
2785 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 dmabuf = &state->dmabuf;
2787 if (val & PCM_ENABLE_OUTPUT) {
2788 if (!dmabuf->ready && (ret = prog_dmabuf(state)))
2789 return ret;
2790 start_dac(state);
2791 } else
2792 stop_dac(state);
2793 }
2794 }
2795 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 case SNDCTL_DSP_GETIPTR:
2797 if (!(file->f_mode & FMODE_READ))
2798 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002799 state = card->states[0];
2800 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 dmabuf = &state->dmabuf;
2802 spin_lock_irqsave(&state->card->lock, flags);
2803 cs_update_ptr(card, CS_TRUE);
2804 cinfo.bytes = dmabuf->total_bytes/dmabuf->divisor;
2805 cinfo.blocks = dmabuf->count/dmabuf->divisor >> dmabuf->fragshift;
2806 cinfo.ptr = dmabuf->hwptr/dmabuf->divisor;
2807 spin_unlock_irqrestore(&state->card->lock, flags);
2808 if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
2809 return -EFAULT;
2810 return 0;
2811 }
2812 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 case SNDCTL_DSP_GETOPTR:
2814 if (!(file->f_mode & FMODE_WRITE))
2815 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002816 state = card->states[1];
2817 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 dmabuf = &state->dmabuf;
2819 spin_lock_irqsave(&state->card->lock, flags);
2820 cs_update_ptr(card, CS_TRUE);
2821 cinfo.bytes = dmabuf->total_bytes;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002822 if (dmabuf->mapped) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 cinfo.blocks = (cinfo.bytes >> dmabuf->fragshift)
2824 - dmabuf->blocks;
2825 CS_DBGOUT(CS_PARMS, 8,
2826 printk("total_bytes=%d blocks=%d dmabuf->blocks=%d\n",
2827 cinfo.bytes,cinfo.blocks,dmabuf->blocks) );
2828 dmabuf->blocks = cinfo.bytes >> dmabuf->fragshift;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002829 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
2831 }
2832 cinfo.ptr = dmabuf->hwptr;
2833
2834 CS_DBGOUT(CS_PARMS, 4, printk(
2835 "cs46xx: GETOPTR bytes=%d blocks=%d ptr=%d\n",
2836 cinfo.bytes,cinfo.blocks,cinfo.ptr) );
2837 spin_unlock_irqrestore(&state->card->lock, flags);
2838 if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
2839 return -EFAULT;
2840 return 0;
2841 }
2842 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 case SNDCTL_DSP_SETDUPLEX:
2844 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 case SNDCTL_DSP_GETODELAY:
2846 if (!(file->f_mode & FMODE_WRITE))
2847 return -EINVAL;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002848 state = card->states[1];
2849 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 dmabuf = &state->dmabuf;
2851 spin_lock_irqsave(&state->card->lock, flags);
2852 cs_update_ptr(card, CS_TRUE);
2853 val = dmabuf->count;
2854 spin_unlock_irqrestore(&state->card->lock, flags);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002855 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 val = 0;
2857 return put_user(val, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 case SOUND_PCM_READ_RATE:
Jesper Juhl2eebb192006-06-23 02:05:26 -07002859 if (file->f_mode & FMODE_READ)
2860 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07002862 state = card->states[1];
2863 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 dmabuf = &state->dmabuf;
2865 return put_user(dmabuf->rate, p);
2866 }
2867 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 case SOUND_PCM_READ_CHANNELS:
Jesper Juhl2eebb192006-06-23 02:05:26 -07002869 if (file->f_mode & FMODE_READ)
2870 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07002872 state = card->states[1];
2873 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 dmabuf = &state->dmabuf;
2875 return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
2876 p);
2877 }
2878 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 case SOUND_PCM_READ_BITS:
Jesper Juhl2eebb192006-06-23 02:05:26 -07002880 if (file->f_mode & FMODE_READ)
2881 state = card->states[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 else
Jesper Juhl2eebb192006-06-23 02:05:26 -07002883 state = card->states[1];
2884 if (state) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 dmabuf = &state->dmabuf;
2886 return put_user((dmabuf->fmt & CS_FMT_16BIT) ?
2887 AFMT_S16_LE : AFMT_U8, p);
2888
2889 }
2890 return put_user(0, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 case SNDCTL_DSP_MAPINBUF:
2892 case SNDCTL_DSP_MAPOUTBUF:
2893 case SNDCTL_DSP_SETSYNCRO:
2894 case SOUND_PCM_WRITE_FILTER:
2895 case SOUND_PCM_READ_FILTER:
2896 return -EINVAL;
2897 }
2898 return -EINVAL;
2899}
2900
2901
2902/*
2903 * AMP control - null AMP
2904 */
2905
2906static void amp_none(struct cs_card *card, int change)
2907{
2908}
2909
2910/*
2911 * Crystal EAPD mode
2912 */
2913
2914static void amp_voyetra(struct cs_card *card, int change)
2915{
2916 /* Manage the EAPD bit on the Crystal 4297
2917 and the Analog AD1885 */
2918
Jesper Juhl2eebb192006-06-23 02:05:26 -07002919 int old = card->amplifier;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
2921 card->amplifier+=change;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002922 if (card->amplifier && !old) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 /* Turn the EAPD amp on */
2924 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL,
2925 cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) |
2926 0x8000);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002927 } else if(old && !card->amplifier) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 /* Turn the EAPD amp off */
2929 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL,
2930 cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
2931 ~0x8000);
2932 }
2933}
2934
2935
2936/*
2937 * Game Theatre XP card - EGPIO[2] is used to enable the external amp.
2938 */
2939
2940static void amp_hercules(struct cs_card *card, int change)
2941{
Jesper Juhl2eebb192006-06-23 02:05:26 -07002942 int old = card->amplifier;
2943 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
2945 "cs46xx: amp_hercules() called before initialized.\n"));
2946 return;
2947 }
2948 card->amplifier+=change;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002949 if ((card->amplifier && !old) && !(hercules_egpio_disable)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO
2951 "cs46xx: amp_hercules() external amp enabled\n"));
2952 cs461x_pokeBA0(card, BA0_EGPIODR,
2953 EGPIODR_GPOE2); /* enable EGPIO2 output */
2954 cs461x_pokeBA0(card, BA0_EGPIOPTR,
2955 EGPIOPTR_GPPT2); /* open-drain on output */
Jesper Juhl2eebb192006-06-23 02:05:26 -07002956 } else if (old && !card->amplifier) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO
2958 "cs46xx: amp_hercules() external amp disabled\n"));
2959 cs461x_pokeBA0(card, BA0_EGPIODR, 0); /* disable */
2960 cs461x_pokeBA0(card, BA0_EGPIOPTR, 0); /* disable */
2961 }
2962}
2963
2964/*
2965 * Handle the CLKRUN on a thinkpad. We must disable CLKRUN support
2966 * whenever we need to beat on the chip.
2967 *
2968 * The original idea and code for this hack comes from David Kaiser at
2969 * Linuxcare. Perhaps one day Crystal will document their chips well
2970 * enough to make them useful.
2971 */
2972
2973static void clkrun_hack(struct cs_card *card, int change)
2974{
2975 struct pci_dev *acpi_dev;
2976 u16 control;
2977 u8 pp;
2978 unsigned long port;
Jesper Juhl2eebb192006-06-23 02:05:26 -07002979 int old = card->active;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980
2981 card->active+=change;
2982
2983 acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002984 if (acpi_dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 return; /* Not a thinkpad thats for sure */
2986
2987 /* Find the control port */
2988 pci_read_config_byte(acpi_dev, 0x41, &pp);
Jesper Juhl2eebb192006-06-23 02:05:26 -07002989 port = pp << 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990
2991 /* Read ACPI port */
Jesper Juhl2eebb192006-06-23 02:05:26 -07002992 control = inw(port + 0x10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993
2994 /* Flip CLKRUN off while running */
Jesper Juhl2eebb192006-06-23 02:05:26 -07002995 if (!card->active && old) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
2997 "cs46xx: clkrun() enable clkrun - change=%d active=%d\n",
2998 change,card->active));
2999 outw(control|0x2000, port+0x10);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003000 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 /*
3002 * sometimes on a resume the bit is set, so always reset the bit.
3003 */
3004 CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
3005 "cs46xx: clkrun() disable clkrun - change=%d active=%d\n",
3006 change,card->active));
3007 outw(control&~0x2000, port+0x10);
3008 }
3009}
3010
3011
3012static int cs_open(struct inode *inode, struct file *file)
3013{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003014 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 struct cs_state *state = NULL;
3016 struct dmabuf *dmabuf = NULL;
3017 struct list_head *entry;
3018 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003019 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 unsigned int tmp;
3021
3022 CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()+ file=%p %s %s\n",
3023 file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
3024 file->f_mode & FMODE_READ ? "FMODE_READ" : "") );
3025
Jesper Juhl2eebb192006-06-23 02:05:26 -07003026 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 card = list_entry(entry, struct cs_card, list);
3028
3029 if (!((card->dev_audio ^ minor) & ~0xf))
3030 break;
3031 }
3032 if (entry == &cs46xx_devs)
3033 return -ENODEV;
3034 if (!card) {
3035 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
3036 "cs46xx: cs_open(): Error - unable to find audio card struct\n"));
3037 return -ENODEV;
3038 }
3039
3040 /*
3041 * hardcode state[0] for capture, [1] for playback
3042 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003043 if (file->f_mode & FMODE_READ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 CS_DBGOUT(CS_WAVE_READ, 2, printk("cs46xx: cs_open() FMODE_READ\n") );
3045 if (card->states[0] == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003046 state = card->states[0] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 kmalloc(sizeof(struct cs_state), GFP_KERNEL);
3048 if (state == NULL)
3049 return -ENOMEM;
3050 memset(state, 0, sizeof(struct cs_state));
Ingo Molnar910f5d22006-03-23 03:00:39 -08003051 mutex_init(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 dmabuf = &state->dmabuf;
3053 dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003054 if (dmabuf->pbuf == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 kfree(state);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003056 card->states[0] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 return -ENOMEM;
3058 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003059 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003061 if (state->open_mode & FMODE_READ)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 return -EBUSY;
3063 }
3064 dmabuf->channel = card->alloc_rec_pcm_channel(card);
3065
3066 if (dmabuf->channel == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003067 kfree(card->states[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 card->states[0] = NULL;
3069 return -ENODEV;
3070 }
3071
3072 /* Now turn on external AMP if needed */
3073 state->card = card;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003074 state->card->active_ctrl(state->card, 1);
3075 state->card->amplifier_ctrl(state->card, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076
Jesper Juhl2eebb192006-06-23 02:05:26 -07003077 if ((tmp = cs46xx_powerup(card, CS_POWER_ADC))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003079 "cs46xx: cs46xx_powerup of ADC failed (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 return -EIO;
3081 }
3082
3083 dmabuf->channel->state = state;
3084 /* initialize the virtual channel */
3085 state->virt = 0;
3086 state->magic = CS_STATE_MAGIC;
3087 init_waitqueue_head(&dmabuf->wait);
Ingo Molnar910f5d22006-03-23 03:00:39 -08003088 mutex_init(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 file->private_data = card;
3090
Ingo Molnar910f5d22006-03-23 03:00:39 -08003091 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
3093 /* set default sample format. According to OSS Programmer's Guide /dev/dsp
3094 should be default to unsigned 8-bits, mono, with sample rate 8kHz and
3095 /dev/dspW will accept 16-bits sample */
3096
3097 /* Default input is 8bit mono */
3098 dmabuf->fmt &= ~CS_FMT_MASK;
3099 dmabuf->type = CS_TYPE_ADC;
3100 dmabuf->ossfragshift = 0;
3101 dmabuf->ossmaxfrags = 0;
3102 dmabuf->subdivision = 0;
3103 cs_set_adc_rate(state, 8000);
3104 cs_set_divisor(dmabuf);
3105
3106 state->open_mode |= FMODE_READ;
Ingo Molnar910f5d22006-03-23 03:00:39 -08003107 mutex_unlock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003109 if (file->f_mode & FMODE_WRITE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 CS_DBGOUT(CS_OPEN, 2, printk("cs46xx: cs_open() FMODE_WRITE\n") );
3111 if (card->states[1] == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003112 state = card->states[1] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 kmalloc(sizeof(struct cs_state), GFP_KERNEL);
3114 if (state == NULL)
3115 return -ENOMEM;
3116 memset(state, 0, sizeof(struct cs_state));
Ingo Molnar910f5d22006-03-23 03:00:39 -08003117 mutex_init(&state->sem);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 dmabuf = &state->dmabuf;
3119 dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003120 if (dmabuf->pbuf == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 kfree(state);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003122 card->states[1] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 return -ENOMEM;
3124 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003125 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003127 if (state->open_mode & FMODE_WRITE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 return -EBUSY;
3129 }
3130 dmabuf->channel = card->alloc_pcm_channel(card);
3131
3132 if (dmabuf->channel == NULL) {
Jesper Juhl2eebb192006-06-23 02:05:26 -07003133 kfree(card->states[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 card->states[1] = NULL;
3135 return -ENODEV;
3136 }
3137
3138 /* Now turn on external AMP if needed */
3139 state->card = card;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003140 state->card->active_ctrl(state->card, 1);
3141 state->card->amplifier_ctrl(state->card, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142
Jesper Juhl2eebb192006-06-23 02:05:26 -07003143 if ((tmp = cs46xx_powerup(card, CS_POWER_DAC))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003145 "cs46xx: cs46xx_powerup of DAC failed (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 return -EIO;
3147 }
3148
3149 dmabuf->channel->state = state;
3150 /* initialize the virtual channel */
3151 state->virt = 1;
3152 state->magic = CS_STATE_MAGIC;
3153 init_waitqueue_head(&dmabuf->wait);
Ingo Molnar910f5d22006-03-23 03:00:39 -08003154 mutex_init(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 file->private_data = card;
3156
Ingo Molnar910f5d22006-03-23 03:00:39 -08003157 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158
3159 /* set default sample format. According to OSS Programmer's Guide /dev/dsp
3160 should be default to unsigned 8-bits, mono, with sample rate 8kHz and
3161 /dev/dspW will accept 16-bits sample */
3162
3163 /* Default output is 8bit mono. */
3164 dmabuf->fmt &= ~CS_FMT_MASK;
3165 dmabuf->type = CS_TYPE_DAC;
3166 dmabuf->ossfragshift = 0;
3167 dmabuf->ossmaxfrags = 0;
3168 dmabuf->subdivision = 0;
3169 cs_set_dac_rate(state, 8000);
3170 cs_set_divisor(dmabuf);
3171
3172 state->open_mode |= FMODE_WRITE;
Ingo Molnar910f5d22006-03-23 03:00:39 -08003173 mutex_unlock(&state->open_mutex);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003174 if ((ret = prog_dmabuf(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 return ret;
3176 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003177 CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()- 0\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 return nonseekable_open(inode, file);
3179}
3180
3181static int cs_release(struct inode *inode, struct file *file)
3182{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003183 struct cs_card *card = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 struct dmabuf *dmabuf;
3185 struct cs_state *state;
3186 unsigned int tmp;
3187 CS_DBGOUT(CS_RELEASE | CS_FUNCTION, 2, printk("cs46xx: cs_release()+ file=%p %s %s\n",
3188 file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
Jesper Juhl2eebb192006-06-23 02:05:26 -07003189 file->f_mode & FMODE_READ ? "FMODE_READ" : ""));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190
3191 if (!(file->f_mode & (FMODE_WRITE | FMODE_READ)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 state = card->states[1];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003194 if (state) {
3195 if ((state->open_mode & FMODE_WRITE) & (file->f_mode & FMODE_WRITE)) {
3196 CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_WRITE\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197 dmabuf = &state->dmabuf;
3198 cs_clear_tail(state);
3199 drain_dac(state, file->f_flags & O_NONBLOCK);
3200 /* stop DMA state machine and free DMA buffers/channels */
Ingo Molnar910f5d22006-03-23 03:00:39 -08003201 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 stop_dac(state);
3203 dealloc_dmabuf(state);
3204 state->card->free_pcm_channel(state->card, dmabuf->channel->num);
3205 free_page((unsigned long)state->dmabuf.pbuf);
3206
Ingo Molnar910f5d22006-03-23 03:00:39 -08003207 /* we're covered by the open_mutex */
3208 mutex_unlock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 state->card->states[state->virt] = NULL;
3210 state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
3211
Jesper Juhl2eebb192006-06-23 02:05:26 -07003212 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
3214 "cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) );
3215 }
3216
3217 /* Now turn off external AMP if needed */
3218 state->card->amplifier_ctrl(state->card, -1);
3219 state->card->active_ctrl(state->card, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 kfree(state);
3221 }
3222 }
3223
3224 state = card->states[0];
Jesper Juhl2eebb192006-06-23 02:05:26 -07003225 if (state) {
3226 if ((state->open_mode & FMODE_READ) & (file->f_mode & FMODE_READ)) {
3227 CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_READ\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228 dmabuf = &state->dmabuf;
Ingo Molnar910f5d22006-03-23 03:00:39 -08003229 mutex_lock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 stop_adc(state);
3231 dealloc_dmabuf(state);
3232 state->card->free_pcm_channel(state->card, dmabuf->channel->num);
3233 free_page((unsigned long)state->dmabuf.pbuf);
3234
Ingo Molnar910f5d22006-03-23 03:00:39 -08003235 /* we're covered by the open_mutex */
3236 mutex_unlock(&state->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 state->card->states[state->virt] = NULL;
3238 state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
3239
Jesper Juhl2eebb192006-06-23 02:05:26 -07003240 if ((tmp = cs461x_powerdown(card, CS_POWER_ADC, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
3242 "cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) );
3243 }
3244
3245 /* Now turn off external AMP if needed */
3246 state->card->amplifier_ctrl(state->card, -1);
3247 state->card->active_ctrl(state->card, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 kfree(state);
3249 }
3250 }
3251
Jesper Juhl2eebb192006-06-23 02:05:26 -07003252 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk("cs46xx: cs_release()- 0\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 return 0;
3254}
3255
3256static void printpm(struct cs_card *s)
3257{
3258 CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
3259 CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
3260 (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue));
3261 CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n",
3262 s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue));
3263 CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n",
3264 s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue));
3265 CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n",
3266 s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue));
3267 CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n",
3268 s->pm.u32SSCR,s->pm.u32SRCSA));
3269 CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n",
3270 s->pm.u32DacASR,s->pm.u32AdcASR));
3271 CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n",
3272 s->pm.u32DacSR,s->pm.u32AdcSR));
3273 CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n",
3274 s->pm.u32MIDCR_Save));
3275 CS_DBGOUT(CS_PM, 9, printk("u32AC97_powerdown: 0x%x _general_purpose 0x%x\n",
3276 s->pm.u32AC97_powerdown,s->pm.u32AC97_general_purpose));
3277 CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume: 0x%x\n",
3278 s->pm.u32AC97_master_volume));
3279 CS_DBGOUT(CS_PM, 9, printk("u32AC97_headphone_volume: 0x%x\n",
3280 s->pm.u32AC97_headphone_volume));
3281 CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume_mono: 0x%x\n",
3282 s->pm.u32AC97_master_volume_mono));
3283 CS_DBGOUT(CS_PM, 9, printk("u32AC97_pcm_out_volume: 0x%x\n",
3284 s->pm.u32AC97_pcm_out_volume));
3285 CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_play: 0x%x dmabuf_count_play: %d\n",
3286 s->pm.dmabuf_swptr_play,s->pm.dmabuf_count_play));
3287 CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_capture: 0x%x dmabuf_count_capture: %d\n",
3288 s->pm.dmabuf_swptr_capture,s->pm.dmabuf_count_capture));
3289
3290}
3291
3292/****************************************************************************
3293*
3294* Suspend - save the ac97 regs, mute the outputs and power down the part.
3295*
3296****************************************************************************/
3297static void cs46xx_ac97_suspend(struct cs_card *card)
3298{
3299 int Count,i;
3300 struct ac97_codec *dev=card->ac97_codec[0];
3301 unsigned int tmp;
3302
3303 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n"));
3304
Jesper Juhl2eebb192006-06-23 02:05:26 -07003305 if (card->states[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306 stop_dac(card->states[1]);
3307 resync_dma_ptrs(card->states[1]);
3308 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003309 if (card->states[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310 stop_adc(card->states[0]);
3311 resync_dma_ptrs(card->states[0]);
3312 }
3313
Jesper Juhl2eebb192006-06-23 02:05:26 -07003314 for (Count = 0x2, i = 0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE)
3315 && (i < CS46XX_AC97_NUMBER_RESTORE_REGS);
3316 Count += 2, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 card->pm.ac97[i] = cs_ac97_get(dev, BA0_AC97_RESET + Count);
3318 }
3319/*
3320* Save the ac97 volume registers as well as the current powerdown state.
3321* Now, mute the all the outputs (master, headphone, and mono), as well
3322* as the PCM volume, in preparation for powering down the entire part.
3323 card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev,
3324 (u8)BA0_AC97_MASTER_VOLUME);
3325 card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev,
3326 (u8)BA0_AC97_HEADPHONE_VOLUME);
3327 card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev,
3328 (u8)BA0_AC97_MASTER_VOLUME_MONO);
3329 card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev,
3330 (u8)BA0_AC97_PCM_OUT_VOLUME);
3331*/
3332/*
3333* mute the outputs
3334*/
3335 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
3336 cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
3337 cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
3338 cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
3339
3340/*
3341* save the registers that cause pops
3342*/
3343 card->pm.u32AC97_powerdown = (u32)cs_ac97_get(dev, (u8)AC97_POWER_CONTROL);
3344 card->pm.u32AC97_general_purpose = (u32)cs_ac97_get(dev, (u8)BA0_AC97_GENERAL_PURPOSE);
3345/*
3346* And power down everything on the AC97 codec.
3347* well, for now, only power down the DAC/ADC and MIXER VREFON components.
3348* trouble with removing VREF.
3349*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003350 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
3351 CS_POWER_MIXVON, CS_TRUE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003353 "cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 }
3355
3356 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()-\n"));
3357}
3358
3359/****************************************************************************
3360*
3361* Resume - power up the part and restore its registers..
3362*
3363****************************************************************************/
3364static void cs46xx_ac97_resume(struct cs_card *card)
3365{
3366 int Count,i;
3367 struct ac97_codec *dev=card->ac97_codec[0];
3368
3369 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()+\n"));
3370
3371/*
3372* First, we restore the state of the general purpose register. This
3373* contains the mic select (mic1 or mic2) and if we restore this after
3374* we restore the mic volume/boost state and mic2 was selected at
3375* suspend time, we will end up with a brief period of time where mic1
3376* is selected with the volume/boost settings for mic2, causing
3377* acoustic feedback. So we restore the general purpose register
3378* first, thereby getting the correct mic selected before we restore
3379* the mic volume/boost.
3380*/
3381 cs_ac97_set(dev, (u8)BA0_AC97_GENERAL_PURPOSE,
3382 (u16)card->pm.u32AC97_general_purpose);
3383/*
3384* Now, while the outputs are still muted, restore the state of power
3385* on the AC97 part.
3386*/
3387 cs_ac97_set(dev, (u8)BA0_AC97_POWERDOWN, (u16)card->pm.u32AC97_powerdown);
3388 mdelay(5 * cs_laptop_wait);
3389/*
3390* Restore just the first set of registers, from register number
3391* 0x02 to the register number that ulHighestRegToRestore specifies.
3392*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003393 for (Count = 0x2, i=0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE) &&
3394 (i < CS46XX_AC97_NUMBER_RESTORE_REGS); Count += 2, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 cs_ac97_set(dev, (u8)(BA0_AC97_RESET + Count), (u16)card->pm.ac97[i]);
3396 }
3397
3398 /* Check if we have to init the amplifier */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003399 if (card->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 card->amp_init(card);
3401
3402 CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()-\n"));
3403}
3404
3405
3406static int cs46xx_restart_part(struct cs_card *card)
3407{
3408 struct dmabuf *dmabuf;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003409
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3411 printk( "cs46xx: cs46xx_restart_part()+\n"));
Jesper Juhl2eebb192006-06-23 02:05:26 -07003412 if (card->states[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 dmabuf = &card->states[1]->dmabuf;
3414 dmabuf->ready = 0;
3415 resync_dma_ptrs(card->states[1]);
3416 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003417 if (__prog_dmabuf(card->states[1])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 CS_DBGOUT(CS_PM | CS_ERROR, 1,
3419 printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n"));
3420 return -1;
3421 }
3422 cs_set_dac_rate(card->states[1], dmabuf->rate);
3423 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003424 if (card->states[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 dmabuf = &card->states[0]->dmabuf;
3426 dmabuf->ready = 0;
3427 resync_dma_ptrs(card->states[0]);
3428 cs_set_divisor(dmabuf);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003429 if (__prog_dmabuf(card->states[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 CS_DBGOUT(CS_PM | CS_ERROR, 1,
3431 printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n"));
3432 return -1;
3433 }
3434 cs_set_adc_rate(card->states[0], dmabuf->rate);
3435 }
3436 card->pm.flags |= CS46XX_PM_RESUMED;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003437 if (card->states[0])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 start_adc(card->states[0]);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003439 if (card->states[1])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 start_dac(card->states[1]);
3441
3442 card->pm.flags |= CS46XX_PM_IDLE;
3443 card->pm.flags &= ~(CS46XX_PM_SUSPENDING | CS46XX_PM_SUSPENDED
3444 | CS46XX_PM_RESUMING | CS46XX_PM_RESUMED);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003445 if (card->states[0])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 wake_up(&card->states[0]->dmabuf.wait);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003447 if (card->states[1])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 wake_up(&card->states[1]->dmabuf.wait);
3449
3450 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3451 printk( "cs46xx: cs46xx_restart_part()-\n"));
3452 return 0;
3453}
3454
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455static void cs461x_reset(struct cs_card *card);
3456static void cs461x_proc_stop(struct cs_card *card);
Pavel Machek3bfffd92005-04-16 15:25:37 -07003457static int cs46xx_suspend(struct cs_card *card, pm_message_t state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458{
3459 unsigned int tmp;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003460
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3462 printk("cs46xx: cs46xx_suspend()+ flags=0x%x s=%p\n",
3463 (unsigned)card->pm.flags,card));
3464/*
3465* check the current state, only suspend if IDLE
3466*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003467 if (!(card->pm.flags & CS46XX_PM_IDLE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 CS_DBGOUT(CS_PM | CS_ERROR, 2,
3469 printk("cs46xx: cs46xx_suspend() unable to suspend, not IDLE\n"));
3470 return 1;
3471 }
3472 card->pm.flags &= ~CS46XX_PM_IDLE;
3473 card->pm.flags |= CS46XX_PM_SUSPENDING;
3474
3475 card->active_ctrl(card,1);
3476
3477 tmp = cs461x_peek(card, BA1_PFIE);
3478 tmp &= ~0x0000f03f;
3479 tmp |= 0x00000010;
3480 cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */
3481
3482 tmp = cs461x_peek(card, BA1_CIE);
3483 tmp &= ~0x0000003f;
3484 tmp |= 0x00000011;
3485 cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */
3486
3487 /*
3488 * Stop playback DMA.
3489 */
3490 tmp = cs461x_peek(card, BA1_PCTL);
3491 cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
3492
3493 /*
3494 * Stop capture DMA.
3495 */
3496 tmp = cs461x_peek(card, BA1_CCTL);
3497 cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
3498
Jesper Juhl2eebb192006-06-23 02:05:26 -07003499 if (card->states[1]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 card->pm.dmabuf_swptr_play = card->states[1]->dmabuf.swptr;
3501 card->pm.dmabuf_count_play = card->states[1]->dmabuf.count;
3502 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003503 if (card->states[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 card->pm.dmabuf_swptr_capture = card->states[0]->dmabuf.swptr;
3505 card->pm.dmabuf_count_capture = card->states[0]->dmabuf.count;
3506 }
3507
3508 cs46xx_ac97_suspend(card);
3509
3510 /*
3511 * Reset the processor.
3512 */
3513 cs461x_reset(card);
3514
3515 cs461x_proc_stop(card);
3516
3517 /*
3518 * Power down the DAC and ADC. For now leave the other areas on.
3519 */
3520 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x0300);
3521
3522 /*
3523 * Power down the PLL.
3524 */
3525 cs461x_pokeBA0(card, BA0_CLKCR1, 0);
3526
3527 /*
3528 * Turn off the Processor by turning off the software clock enable flag in
3529 * the clock control register.
3530 */
3531 tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE;
3532 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
3533
3534 card->active_ctrl(card,-1);
3535
3536 card->pm.flags &= ~CS46XX_PM_SUSPENDING;
3537 card->pm.flags |= CS46XX_PM_SUSPENDED;
3538
3539 printpm(card);
3540
3541 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3542 printk("cs46xx: cs46xx_suspend()- flags=0x%x\n",
3543 (unsigned)card->pm.flags));
3544 return 0;
3545}
3546
3547static int cs46xx_resume(struct cs_card *card)
3548{
3549 int i;
3550
3551 CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
3552 printk( "cs46xx: cs46xx_resume()+ flags=0x%x\n",
3553 (unsigned)card->pm.flags));
Jesper Juhl2eebb192006-06-23 02:05:26 -07003554 if (!(card->pm.flags & CS46XX_PM_SUSPENDED)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 CS_DBGOUT(CS_PM | CS_ERROR, 2,
3556 printk("cs46xx: cs46xx_resume() unable to resume, not SUSPENDED\n"));
3557 return 1;
3558 }
3559 card->pm.flags |= CS46XX_PM_RESUMING;
3560 card->pm.flags &= ~CS46XX_PM_SUSPENDED;
3561 printpm(card);
3562 card->active_ctrl(card, 1);
3563
Jesper Juhl2eebb192006-06-23 02:05:26 -07003564 for (i = 0; i < 5; i++) {
3565 if (cs_hardware_init(card) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
3567 "cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n"));
3568 mdelay(10 * cs_laptop_wait);
3569 cs461x_reset(card);
3570 continue;
3571 }
3572 break;
3573 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003574 if (i >= 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
3576 "cs46xx: cs46xx_resume()- cs_hardware_init() failed, retried %d times.\n",i));
3577 return 0;
3578 }
3579
Jesper Juhl2eebb192006-06-23 02:05:26 -07003580 if (cs46xx_restart_part(card)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
3582 "cs46xx: cs46xx_resume(): cs46xx_restart_part() returned error\n"));
3583 }
3584
3585 card->active_ctrl(card, -1);
3586
3587 CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=0x%x\n",
3588 (unsigned)card->pm.flags));
3589 return 0;
3590}
3591
3592static /*const*/ struct file_operations cs461x_fops = {
3593 CS_OWNER CS_THIS_MODULE
3594 .llseek = no_llseek,
3595 .read = cs_read,
3596 .write = cs_write,
3597 .poll = cs_poll,
3598 .ioctl = cs_ioctl,
3599 .mmap = cs_mmap,
3600 .open = cs_open,
3601 .release = cs_release,
3602};
3603
3604/* Write AC97 codec registers */
3605
3606
3607static u16 _cs_ac97_get(struct ac97_codec *dev, u8 reg)
3608{
3609 struct cs_card *card = dev->private_data;
3610 int count,loopcnt;
3611 unsigned int tmp;
3612 u16 ret;
3613
3614 /*
3615 * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
3616 * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97
3617 * 3. Write ACCTL = Control Register = 460h for initiating the write
3618 * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
3619 * 5. if DCV not cleared, break and return error
3620 * 6. Read ACSTS = Status Register = 464h, check VSTS bit
3621 */
3622
3623 cs461x_peekBA0(card, BA0_ACSDA);
3624
3625 /*
3626 * Setup the AC97 control registers on the CS461x to send the
3627 * appropriate command to the AC97 to perform the read.
3628 * ACCAD = Command Address Register = 46Ch
3629 * ACCDA = Command Data Register = 470h
3630 * ACCTL = Control Register = 460h
3631 * set DCV - will clear when process completed
3632 * set CRW - Read command
3633 * set VFRM - valid frame enabled
3634 * set ESYN - ASYNC generation enabled
3635 * set RSTN - ARST# inactive, AC97 codec not reset
3636 */
3637
3638 cs461x_pokeBA0(card, BA0_ACCAD, reg);
3639 cs461x_pokeBA0(card, BA0_ACCDA, 0);
3640 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW |
3641 ACCTL_VFRM | ACCTL_ESYN |
3642 ACCTL_RSTN);
3643
3644
3645 /*
3646 * Wait for the read to occur.
3647 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003648 if (!(card->pm.flags & CS46XX_PM_IDLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 loopcnt = 2000;
3650 else
3651 loopcnt = 500 * cs_laptop_wait;
3652 loopcnt *= cs_laptop_wait;
3653 for (count = 0; count < loopcnt; count++) {
3654 /*
3655 * First, we want to wait for a short time.
3656 */
3657 udelay(10 * cs_laptop_wait);
3658 /*
3659 * Now, check to see if the read has completed.
3660 * ACCTL = 460h, DCV should be reset by now and 460h = 17h
3661 */
3662 if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV))
3663 break;
3664 }
3665
3666 /*
3667 * Make sure the read completed.
3668 */
3669 if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
3670 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
3671 "cs46xx: AC'97 read problem (ACCTL_DCV), reg = 0x%x returning 0xffff\n", reg));
3672 return 0xffff;
3673 }
3674
3675 /*
3676 * Wait for the valid status bit to go active.
3677 */
3678
Jesper Juhl2eebb192006-06-23 02:05:26 -07003679 if (!(card->pm.flags & CS46XX_PM_IDLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 loopcnt = 2000;
3681 else
3682 loopcnt = 1000;
3683 loopcnt *= cs_laptop_wait;
3684 for (count = 0; count < loopcnt; count++) {
3685 /*
3686 * Read the AC97 status register.
3687 * ACSTS = Status Register = 464h
3688 * VSTS - Valid Status
3689 */
3690 if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)
3691 break;
3692 udelay(10 * cs_laptop_wait);
3693 }
3694
3695 /*
3696 * Make sure we got valid status.
3697 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003698 if (!((tmp = cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 CS_DBGOUT(CS_ERROR, 2, printk(KERN_WARNING
3700 "cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x 0xffff \n",
3701 reg, tmp));
3702 return 0xffff;
3703 }
3704
3705 /*
3706 * Read the data returned from the AC97 register.
3707 * ACSDA = Status Data Register = 474h
3708 */
3709 CS_DBGOUT(CS_FUNCTION, 9, printk(KERN_INFO
3710 "cs46xx: cs_ac97_get() reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n",
3711 reg, cs461x_peekBA0(card, BA0_ACSDA),
3712 cs461x_peekBA0(card, BA0_ACCAD)));
3713 ret = cs461x_peekBA0(card, BA0_ACSDA);
3714 return ret;
3715}
3716
3717static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg)
3718{
3719 u16 ret;
3720 struct cs_card *card = dev->private_data;
3721
3722 spin_lock(&card->ac97_lock);
3723 ret = _cs_ac97_get(dev, reg);
3724 spin_unlock(&card->ac97_lock);
3725 return ret;
3726}
3727
3728static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
3729{
3730 struct cs_card *card = dev->private_data;
3731 int count;
3732 int val2 = 0;
3733
3734 spin_lock(&card->ac97_lock);
3735
Jesper Juhl2eebb192006-06-23 02:05:26 -07003736 if (reg == AC97_CD_VOL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 val2 = _cs_ac97_get(dev, AC97_CD_VOL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003738
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 /*
3740 * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
3741 * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97
3742 * 3. Write ACCTL = Control Register = 460h for initiating the write
3743 * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h
3744 * 5. if DCV not cleared, break and return error
3745 */
3746
3747 /*
3748 * Setup the AC97 control registers on the CS461x to send the
3749 * appropriate command to the AC97 to perform the read.
3750 * ACCAD = Command Address Register = 46Ch
3751 * ACCDA = Command Data Register = 470h
3752 * ACCTL = Control Register = 460h
3753 * set DCV - will clear when process completed
3754 * reset CRW - Write command
3755 * set VFRM - valid frame enabled
3756 * set ESYN - ASYNC generation enabled
3757 * set RSTN - ARST# inactive, AC97 codec not reset
3758 */
3759 cs461x_pokeBA0(card, BA0_ACCAD, reg);
3760 cs461x_pokeBA0(card, BA0_ACCDA, val);
3761 cs461x_peekBA0(card, BA0_ACCTL);
3762 cs461x_pokeBA0(card, BA0_ACCTL, 0 | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
3763 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM |
3764 ACCTL_ESYN | ACCTL_RSTN);
3765 for (count = 0; count < 1000; count++) {
3766 /*
3767 * First, we want to wait for a short time.
3768 */
3769 udelay(10 * cs_laptop_wait);
3770 /*
3771 * Now, check to see if the write has completed.
3772 * ACCTL = 460h, DCV should be reset by now and 460h = 07h
3773 */
3774 if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV))
3775 break;
3776 }
3777 /*
3778 * Make sure the write completed.
3779 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003780 if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
3782 "cs46xx: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val));
3783 }
3784
3785 spin_unlock(&card->ac97_lock);
3786
3787 /*
3788 * Adjust power if the mixer is selected/deselected according
3789 * to the CD.
3790 *
3791 * IF the CD is a valid input source (mixer or direct) AND
3792 * the CD is not muted THEN power is needed
3793 *
3794 * We do two things. When record select changes the input to
3795 * add/remove the CD we adjust the power count if the CD is
3796 * unmuted.
3797 *
3798 * When the CD mute changes we adjust the power level if the
3799 * CD was a valid input.
3800 *
3801 * We also check for CD volume != 0, as the CD mute isn't
3802 * normally tweaked from userspace.
3803 */
3804
3805 /* CD mute change ? */
3806
Jesper Juhl2eebb192006-06-23 02:05:26 -07003807 if (reg == AC97_CD_VOL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 /* Mute bit change ? */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003809 if ((val2^val) & 0x8000 ||
3810 ((val2 == 0x1f1f || val == 0x1f1f) && val2 != val)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811 /* This is a hack but its cleaner than the alternatives.
3812 Right now card->ac97_codec[0] might be NULL as we are
3813 still doing codec setup. This does an early assignment
3814 to avoid the problem if it occurs */
3815
Jesper Juhl2eebb192006-06-23 02:05:26 -07003816 if (card->ac97_codec[0] == NULL)
3817 card->ac97_codec[0] = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818
3819 /* Mute on */
Jesper Juhl2eebb192006-06-23 02:05:26 -07003820 if (val & 0x8000 || val == 0x1f1f)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 card->amplifier_ctrl(card, -1);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003822 else { /* Mute off power on */
3823 if (card->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 card->amp_init(card);
3825 card->amplifier_ctrl(card, 1);
3826 }
3827 }
3828 }
3829}
3830
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831/* OSS /dev/mixer file operation methods */
3832
3833static int cs_open_mixdev(struct inode *inode, struct file *file)
3834{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003835 int i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003837 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 struct list_head *entry;
3839 unsigned int tmp;
3840
3841 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
3842 printk(KERN_INFO "cs46xx: cs_open_mixdev()+\n"));
3843
Jesper Juhl2eebb192006-06-23 02:05:26 -07003844 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 card = list_entry(entry, struct cs_card, list);
3846 for (i = 0; i < NR_AC97; i++)
3847 if (card->ac97_codec[i] != NULL &&
3848 card->ac97_codec[i]->dev_mixer == minor)
3849 goto match;
3850 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003851 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
3853 printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
3854 return -ENODEV;
3855 }
3856 match:
Jesper Juhl2eebb192006-06-23 02:05:26 -07003857 if (!card->ac97_codec[i])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 return -ENODEV;
3859 file->private_data = card->ac97_codec[i];
3860
3861 card->active_ctrl(card,1);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003862 if (!CS_IN_USE(&card->mixer_use_cnt)) {
3863 if ((tmp = cs46xx_powerup(card, CS_POWER_MIXVON))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003865 "cs46xx: cs_open_mixdev() powerup failure (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 return -EIO;
3867 }
3868 }
3869 card->amplifier_ctrl(card, 1);
3870 CS_INC_USE_COUNT(&card->mixer_use_cnt);
3871 CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
3872 printk(KERN_INFO "cs46xx: cs_open_mixdev()- 0\n"));
3873 return nonseekable_open(inode, file);
3874}
3875
3876static int cs_release_mixdev(struct inode *inode, struct file *file)
3877{
3878 unsigned int minor = iminor(inode);
Jesper Juhl2eebb192006-06-23 02:05:26 -07003879 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 struct list_head *entry;
3881 int i;
3882 unsigned int tmp;
3883
3884 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
3885 printk(KERN_INFO "cs46xx: cs_release_mixdev()+\n"));
3886 list_for_each(entry, &cs46xx_devs)
3887 {
3888 card = list_entry(entry, struct cs_card, list);
3889 for (i = 0; i < NR_AC97; i++)
3890 if (card->ac97_codec[i] != NULL &&
3891 card->ac97_codec[i]->dev_mixer == minor)
3892 goto match;
3893 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003894 if (!card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
3896 printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
3897 return -ENODEV;
3898 }
3899match:
Jesper Juhl2eebb192006-06-23 02:05:26 -07003900 if (!CS_DEC_AND_TEST(&card->mixer_use_cnt)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
3902 printk(KERN_INFO "cs46xx: cs_release_mixdev()- no powerdown, usecnt>0\n"));
3903 card->active_ctrl(card, -1);
3904 card->amplifier_ctrl(card, -1);
3905 return 0;
3906 }
3907/*
3908* ok, no outstanding mixer opens, so powerdown.
3909*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07003910 if ((tmp = cs461x_powerdown(card, CS_POWER_MIXVON, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003912 "cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n", tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 card->active_ctrl(card, -1);
3914 card->amplifier_ctrl(card, -1);
3915 return -EIO;
3916 }
3917 card->active_ctrl(card, -1);
3918 card->amplifier_ctrl(card, -1);
3919 CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
3920 printk(KERN_INFO "cs46xx: cs_release_mixdev()- 0\n"));
3921 return 0;
3922}
3923
3924static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
Jesper Juhl2eebb192006-06-23 02:05:26 -07003925 unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926{
Jesper Juhl2eebb192006-06-23 02:05:26 -07003927 struct ac97_codec *codec = file->private_data;
3928 struct cs_card *card = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 struct list_head *entry;
3930 unsigned long __user *p = (long __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931#if CSDEBUG_INTERFACE
3932 int val;
3933
Jesper Juhl2eebb192006-06-23 02:05:26 -07003934 if ( (cmd == SOUND_MIXER_CS_GETDBGMASK) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 (cmd == SOUND_MIXER_CS_SETDBGMASK) ||
3936 (cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
3937 (cmd == SOUND_MIXER_CS_SETDBGLEVEL) ||
Jesper Juhl2eebb192006-06-23 02:05:26 -07003938 (cmd == SOUND_MIXER_CS_APM)) {
3939 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940 case SOUND_MIXER_CS_GETDBGMASK:
3941 return put_user(cs_debugmask, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 case SOUND_MIXER_CS_GETDBGLEVEL:
3943 return put_user(cs_debuglevel, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 case SOUND_MIXER_CS_SETDBGMASK:
3945 if (get_user(val, p))
3946 return -EFAULT;
3947 cs_debugmask = val;
3948 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 case SOUND_MIXER_CS_SETDBGLEVEL:
3950 if (get_user(val, p))
3951 return -EFAULT;
3952 cs_debuglevel = val;
3953 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 case SOUND_MIXER_CS_APM:
3955 if (get_user(val, p))
3956 return -EFAULT;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003957 if (val == CS_IOCTL_CMD_SUSPEND) {
3958 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 card = list_entry(entry, struct cs_card, list);
Pavel Machek2a569572005-07-07 17:56:40 -07003960 cs46xx_suspend(card, PMSG_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 }
3962
Jesper Juhl2eebb192006-06-23 02:05:26 -07003963 } else if (val == CS_IOCTL_CMD_RESUME) {
3964 list_for_each(entry, &cs46xx_devs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 card = list_entry(entry, struct cs_card, list);
3966 cs46xx_resume(card);
3967 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07003968 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
3970 "cs46xx: mixer_ioctl(): invalid APM cmd (%d)\n",
3971 val));
3972 }
3973 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 default:
3975 CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07003976 "cs46xx: mixer_ioctl(): ERROR unknown debug cmd\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 return 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07003978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 }
3980#endif
3981 return codec->mixer_ioctl(codec, cmd, arg);
3982}
3983
3984static /*const*/ struct file_operations cs_mixer_fops = {
3985 CS_OWNER CS_THIS_MODULE
3986 .llseek = no_llseek,
3987 .ioctl = cs_ioctl_mixdev,
3988 .open = cs_open_mixdev,
3989 .release = cs_release_mixdev,
3990};
3991
3992/* AC97 codec initialisation. */
3993static int __init cs_ac97_init(struct cs_card *card)
3994{
3995 int num_ac97 = 0;
3996 int ready_2nd = 0;
3997 struct ac97_codec *codec;
3998 u16 eid;
3999
4000 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4001 "cs46xx: cs_ac97_init()+\n") );
4002
4003 for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
4004 if ((codec = ac97_alloc_codec()) == NULL)
4005 return -ENOMEM;
4006
4007 /* initialize some basic codec information, other fields will be filled
4008 in ac97_probe_codec */
4009 codec->private_data = card;
4010 codec->id = num_ac97;
4011
4012 codec->codec_read = cs_ac97_get;
4013 codec->codec_write = cs_ac97_set;
4014
Jesper Juhl2eebb192006-06-23 02:05:26 -07004015 if (ac97_probe_codec(codec) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4017 "cs46xx: cs_ac97_init()- codec number %d not found\n",
4018 num_ac97) );
4019 card->ac97_codec[num_ac97] = NULL;
4020 break;
4021 }
4022 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07004023 "cs46xx: cs_ac97_init() found codec %d\n",num_ac97));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024
4025 eid = cs_ac97_get(codec, AC97_EXTENDED_ID);
4026
Jesper Juhl2eebb192006-06-23 02:05:26 -07004027 if (eid == 0xFFFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 printk(KERN_WARNING "cs46xx: codec %d not present\n",num_ac97);
4029 ac97_release_codec(codec);
4030 break;
4031 }
4032
4033 card->ac97_features = eid;
4034
4035 if ((codec->dev_mixer = register_sound_mixer(&cs_mixer_fops, -1)) < 0) {
4036 printk(KERN_ERR "cs46xx: couldn't register mixer!\n");
4037 ac97_release_codec(codec);
4038 break;
4039 }
4040 card->ac97_codec[num_ac97] = codec;
4041
4042 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4043 "cs46xx: cs_ac97_init() ac97_codec[%d] set to %p\n",
4044 (unsigned int)num_ac97,
4045 codec));
4046 /* if there is no secondary codec at all, don't probe any more */
4047 if (!ready_2nd)
4048 {
4049 num_ac97 += 1;
4050 break;
4051 }
4052 }
4053 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4054 "cs46xx: cs_ac97_init()- %d\n", (unsigned int)num_ac97));
4055 return num_ac97;
4056}
4057
4058/*
4059 * load the static image into the DSP
4060 */
4061#include "cs461x_image.h"
4062static void cs461x_download_image(struct cs_card *card)
4063{
4064 unsigned i, j, temp1, temp2, offset, count;
4065 unsigned char __iomem *pBA1 = ioremap(card->ba1_addr, 0x40000);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004066 for (i = 0; i < CLEAR__COUNT; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 offset = ClrStat[i].BA1__DestByteOffset;
4068 count = ClrStat[i].BA1__SourceSize;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004069 for (temp1 = offset; temp1 < (offset + count); temp1 += 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 writel(0, pBA1+temp1);
4071 }
4072
Jesper Juhl2eebb192006-06-23 02:05:26 -07004073 for (i = 0; i < FILL__COUNT; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 temp2 = FillStat[i].Offset;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004075 for (j = 0; j < (FillStat[i].Size) / 4; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 temp1 = (FillStat[i]).pFill[j];
Jesper Juhl2eebb192006-06-23 02:05:26 -07004077 writel(temp1, pBA1+temp2 + j * 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 }
4079 }
4080 iounmap(pBA1);
4081}
4082
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083/*
4084 * Chip reset
4085 */
4086
4087static void cs461x_reset(struct cs_card *card)
4088{
4089 int idx;
4090
4091 /*
4092 * Write the reset bit of the SP control register.
4093 */
4094 cs461x_poke(card, BA1_SPCR, SPCR_RSTSP);
4095
4096 /*
4097 * Write the control register.
4098 */
4099 cs461x_poke(card, BA1_SPCR, SPCR_DRQEN);
4100
4101 /*
4102 * Clear the trap registers.
4103 */
4104 for (idx = 0; idx < 8; idx++) {
4105 cs461x_poke(card, BA1_DREG, DREG_REGID_TRAP_SELECT + idx);
4106 cs461x_poke(card, BA1_TWPR, 0xFFFF);
4107 }
4108 cs461x_poke(card, BA1_DREG, 0);
4109
4110 /*
4111 * Set the frame timer to reflect the number of cycles per frame.
4112 */
4113 cs461x_poke(card, BA1_FRMT, 0xadf);
4114}
4115
4116static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type)
4117{
4118 int idx, loop, startfifo=0, endfifo=0, powerdown1 = 0;
4119 unsigned int tmp;
4120
4121 /*
4122 * See if the devices are powered down. If so, we must power them up first
4123 * or they will not respond.
4124 */
4125 if (!((tmp = cs461x_peekBA0(card, BA0_CLKCR1)) & CLKCR1_SWCE)) {
4126 cs461x_pokeBA0(card, BA0_CLKCR1, tmp | CLKCR1_SWCE);
4127 powerdown1 = 1;
4128 }
4129
4130 /*
4131 * We want to clear out the serial port FIFOs so we don't end up playing
4132 * whatever random garbage happens to be in them. We fill the sample FIFOS
4133 * with zero (silence).
4134 */
4135 cs461x_pokeBA0(card, BA0_SERBWP, 0);
4136
4137 /*
4138 * Check for which FIFO locations to clear, if we are currently
4139 * playing or capturing then we don't want to put in 128 bytes of
4140 * "noise".
4141 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004142 if (type & CS_TYPE_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 startfifo = 128;
4144 endfifo = 256;
4145 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004146 if (type & CS_TYPE_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 startfifo = 0;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004148 if (!endfifo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 endfifo = 128;
4150 }
4151 /*
4152 * Fill sample FIFO locations (256 locations total).
4153 */
4154 for (idx = startfifo; idx < endfifo; idx++) {
4155 /*
4156 * Make sure the previous FIFO write operation has completed.
4157 */
4158 for (loop = 0; loop < 5; loop++) {
4159 udelay(50);
4160 if (!(cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY))
4161 break;
4162 }
4163 if (cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY) {
4164 if (powerdown1)
4165 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
4166 }
4167 /*
4168 * Write the serial port FIFO index.
4169 */
4170 cs461x_pokeBA0(card, BA0_SERBAD, idx);
4171 /*
4172 * Tell the serial port to load the new value into the FIFO location.
4173 */
4174 cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC);
4175 }
4176 /*
4177 * Now, if we powered up the devices, then power them back down again.
4178 * This is kinda ugly, but should never happen.
4179 */
4180 if (powerdown1)
4181 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
4182}
4183
4184
4185static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag)
4186{
4187 int count;
4188 unsigned int tmp=0,muted=0;
4189
4190 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
4191 "cs46xx: cs461x_powerdown()+ type=0x%x\n",type));
Jesper Juhl2eebb192006-06-23 02:05:26 -07004192 if (!cs_powerdown && !suspendflag) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4194 "cs46xx: cs461x_powerdown() DISABLED exiting\n"));
4195 return 0;
4196 }
4197 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
4198 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4199 "cs46xx: cs461x_powerdown() powerdown reg=0x%x\n",tmp));
4200/*
4201* if powering down only the VREF, and not powering down the DAC/ADC,
4202* then do not power down the VREF, UNLESS both the DAC and ADC are not
4203* currently powered down. If powering down DAC and ADC, then
4204* it is possible to power down the VREF (ON).
4205*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07004206 if (((type & CS_POWER_MIXVON) &&
4207 (!(type & CS_POWER_ADC) || (!(type & CS_POWER_DAC))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 &&
4209 ((tmp & CS_AC97_POWER_CONTROL_ADC_ON) ||
Jesper Juhl2eebb192006-06-23 02:05:26 -07004210 (tmp & CS_AC97_POWER_CONTROL_DAC_ON))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4212 "cs46xx: cs461x_powerdown()- 0 unable to powerdown. tmp=0x%x\n",tmp));
4213 return 0;
4214 }
4215/*
4216* for now, always keep power to the mixer block.
4217* not sure why it's a problem but it seems to be if we power off.
4218*/
4219 type &= ~CS_POWER_MIXVON;
4220 type &= ~CS_POWER_MIXVOFF;
4221
4222 /*
4223 * Power down indicated areas.
4224 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004225 if (type & CS_POWER_MIXVOFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226
4227 CS_DBGOUT(CS_FUNCTION, 4,
4228 printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVOFF\n"));
4229 /*
4230 * Power down the MIXER (VREF ON) on the AC97 card.
4231 */
4232 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004233 if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON) {
4234 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004236 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 }
4238 tmp |= CS_AC97_POWER_CONTROL_MIXVOFF;
4239 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4240 /*
4241 * Now, we wait until we sample a ready state.
4242 */
4243 for (count = 0; count < 32; count++) {
4244 /*
4245 * First, lets wait a short while to let things settle out a
4246 * bit, and to prevent retrying the read too quickly.
4247 */
4248 udelay(500);
4249
4250 /*
4251 * Read the current state of the power control register.
4252 */
4253 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4254 CS_AC97_POWER_CONTROL_MIXVOFF_ON))
4255 break;
4256 }
4257
4258 /*
4259 * Check the status..
4260 */
4261 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004262 CS_AC97_POWER_CONTROL_MIXVOFF_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4264 "cs46xx: powerdown MIXVOFF failed\n"));
4265 return 1;
4266 }
4267 }
4268 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004269 if (type & CS_POWER_MIXVON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270
4271 CS_DBGOUT(CS_FUNCTION, 4,
4272 printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVON\n"));
4273 /*
4274 * Power down the MIXER (VREF ON) on the AC97 card.
4275 */
4276 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004277 if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON) {
4278 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004280 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 }
4282 tmp |= CS_AC97_POWER_CONTROL_MIXVON;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004283 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 /*
4285 * Now, we wait until we sample a ready state.
4286 */
4287 for (count = 0; count < 32; count++) {
4288 /*
4289 * First, lets wait a short while to let things settle out a
4290 * bit, and to prevent retrying the read too quickly.
4291 */
4292 udelay(500);
4293
4294 /*
4295 * Read the current state of the power control register.
4296 */
4297 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4298 CS_AC97_POWER_CONTROL_MIXVON_ON))
4299 break;
4300 }
4301
4302 /*
4303 * Check the status..
4304 */
4305 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004306 CS_AC97_POWER_CONTROL_MIXVON_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4308 "cs46xx: powerdown MIXVON failed\n"));
4309 return 1;
4310 }
4311 }
4312 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004313 if (type & CS_POWER_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 /*
4315 * Power down the ADC on the AC97 card.
4316 */
4317 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs461x_powerdown()+ ADC\n"));
4318 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004319 if (tmp & CS_AC97_POWER_CONTROL_ADC_ON) {
4320 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004322 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 }
4324 tmp |= CS_AC97_POWER_CONTROL_ADC;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004325 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326
4327 /*
4328 * Now, we wait until we sample a ready state.
4329 */
4330 for (count = 0; count < 32; count++) {
4331 /*
4332 * First, lets wait a short while to let things settle out a
4333 * bit, and to prevent retrying the read too quickly.
4334 */
4335 udelay(500);
4336
4337 /*
4338 * Read the current state of the power control register.
4339 */
4340 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4341 CS_AC97_POWER_CONTROL_ADC_ON))
4342 break;
4343 }
4344
4345 /*
4346 * Check the status..
4347 */
4348 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004349 CS_AC97_POWER_CONTROL_ADC_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4351 "cs46xx: powerdown ADC failed\n"));
4352 return 1;
4353 }
4354 }
4355 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004356 if (type & CS_POWER_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 /*
4358 * Power down the DAC on the AC97 card.
4359 */
4360
4361 CS_DBGOUT(CS_FUNCTION, 4,
4362 printk(KERN_INFO "cs46xx: cs461x_powerdown()+ DAC\n"));
4363 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004364 if (tmp & CS_AC97_POWER_CONTROL_DAC_ON) {
4365 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004367 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 }
4369 tmp |= CS_AC97_POWER_CONTROL_DAC;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004370 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 /*
4372 * Now, we wait until we sample a ready state.
4373 */
4374 for (count = 0; count < 32; count++) {
4375 /*
4376 * First, lets wait a short while to let things settle out a
4377 * bit, and to prevent retrying the read too quickly.
4378 */
4379 udelay(500);
4380
4381 /*
4382 * Read the current state of the power control register.
4383 */
4384 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4385 CS_AC97_POWER_CONTROL_DAC_ON))
4386 break;
4387 }
4388
4389 /*
4390 * Check the status..
4391 */
4392 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004393 CS_AC97_POWER_CONTROL_DAC_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4395 "cs46xx: powerdown DAC failed\n"));
4396 return 1;
4397 }
4398 }
4399 }
4400 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004401 if (muted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 cs_mute(card, CS_FALSE);
4403 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
4404 "cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp));
4405 return 0;
4406}
4407
4408static int cs46xx_powerup(struct cs_card *card, unsigned int type)
4409{
4410 int count;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004411 unsigned int tmp = 0, muted = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412
4413 CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
4414 "cs46xx: cs46xx_powerup()+ type=0x%x\n",type));
4415 /*
4416 * check for VREF and powerup if need to.
4417 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004418 if (type & CS_POWER_MIXVON)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 type |= CS_POWER_MIXVOFF;
Jesper Juhl2eebb192006-06-23 02:05:26 -07004420 if (type & (CS_POWER_DAC | CS_POWER_ADC))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF;
4422
4423 /*
4424 * Power up indicated areas.
4425 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004426 if (type & CS_POWER_MIXVOFF) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427
4428 CS_DBGOUT(CS_FUNCTION, 4,
4429 printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVOFF\n"));
4430 /*
4431 * Power up the MIXER (VREF ON) on the AC97 card.
4432 */
4433 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004434 if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)) {
4435 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004437 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 }
4439 tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF;
4440 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4441 /*
4442 * Now, we wait until we sample a ready state.
4443 */
4444 for (count = 0; count < 32; count++) {
4445 /*
4446 * First, lets wait a short while to let things settle out a
4447 * bit, and to prevent retrying the read too quickly.
4448 */
4449 udelay(500);
4450
4451 /*
4452 * Read the current state of the power control register.
4453 */
4454 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4455 CS_AC97_POWER_CONTROL_MIXVOFF_ON)
4456 break;
4457 }
4458
4459 /*
4460 * Check the status..
4461 */
4462 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004463 CS_AC97_POWER_CONTROL_MIXVOFF_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4465 "cs46xx: powerup MIXVOFF failed\n"));
4466 return 1;
4467 }
4468 }
4469 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004470 if(type & CS_POWER_MIXVON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471
4472 CS_DBGOUT(CS_FUNCTION, 4,
4473 printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVON\n"));
4474 /*
4475 * Power up the MIXER (VREF ON) on the AC97 card.
4476 */
4477 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004478 if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)) {
4479 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004481 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 }
4483 tmp &= ~CS_AC97_POWER_CONTROL_MIXVON;
4484 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4485 /*
4486 * Now, we wait until we sample a ready state.
4487 */
4488 for (count = 0; count < 32; count++) {
4489 /*
4490 * First, lets wait a short while to let things settle out a
4491 * bit, and to prevent retrying the read too quickly.
4492 */
4493 udelay(500);
4494
4495 /*
4496 * Read the current state of the power control register.
4497 */
4498 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4499 CS_AC97_POWER_CONTROL_MIXVON_ON)
4500 break;
4501 }
4502
4503 /*
4504 * Check the status..
4505 */
4506 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004507 CS_AC97_POWER_CONTROL_MIXVON_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4509 "cs46xx: powerup MIXVON failed\n"));
4510 return 1;
4511 }
4512 }
4513 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004514 if (type & CS_POWER_ADC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 /*
4516 * Power up the ADC on the AC97 card.
4517 */
4518 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs46xx_powerup()+ ADC\n"));
4519 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004520 if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON)) {
4521 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004523 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 }
4525 tmp &= ~CS_AC97_POWER_CONTROL_ADC;
4526 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4527
4528 /*
4529 * Now, we wait until we sample a ready state.
4530 */
4531 for (count = 0; count < 32; count++) {
4532 /*
4533 * First, lets wait a short while to let things settle out a
4534 * bit, and to prevent retrying the read too quickly.
4535 */
4536 udelay(500);
4537
4538 /*
4539 * Read the current state of the power control register.
4540 */
4541 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4542 CS_AC97_POWER_CONTROL_ADC_ON)
4543 break;
4544 }
4545
4546 /*
4547 * Check the status..
4548 */
4549 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004550 CS_AC97_POWER_CONTROL_ADC_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4552 "cs46xx: powerup ADC failed\n"));
4553 return 1;
4554 }
4555 }
4556 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004557 if (type & CS_POWER_DAC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 /*
4559 * Power up the DAC on the AC97 card.
4560 */
4561
4562 CS_DBGOUT(CS_FUNCTION, 4,
4563 printk(KERN_INFO "cs46xx: cs46xx_powerup()+ DAC\n"));
4564 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004565 if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON)) {
4566 if (!muted) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 cs_mute(card, CS_TRUE);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004568 muted = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 }
4570 tmp &= ~CS_AC97_POWER_CONTROL_DAC;
4571 cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
4572 /*
4573 * Now, we wait until we sample a ready state.
4574 */
4575 for (count = 0; count < 32; count++) {
4576 /*
4577 * First, lets wait a short while to let things settle out a
4578 * bit, and to prevent retrying the read too quickly.
4579 */
4580 udelay(500);
4581
4582 /*
4583 * Read the current state of the power control register.
4584 */
4585 if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
4586 CS_AC97_POWER_CONTROL_DAC_ON)
4587 break;
4588 }
4589
4590 /*
4591 * Check the status..
4592 */
4593 if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
Jesper Juhl2eebb192006-06-23 02:05:26 -07004594 CS_AC97_POWER_CONTROL_DAC_ON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
4596 "cs46xx: powerup DAC failed\n"));
4597 return 1;
4598 }
4599 }
4600 }
4601 tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
Jesper Juhl2eebb192006-06-23 02:05:26 -07004602 if (muted)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 cs_mute(card, CS_FALSE);
4604 CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
4605 "cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp));
4606 return 0;
4607}
4608
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609static void cs461x_proc_start(struct cs_card *card)
4610{
4611 int cnt;
4612
4613 /*
4614 * Set the frame timer to reflect the number of cycles per frame.
4615 */
4616 cs461x_poke(card, BA1_FRMT, 0xadf);
4617 /*
4618 * Turn on the run, run at frame, and DMA enable bits in the local copy of
4619 * the SP control register.
4620 */
4621 cs461x_poke(card, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN);
4622 /*
4623 * Wait until the run at frame bit resets itself in the SP control
4624 * register.
4625 */
4626 for (cnt = 0; cnt < 25; cnt++) {
4627 udelay(50);
4628 if (!(cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR))
4629 break;
4630 }
4631
4632 if (cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR)
4633 printk(KERN_WARNING "cs46xx: SPCR_RUNFR never reset\n");
4634}
4635
4636static void cs461x_proc_stop(struct cs_card *card)
4637{
4638 /*
4639 * Turn off the run, run at frame, and DMA enable bits in the local copy of
4640 * the SP control register.
4641 */
4642 cs461x_poke(card, BA1_SPCR, 0);
4643}
4644
4645static int cs_hardware_init(struct cs_card *card)
4646{
4647 unsigned long end_time;
4648 unsigned int tmp,count;
4649
4650 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4651 "cs46xx: cs_hardware_init()+\n") );
4652 /*
4653 * First, blast the clock control register to zero so that the PLL starts
4654 * out in a known state, and blast the master serial port control register
4655 * to zero so that the serial ports also start out in a known state.
4656 */
4657 cs461x_pokeBA0(card, BA0_CLKCR1, 0);
4658 cs461x_pokeBA0(card, BA0_SERMC1, 0);
4659
4660 /*
4661 * If we are in AC97 mode, then we must set the part to a host controlled
4662 * AC-link. Otherwise, we won't be able to bring up the link.
4663 */
4664 cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_1_03); /* 1.03 card */
4665 /* cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_2_0); */ /* 2.00 card */
4666
4667 /*
4668 * Drive the ARST# pin low for a minimum of 1uS (as defined in the AC97
4669 * spec) and then drive it high. This is done for non AC97 modes since
4670 * there might be logic external to the CS461x that uses the ARST# line
4671 * for a reset.
4672 */
4673 cs461x_pokeBA0(card, BA0_ACCTL, 1);
4674 udelay(50);
4675 cs461x_pokeBA0(card, BA0_ACCTL, 0);
4676 udelay(50);
4677 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN);
4678
4679 /*
4680 * The first thing we do here is to enable sync generation. As soon
4681 * as we start receiving bit clock, we'll start producing the SYNC
4682 * signal.
4683 */
4684 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_ESYN | ACCTL_RSTN);
4685
4686 /*
4687 * Now wait for a short while to allow the AC97 part to start
4688 * generating bit clock (so we don't try to start the PLL without an
4689 * input clock).
4690 */
4691 mdelay(5 * cs_laptop_wait); /* 1 should be enough ?? (and pigs might fly) */
4692
4693 /*
4694 * Set the serial port timing configuration, so that
4695 * the clock control circuit gets its clock from the correct place.
4696 */
4697 cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97);
4698
4699 /*
4700 * The part seems to not be ready for a while after a resume.
4701 * so, if we are resuming, then wait for 700 mils. Note that 600 mils
4702 * is not enough for some platforms! tested on an IBM Thinkpads and
4703 * reference cards.
4704 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004705 if (!(card->pm.flags & CS46XX_PM_IDLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 mdelay(initdelay);
4707 /*
4708 * Write the selected clock control setup to the hardware. Do not turn on
4709 * SWCE yet (if requested), so that the devices clocked by the output of
4710 * PLL are not clocked until the PLL is stable.
4711 */
4712 cs461x_pokeBA0(card, BA0_PLLCC, PLLCC_LPF_1050_2780_KHZ | PLLCC_CDR_73_104_MHZ);
4713 cs461x_pokeBA0(card, BA0_PLLM, 0x3a);
4714 cs461x_pokeBA0(card, BA0_CLKCR2, CLKCR2_PDIVS_8);
4715
4716 /*
4717 * Power up the PLL.
4718 */
4719 cs461x_pokeBA0(card, BA0_CLKCR1, CLKCR1_PLLP);
4720
4721 /*
4722 * Wait until the PLL has stabilized.
4723 */
4724 mdelay(5 * cs_laptop_wait); /* Again 1 should be enough ?? */
4725
4726 /*
4727 * Turn on clocking of the core so that we can setup the serial ports.
4728 */
4729 tmp = cs461x_peekBA0(card, BA0_CLKCR1) | CLKCR1_SWCE;
4730 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
4731
4732 /*
4733 * Fill the serial port FIFOs with silence.
4734 */
4735 cs461x_clear_serial_FIFOs(card,CS_TYPE_DAC | CS_TYPE_ADC);
4736
4737 /*
4738 * Set the serial port FIFO pointer to the first sample in the FIFO.
4739 */
4740 /* cs461x_pokeBA0(card, BA0_SERBSP, 0); */
4741
4742 /*
4743 * Write the serial port configuration to the part. The master
4744 * enable bit is not set until all other values have been written.
4745 */
4746 cs461x_pokeBA0(card, BA0_SERC1, SERC1_SO1F_AC97 | SERC1_SO1EN);
4747 cs461x_pokeBA0(card, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN);
4748 cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
4749
4750
4751 mdelay(5 * cs_laptop_wait); /* Shouldnt be needed ?? */
4752
4753/*
4754* If we are resuming under 2.2.x then we can not schedule a timeout.
4755* so, just spin the CPU.
4756*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07004757 if (card->pm.flags & CS46XX_PM_IDLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 /*
4759 * Wait for the card ready signal from the AC97 card.
4760 */
4761 end_time = jiffies + 3 * (HZ >> 2);
4762 do {
4763 /*
4764 * Read the AC97 status register to see if we've seen a CODEC READY
4765 * signal from the AC97 card.
4766 */
4767 if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
4768 break;
4769 current->state = TASK_UNINTERRUPTIBLE;
4770 schedule_timeout(1);
4771 } while (time_before(jiffies, end_time));
Jesper Juhl2eebb192006-06-23 02:05:26 -07004772 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 for (count = 0; count < 100; count++) {
4774 // First, we want to wait for a short time.
4775 udelay(25 * cs_laptop_wait);
4776
4777 if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
4778 break;
4779 }
4780 }
4781
4782 /*
4783 * Make sure CODEC is READY.
4784 */
4785 if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)) {
4786 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
4787 "cs46xx: create - never read card ready from AC'97\n"));
4788 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
4789 "cs46xx: probably not a bug, try using the CS4232 driver,\n"));
4790 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
4791 "cs46xx: or turn off any automatic Power Management support in the BIOS.\n"));
4792 return -EIO;
4793 }
4794
4795 /*
4796 * Assert the vaid frame signal so that we can start sending commands
4797 * to the AC97 card.
4798 */
4799 cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
4800
Jesper Juhl2eebb192006-06-23 02:05:26 -07004801 if (card->pm.flags & CS46XX_PM_IDLE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 /*
4803 * Wait until we've sampled input slots 3 and 4 as valid, meaning that
4804 * the card is pumping ADC data across the AC-link.
4805 */
4806 end_time = jiffies + 3 * (HZ >> 2);
4807 do {
4808 /*
4809 * Read the input slot valid register and see if input slots 3 and
4810 * 4 are valid yet.
4811 */
4812 if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
4813 break;
4814 current->state = TASK_UNINTERRUPTIBLE;
4815 schedule_timeout(1);
4816 } while (time_before(jiffies, end_time));
Jesper Juhl2eebb192006-06-23 02:05:26 -07004817 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 for (count = 0; count < 100; count++) {
4819 // First, we want to wait for a short time.
4820 udelay(25 * cs_laptop_wait);
4821
4822 if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
4823 break;
4824 }
4825 }
4826 /*
4827 * Make sure input slots 3 and 4 are valid. If not, then return
4828 * an error.
4829 */
4830 if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) != (ACISV_ISV3 | ACISV_ISV4)) {
4831 printk(KERN_WARNING "cs46xx: create - never read ISV3 & ISV4 from AC'97\n");
4832 return -EIO;
4833 }
4834
4835 /*
4836 * Now, assert valid frame and the slot 3 and 4 valid bits. This will
4837 * commense the transfer of digital audio data to the AC97 card.
4838 */
4839 cs461x_pokeBA0(card, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4);
4840
4841 /*
4842 * Turn off the Processor by turning off the software clock enable flag in
4843 * the clock control register.
4844 */
4845 /* tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE; */
4846 /* cs461x_pokeBA0(card, BA0_CLKCR1, tmp); */
4847
4848 /*
4849 * Reset the processor.
4850 */
4851 cs461x_reset(card);
4852
4853 /*
4854 * Download the image to the processor.
4855 */
4856
4857 cs461x_download_image(card);
4858
4859 /*
4860 * Stop playback DMA.
4861 */
4862 tmp = cs461x_peek(card, BA1_PCTL);
4863 card->pctl = tmp & 0xffff0000;
4864 cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
4865
4866 /*
4867 * Stop capture DMA.
4868 */
4869 tmp = cs461x_peek(card, BA1_CCTL);
4870 card->cctl = tmp & 0x0000ffff;
4871 cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
4872
4873 /* initialize AC97 codec and register /dev/mixer */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004874 if (card->pm.flags & CS46XX_PM_IDLE) {
4875 if (cs_ac97_init(card) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
Jesper Juhl2eebb192006-06-23 02:05:26 -07004877 "cs46xx: cs_ac97_init() failure\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 return -EIO;
4879 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004880 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 cs46xx_ac97_resume(card);
4882 }
4883
4884 cs461x_proc_start(card);
4885
4886 /*
4887 * Enable interrupts on the part.
4888 */
4889 cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM);
4890
4891 tmp = cs461x_peek(card, BA1_PFIE);
4892 tmp &= ~0x0000f03f;
4893 cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt enable */
4894
4895 tmp = cs461x_peek(card, BA1_CIE);
4896 tmp &= ~0x0000003f;
4897 tmp |= 0x00000001;
4898 cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt enable */
4899
4900 /*
4901 * If IDLE then Power down the part. We will power components up
4902 * when we need them.
4903 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07004904 if (card->pm.flags & CS46XX_PM_IDLE) {
4905 if (!cs_powerdown) {
4906 if ((tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC |
4907 CS_POWER_MIXVON))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
4909 "cs46xx: cs461x_powerup() failure (0x%x)\n",tmp) );
4910 return -EIO;
4911 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07004912 } else {
4913 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
4914 CS_POWER_MIXVON, CS_FALSE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
4916 "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
4917 return -EIO;
4918 }
4919 }
4920 }
4921 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
4922 "cs46xx: cs_hardware_init()- 0\n"));
4923 return 0;
4924}
4925
4926/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered
4927 until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
4928
4929/*
4930 * Card subid table
4931 */
4932
4933struct cs_card_type
4934{
4935 u16 vendor;
4936 u16 id;
4937 char *name;
4938 void (*amp)(struct cs_card *, int);
4939 void (*amp_init)(struct cs_card *);
4940 void (*active)(struct cs_card *, int);
4941};
4942
4943static struct cs_card_type cards[] = {
4944 {
4945 .vendor = 0x1489,
4946 .id = 0x7001,
4947 .name = "Genius Soundmaker 128 value",
4948 .amp = amp_none,
4949 },
4950 {
4951 .vendor = 0x5053,
4952 .id = 0x3357,
4953 .name = "Voyetra",
4954 .amp = amp_voyetra,
4955 },
4956 {
4957 .vendor = 0x1071,
4958 .id = 0x6003,
4959 .name = "Mitac MI6020/21",
4960 .amp = amp_voyetra,
4961 },
4962 {
4963 .vendor = 0x14AF,
4964 .id = 0x0050,
4965 .name = "Hercules Game Theatre XP",
4966 .amp = amp_hercules,
4967 },
4968 {
4969 .vendor = 0x1681,
4970 .id = 0x0050,
4971 .name = "Hercules Game Theatre XP",
4972 .amp = amp_hercules,
4973 },
4974 {
4975 .vendor = 0x1681,
4976 .id = 0x0051,
4977 .name = "Hercules Game Theatre XP",
4978 .amp = amp_hercules,
4979 },
4980 {
4981 .vendor = 0x1681,
4982 .id = 0x0052,
4983 .name = "Hercules Game Theatre XP",
4984 .amp = amp_hercules,
4985 },
4986 {
4987 .vendor = 0x1681,
4988 .id = 0x0053,
4989 .name = "Hercules Game Theatre XP",
4990 .amp = amp_hercules,
4991 },
4992 {
4993 .vendor = 0x1681,
4994 .id = 0x0054,
4995 .name = "Hercules Game Theatre XP",
4996 .amp = amp_hercules,
4997 },
4998 {
4999 .vendor = 0x1681,
5000 .id = 0xa010,
5001 .name = "Hercules Fortissimo II",
5002 .amp = amp_none,
5003 },
5004 /* Not sure if the 570 needs the clkrun hack */
5005 {
5006 .vendor = PCI_VENDOR_ID_IBM,
5007 .id = 0x0132,
5008 .name = "Thinkpad 570",
5009 .amp = amp_none,
5010 .active = clkrun_hack,
5011 },
5012 {
5013 .vendor = PCI_VENDOR_ID_IBM,
5014 .id = 0x0153,
5015 .name = "Thinkpad 600X/A20/T20",
5016 .amp = amp_none,
5017 .active = clkrun_hack,
5018 },
5019 {
5020 .vendor = PCI_VENDOR_ID_IBM,
5021 .id = 0x1010,
5022 .name = "Thinkpad 600E (unsupported)",
5023 },
5024 {
5025 .name = "Card without SSID set",
5026 },
5027 { 0, },
5028};
5029
5030MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <pcaudio@crystal.cirrus.com>");
5031MODULE_DESCRIPTION("Crystal SoundFusion Audio Support");
5032MODULE_LICENSE("GPL");
5033
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034static const char cs46xx_banner[] = KERN_INFO "Crystal 4280/46xx + AC97 Audio, version " CS46XX_MAJOR_VERSION "." CS46XX_MINOR_VERSION "." CS46XX_ARCH ", " __TIME__ " " __DATE__ "\n";
5035static const char fndmsg[] = KERN_INFO "cs46xx: Found %d audio device(s).\n";
5036
5037static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
5038 const struct pci_device_id *pciid)
5039{
Jesper Juhl2eebb192006-06-23 02:05:26 -07005040 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 u16 ss_card, ss_vendor;
5042 struct cs_card *card;
5043 dma_addr_t dma_mask;
5044 struct cs_card_type *cp = &cards[0];
5045
5046 CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
5047 printk(KERN_INFO "cs46xx: probe()+\n"));
5048
5049 dma_mask = 0xffffffff; /* this enables playback and recording */
5050 if (pci_enable_device(pci_dev)) {
5051 CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
5052 "cs46xx: pci_enable_device() failed\n"));
5053 return -1;
5054 }
5055 if (!RSRCISMEMORYREGION(pci_dev, 0) ||
5056 !RSRCISMEMORYREGION(pci_dev, 1)) {
5057 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
5058 "cs46xx: probe()- Memory region not assigned\n"));
5059 return -1;
5060 }
5061 if (pci_dev->irq == 0) {
5062 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
5063 "cs46xx: probe() IRQ not assigned\n"));
5064 return -1;
5065 }
5066 if (!pci_dma_supported(pci_dev, 0xffffffff)) {
5067 CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
5068 "cs46xx: probe() architecture does not support 32bit PCI busmaster DMA\n"));
5069 return -1;
5070 }
5071 pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
5072 pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card);
5073
5074 if ((card = kmalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) {
5075 printk(KERN_ERR "cs46xx: out of memory\n");
5076 return -ENOMEM;
5077 }
5078 memset(card, 0, sizeof(*card));
5079 card->ba0_addr = RSRCADDRESS(pci_dev, 0);
5080 card->ba1_addr = RSRCADDRESS(pci_dev, 1);
5081 card->pci_dev = pci_dev;
5082 card->irq = pci_dev->irq;
5083 card->magic = CS_CARD_MAGIC;
5084 spin_lock_init(&card->lock);
5085 spin_lock_init(&card->ac97_lock);
5086
5087 pci_set_master(pci_dev);
5088
5089 printk(cs46xx_banner);
5090 printk(KERN_INFO "cs46xx: Card found at 0x%08lx and 0x%08lx, IRQ %d\n",
5091 card->ba0_addr, card->ba1_addr, card->irq);
5092
5093 card->alloc_pcm_channel = cs_alloc_pcm_channel;
5094 card->alloc_rec_pcm_channel = cs_alloc_rec_pcm_channel;
5095 card->free_pcm_channel = cs_free_pcm_channel;
5096 card->amplifier_ctrl = amp_none;
5097 card->active_ctrl = amp_none;
5098
5099 while (cp->name)
5100 {
Jesper Juhl2eebb192006-06-23 02:05:26 -07005101 if (cp->vendor == ss_vendor && cp->id == ss_card) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 card->amplifier_ctrl = cp->amp;
Jesper Juhl2eebb192006-06-23 02:05:26 -07005103 if (cp->active)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 card->active_ctrl = cp->active;
Jesper Juhl2eebb192006-06-23 02:05:26 -07005105 if (cp->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 card->amp_init = cp->amp_init;
5107 break;
5108 }
5109 cp++;
5110 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005111 if (cp->name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112 printk(KERN_INFO "cs46xx: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
5113 ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005114 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115 printk(KERN_INFO "cs46xx: %s (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
5116 cp->name, ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
5117 }
5118
Jesper Juhl2eebb192006-06-23 02:05:26 -07005119 if (card->amplifier_ctrl == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 card->amplifier_ctrl = amp_none;
5121 card->active_ctrl = clkrun_hack;
5122 }
5123
Jesper Juhl2eebb192006-06-23 02:05:26 -07005124 if (external_amp == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 printk(KERN_INFO "cs46xx: Crystal EAPD support forced on.\n");
5126 card->amplifier_ctrl = amp_voyetra;
5127 }
5128
Jesper Juhl2eebb192006-06-23 02:05:26 -07005129 if (thinkpad == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n");
5131 card->active_ctrl = clkrun_hack;
5132 }
5133/*
5134* The thinkpads don't work well without runtime updating on their kernel
5135* delay values (or any laptop with variable CPU speeds really).
5136* so, just to be safe set the init delay to 2100. Eliminates
5137* failures on T21 Thinkpads. remove this code when the udelay
5138* and mdelay kernel code is replaced by a pm timer, or the delays
5139* work well for battery and/or AC power both.
5140*/
Jesper Juhl2eebb192006-06-23 02:05:26 -07005141 if (card->active_ctrl == clkrun_hack) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 initdelay = 2100;
5143 cs_laptop_wait = 5;
5144 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005145 if ((card->active_ctrl == clkrun_hack) && !(powerdown == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146/*
5147* for some currently unknown reason, powering down the DAC and ADC component
5148* blocks on thinkpads causes some funky behavior... distoorrrtion and ac97
5149* codec access problems. probably the serial clock becomes unsynced.
5150* added code to sync the chips back up, but only helped about 70% the time.
5151*/
5152 cs_powerdown = 0;
5153 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005154 if (powerdown == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 cs_powerdown = 0;
5156 card->active_ctrl(card, 1);
5157
5158 /* claim our iospace and irq */
5159
5160 card->ba0 = ioremap_nocache(card->ba0_addr, CS461X_BA0_SIZE);
5161 card->ba1.name.data0 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
5162 card->ba1.name.data1 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
5163 card->ba1.name.pmem = ioremap_nocache(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
5164 card->ba1.name.reg = ioremap_nocache(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
5165
5166 CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO
5167 "cs46xx: card=%p card->ba0=%p\n",card,card->ba0) );
5168 CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO
5169 "cs46xx: card->ba1=%p %p %p %p\n",
5170 card->ba1.name.data0,
5171 card->ba1.name.data1,
5172 card->ba1.name.pmem,
5173 card->ba1.name.reg) );
5174
Jesper Juhl2eebb192006-06-23 02:05:26 -07005175 if (card->ba0 == 0 || card->ba1.name.data0 == 0 ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 card->ba1.name.data1 == 0 || card->ba1.name.pmem == 0 ||
5177 card->ba1.name.reg == 0)
5178 goto fail2;
5179
Thomas Gleixner65ca68b2006-07-01 19:29:46 -07005180 if (request_irq(card->irq, &cs_interrupt, IRQF_SHARED, "cs46xx", card)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 printk(KERN_ERR "cs46xx: unable to allocate irq %d\n", card->irq);
5182 goto fail2;
5183 }
5184 /* register /dev/dsp */
5185 if ((card->dev_audio = register_sound_dsp(&cs461x_fops, -1)) < 0) {
5186 printk(KERN_ERR "cs46xx: unable to register dsp\n");
5187 goto fail;
5188 }
5189
5190 /* register /dev/midi */
Jesper Juhl2eebb192006-06-23 02:05:26 -07005191 if ((card->dev_midi = register_sound_midi(&cs_midi_fops, -1)) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 printk(KERN_ERR "cs46xx: unable to register midi\n");
5193
5194 card->pm.flags |= CS46XX_PM_IDLE;
Jesper Juhl2eebb192006-06-23 02:05:26 -07005195 for (i = 0; i < 5; i++) {
5196 if (cs_hardware_init(card) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 CS_DBGOUT(CS_ERROR, 4, printk(
5198 "cs46xx: ERROR in cs_hardware_init()... retrying\n"));
5199 for (j = 0; j < NR_AC97; j++)
5200 if (card->ac97_codec[j] != NULL) {
5201 unregister_sound_mixer(card->ac97_codec[j]->dev_mixer);
5202 ac97_release_codec(card->ac97_codec[j]);
5203 }
5204 mdelay(10 * cs_laptop_wait);
5205 continue;
5206 }
5207 break;
5208 }
Jesper Juhl2eebb192006-06-23 02:05:26 -07005209 if(i >= 4) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
5211 "cs46xx: cs46xx_probe()- cs_hardware_init() failed, retried %d times.\n",i));
5212 unregister_sound_dsp(card->dev_audio);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005213 if (card->dev_midi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 unregister_sound_midi(card->dev_midi);
5215 goto fail;
5216 }
5217
5218 init_waitqueue_head(&card->midi.open_wait);
Ingo Molnar910f5d22006-03-23 03:00:39 -08005219 mutex_init(&card->midi.open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 init_waitqueue_head(&card->midi.iwait);
5221 init_waitqueue_head(&card->midi.owait);
5222 cs461x_pokeBA0(card, BA0_MIDCR, MIDCR_MRST);
5223 cs461x_pokeBA0(card, BA0_MIDCR, 0);
5224
5225 /*
5226 * Check if we have to init the amplifier, but probably already done
5227 * since the CD logic in the ac97 init code will turn on the ext amp.
5228 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07005229 if (cp->amp_init)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 cp->amp_init(card);
5231 card->active_ctrl(card, -1);
5232
5233 PCI_SET_DRIVER_DATA(pci_dev, card);
5234 PCI_SET_DMA_MASK(pci_dev, dma_mask);
5235 list_add(&card->list, &cs46xx_devs);
5236
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 CS_DBGOUT(CS_PM, 9, printk(KERN_INFO "cs46xx: pm.flags=0x%x card=%p\n",
5238 (unsigned)card->pm.flags,card));
5239
5240 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5241 "cs46xx: probe()- device allocated successfully\n"));
5242 return 0;
5243
5244fail:
5245 free_irq(card->irq, card);
5246fail2:
Jesper Juhl2eebb192006-06-23 02:05:26 -07005247 if (card->ba0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 iounmap(card->ba0);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005249 if (card->ba1.name.data0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 iounmap(card->ba1.name.data0);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005251 if (card->ba1.name.data1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 iounmap(card->ba1.name.data1);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005253 if (card->ba1.name.pmem)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 iounmap(card->ba1.name.pmem);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005255 if (card->ba1.name.reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 iounmap(card->ba1.name.reg);
5257 kfree(card);
5258 CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
5259 "cs46xx: probe()- no device allocated\n"));
5260 return -ENODEV;
5261} // probe_cs46xx
5262
5263// ---------------------------------------------------------------------
5264
5265static void __devexit cs46xx_remove(struct pci_dev *pci_dev)
5266{
5267 struct cs_card *card = PCI_GET_DRIVER_DATA(pci_dev);
5268 int i;
5269 unsigned int tmp;
5270
5271 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5272 "cs46xx: cs46xx_remove()+\n"));
5273
5274 card->active_ctrl(card,1);
5275
5276 tmp = cs461x_peek(card, BA1_PFIE);
5277 tmp &= ~0x0000f03f;
5278 tmp |= 0x00000010;
5279 cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */
5280
5281 tmp = cs461x_peek(card, BA1_CIE);
5282 tmp &= ~0x0000003f;
5283 tmp |= 0x00000011;
5284 cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */
5285
5286 /*
5287 * Stop playback DMA.
5288 */
5289 tmp = cs461x_peek(card, BA1_PCTL);
5290 cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
5291
5292 /*
5293 * Stop capture DMA.
5294 */
5295 tmp = cs461x_peek(card, BA1_CCTL);
5296 cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
5297
5298 /*
5299 * Reset the processor.
5300 */
5301 cs461x_reset(card);
5302
5303 cs461x_proc_stop(card);
5304
5305 /*
5306 * Power down the DAC and ADC. We will power them up (if) when we need
5307 * them.
5308 */
Jesper Juhl2eebb192006-06-23 02:05:26 -07005309 if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
5310 CS_POWER_MIXVON, CS_TRUE))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
5312 "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
5313 }
5314
5315 /*
5316 * Power down the PLL.
5317 */
5318 cs461x_pokeBA0(card, BA0_CLKCR1, 0);
5319
5320 /*
5321 * Turn off the Processor by turning off the software clock enable flag in
5322 * the clock control register.
5323 */
5324 tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE;
5325 cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
5326
5327 card->active_ctrl(card,-1);
5328
5329 /* free hardware resources */
5330 free_irq(card->irq, card);
5331 iounmap(card->ba0);
5332 iounmap(card->ba1.name.data0);
5333 iounmap(card->ba1.name.data1);
5334 iounmap(card->ba1.name.pmem);
5335 iounmap(card->ba1.name.reg);
5336
5337 /* unregister audio devices */
5338 for (i = 0; i < NR_AC97; i++)
5339 if (card->ac97_codec[i] != NULL) {
5340 unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
5341 ac97_release_codec(card->ac97_codec[i]);
5342 }
5343 unregister_sound_dsp(card->dev_audio);
Jesper Juhl2eebb192006-06-23 02:05:26 -07005344 if (card->dev_midi)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 unregister_sound_midi(card->dev_midi);
5346 list_del(&card->list);
5347 kfree(card);
5348 PCI_SET_DRIVER_DATA(pci_dev,NULL);
5349
5350 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5351 "cs46xx: cs46xx_remove()-: remove successful\n"));
5352}
5353
5354enum {
5355 CS46XX_4610 = 0,
5356 CS46XX_4612, /* same as 4630 */
5357 CS46XX_4615, /* same as 4624 */
5358};
5359
5360static struct pci_device_id cs46xx_pci_tbl[] = {
5361 {
5362 .vendor = PCI_VENDOR_ID_CIRRUS,
5363 .device = PCI_DEVICE_ID_CIRRUS_4610,
5364 .subvendor = PCI_ANY_ID,
5365 .subdevice = PCI_ANY_ID,
5366 .driver_data = CS46XX_4610,
5367 },
5368 {
5369 .vendor = PCI_VENDOR_ID_CIRRUS,
5370 .device = PCI_DEVICE_ID_CIRRUS_4612,
5371 .subvendor = PCI_ANY_ID,
5372 .subdevice = PCI_ANY_ID,
5373 .driver_data = CS46XX_4612,
5374 },
5375 {
5376 .vendor = PCI_VENDOR_ID_CIRRUS,
5377 .device = PCI_DEVICE_ID_CIRRUS_4615,
5378 .subvendor = PCI_ANY_ID,
5379 .subdevice = PCI_ANY_ID,
5380 .driver_data = CS46XX_4615,
5381 },
5382 { 0, },
5383};
5384
5385MODULE_DEVICE_TABLE(pci, cs46xx_pci_tbl);
5386
5387static struct pci_driver cs46xx_pci_driver = {
5388 .name = "cs46xx",
5389 .id_table = cs46xx_pci_tbl,
5390 .probe = cs46xx_probe,
5391 .remove = __devexit_p(cs46xx_remove),
5392 .suspend = CS46XX_SUSPEND_TBL,
5393 .resume = CS46XX_RESUME_TBL,
5394};
5395
5396static int __init cs46xx_init_module(void)
5397{
5398 int rtn = 0;
5399 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
5400 "cs46xx: cs46xx_init_module()+ \n"));
Greg Kroah-Hartman46654722005-12-06 15:33:15 -08005401 rtn = pci_register_driver(&cs46xx_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402
Jesper Juhl2eebb192006-06-23 02:05:26 -07005403 if (rtn == -ENODEV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(
5405 "cs46xx: Unable to detect valid cs46xx device\n"));
5406 }
5407
5408 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
5409 printk(KERN_INFO "cs46xx: cs46xx_init_module()- (%d)\n",rtn));
5410 return rtn;
5411}
5412
5413static void __exit cs46xx_cleanup_module(void)
5414{
5415 pci_unregister_driver(&cs46xx_pci_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
5417 printk(KERN_INFO "cs46xx: cleanup_cs46xx() finished\n"));
5418}
5419
5420module_init(cs46xx_init_module);
5421module_exit(cs46xx_cleanup_module);
5422
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423#if CS46XX_ACPI_SUPPORT
5424static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state)
5425{
5426 struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
5427 CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
5428 printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
Pavel Machek2a569572005-07-07 17:56:40 -07005429 cs46xx_suspend(s, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 return 0;
5431}
5432
5433static int cs46xx_resume_tbl(struct pci_dev *pcidev)
5434{
5435 struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
5436 CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
5437 printk(KERN_INFO "cs46xx: cs46xx_resume_tbl request\n"));
5438 cs46xx_resume(s);
5439 return 0;
5440}
5441#endif