| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  	drivers/sound/harmony.c  | 
 | 3 |  | 
 | 4 | 	This is a sound driver for ASP's and Lasi's Harmony sound chip | 
 | 5 | 	and is unlikely to be used for anything other than on a HP PA-RISC. | 
 | 6 |  | 
 | 7 | 	Harmony is found in HP 712s, 715/new and many other GSC based machines. | 
 | 8 | 	On older 715 machines you'll find the technically identical chip  | 
 | 9 | 	called 'Vivace'. Both Harmony and Vicace are supported by this driver. | 
 | 10 |  | 
 | 11 | 	Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex@onefishtwo.ca> | 
 | 12 | 	Copyright 2000-2003 (c) Helge Deller <deller@gmx.de> | 
 | 13 | 	Copyright 2001 (c) Matthieu Delahaye <delahaym@esiee.fr> | 
 | 14 | 	Copyright 2001 (c) Jean-Christophe Vaugeois <vaugeoij@esiee.fr> | 
 | 15 | 	Copyright 2004 (c) Stuart Brady <sdbrady@ntlworld.com> | 
 | 16 |  | 
 | 17 | 				 | 
 | 18 | TODO: | 
 | 19 | 	- fix SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls to | 
 | 20 | 		return the real values | 
 | 21 | 	- add private ioctl for selecting line- or microphone input | 
 | 22 | 		(only one of them is available at the same time) | 
 | 23 | 	- add module parameters | 
 | 24 | 	- implement mmap functionality | 
 | 25 | 	- implement gain meter ? | 
 | 26 | 	- ... | 
 | 27 | */ | 
 | 28 |  | 
 | 29 | #include <linux/delay.h> | 
 | 30 | #include <linux/errno.h> | 
 | 31 | #include <linux/init.h> | 
 | 32 | #include <linux/interrupt.h> | 
 | 33 | #include <linux/ioport.h> | 
 | 34 | #include <linux/types.h> | 
 | 35 | #include <linux/mm.h> | 
 | 36 | #include <linux/pci.h> | 
 | 37 |  | 
 | 38 | #include <asm/parisc-device.h> | 
 | 39 | #include <asm/io.h> | 
 | 40 |  | 
 | 41 | #include "sound_config.h" | 
 | 42 |  | 
 | 43 |  | 
 | 44 | #define PFX "harmony: " | 
 | 45 | #define HARMONY_VERSION "V0.9a" | 
 | 46 |  | 
 | 47 | #undef DEBUG | 
 | 48 | #ifdef DEBUG | 
 | 49 | # define DPRINTK printk  | 
 | 50 | #else | 
 | 51 | # define DPRINTK(x,...) | 
 | 52 | #endif | 
 | 53 |  | 
 | 54 |  | 
 | 55 | #define MAX_BUFS 10		/* maximum number of rotating buffers */ | 
 | 56 | #define HARMONY_BUF_SIZE 4096	/* needs to be a multiple of PAGE_SIZE (4096)! */ | 
 | 57 |  | 
 | 58 | #define CNTL_C		0x80000000 | 
 | 59 | #define	CNTL_ST		0x00000020 | 
 | 60 | #define CNTL_44100	0x00000015	/* HARMONY_SR_44KHZ */ | 
 | 61 | #define CNTL_8000	0x00000008	/* HARMONY_SR_8KHZ */ | 
 | 62 |  | 
 | 63 | #define GAINCTL_HE	0x08000000 | 
 | 64 | #define GAINCTL_LE	0x04000000 | 
 | 65 | #define GAINCTL_SE	0x02000000 | 
 | 66 |  | 
 | 67 | #define DSTATUS_PN	0x00000200 | 
 | 68 | #define DSTATUS_RN	0x00000002 | 
 | 69 |  | 
 | 70 | #define DSTATUS_IE	0x80000000 | 
 | 71 |  | 
 | 72 | #define HARMONY_DF_16BIT_LINEAR	0 | 
 | 73 | #define HARMONY_DF_8BIT_ULAW	1 | 
 | 74 | #define HARMONY_DF_8BIT_ALAW	2 | 
 | 75 |  | 
 | 76 | #define HARMONY_SS_MONO		0 | 
 | 77 | #define HARMONY_SS_STEREO	1 | 
 | 78 |  | 
 | 79 | #define HARMONY_SR_8KHZ		0x08 | 
 | 80 | #define HARMONY_SR_16KHZ	0x09 | 
 | 81 | #define HARMONY_SR_27KHZ	0x0A | 
 | 82 | #define HARMONY_SR_32KHZ	0x0B | 
 | 83 | #define HARMONY_SR_48KHZ	0x0E | 
 | 84 | #define HARMONY_SR_9KHZ		0x0F | 
 | 85 | #define HARMONY_SR_5KHZ		0x10 | 
 | 86 | #define HARMONY_SR_11KHZ	0x11 | 
 | 87 | #define HARMONY_SR_18KHZ	0x12 | 
 | 88 | #define HARMONY_SR_22KHZ	0x13 | 
 | 89 | #define HARMONY_SR_37KHZ	0x14 | 
 | 90 | #define HARMONY_SR_44KHZ	0x15 | 
 | 91 | #define HARMONY_SR_33KHZ	0x16 | 
 | 92 | #define HARMONY_SR_6KHZ		0x17 | 
 | 93 |  | 
 | 94 | /* | 
 | 95 |  * Some magics numbers used to auto-detect file formats | 
 | 96 |  */ | 
 | 97 |  | 
 | 98 | #define HARMONY_MAGIC_8B_ULAW	1 | 
 | 99 | #define HARMONY_MAGIC_8B_ALAW	27 | 
 | 100 | #define HARMONY_MAGIC_16B_LINEAR 3 | 
 | 101 | #define HARMONY_MAGIC_MONO	1 | 
 | 102 | #define HARMONY_MAGIC_STEREO	2 | 
 | 103 |  | 
 | 104 | /* | 
 | 105 |  * Channels Positions in mixer register | 
 | 106 |  */ | 
 | 107 |  | 
 | 108 | #define GAIN_HE_SHIFT   27 | 
 | 109 | #define GAIN_HE_MASK    ( 1 << GAIN_HE_SHIFT)  | 
 | 110 | #define GAIN_LE_SHIFT   26 | 
 | 111 | #define GAIN_LE_MASK    ( 1 << GAIN_LE_SHIFT)  | 
 | 112 | #define GAIN_SE_SHIFT   25 | 
 | 113 | #define GAIN_SE_MASK    ( 1 << GAIN_SE_SHIFT)  | 
 | 114 | #define GAIN_IS_SHIFT   24 | 
 | 115 | #define GAIN_IS_MASK    ( 1 << GAIN_IS_SHIFT)  | 
 | 116 | #define GAIN_MA_SHIFT   20 | 
 | 117 | #define GAIN_MA_MASK    ( 0x0f << GAIN_MA_SHIFT)  | 
 | 118 | #define GAIN_LI_SHIFT   16 | 
 | 119 | #define GAIN_LI_MASK    ( 0x0f << GAIN_LI_SHIFT)  | 
 | 120 | #define GAIN_RI_SHIFT   12 | 
 | 121 | #define GAIN_RI_MASK    ( 0x0f << GAIN_RI_SHIFT)  | 
 | 122 | #define GAIN_LO_SHIFT   6 | 
 | 123 | #define GAIN_LO_MASK    ( 0x3f << GAIN_LO_SHIFT)  | 
 | 124 | #define GAIN_RO_SHIFT   0 | 
 | 125 | #define GAIN_RO_MASK    ( 0x3f << GAIN_RO_SHIFT)  | 
 | 126 |  | 
 | 127 |  | 
 | 128 | #define MAX_OUTPUT_LEVEL  (GAIN_RO_MASK >> GAIN_RO_SHIFT) | 
 | 129 | #define MAX_INPUT_LEVEL   (GAIN_RI_MASK >> GAIN_RI_SHIFT) | 
 | 130 | #define MAX_MONITOR_LEVEL (GAIN_MA_MASK >> GAIN_MA_SHIFT) | 
 | 131 |  | 
 | 132 | #define MIXER_INTERNAL   SOUND_MIXER_LINE1 | 
 | 133 | #define MIXER_LINEOUT    SOUND_MIXER_LINE2 | 
 | 134 | #define MIXER_HEADPHONES SOUND_MIXER_LINE3 | 
 | 135 |  | 
 | 136 | #define MASK_INTERNAL   SOUND_MASK_LINE1 | 
 | 137 | #define MASK_LINEOUT    SOUND_MASK_LINE2 | 
 | 138 | #define MASK_HEADPHONES SOUND_MASK_LINE3 | 
 | 139 |  | 
 | 140 | /* | 
 | 141 |  * Channels Mask in mixer register | 
 | 142 |  */ | 
 | 143 |  | 
 | 144 | #define GAIN_TOTAL_SILENCE 0x00F00FFF | 
 | 145 | #define GAIN_DEFAULT       0x0FF00000 | 
 | 146 |  | 
 | 147 |  | 
 | 148 | struct harmony_hpa { | 
 | 149 | 	u8	unused000; | 
 | 150 | 	u8	id; | 
 | 151 | 	u8	teleshare_id; | 
 | 152 | 	u8	unused003; | 
 | 153 | 	u32	reset; | 
 | 154 | 	u32	cntl; | 
 | 155 | 	u32	gainctl; | 
 | 156 | 	u32	pnxtadd; | 
 | 157 | 	u32	pcuradd; | 
 | 158 | 	u32	rnxtadd; | 
 | 159 | 	u32	rcuradd; | 
 | 160 | 	u32	dstatus; | 
 | 161 | 	u32	ov; | 
 | 162 | 	u32	pio; | 
 | 163 | 	u32	unused02c; | 
 | 164 | 	u32	unused030[3]; | 
 | 165 | 	u32	diag; | 
 | 166 | }; | 
 | 167 |  | 
 | 168 | struct harmony_dev { | 
 | 169 | 	struct harmony_hpa *hpa; | 
 | 170 | 	struct parisc_device *dev; | 
 | 171 | 	u32 current_gain; | 
 | 172 | 	u32 dac_rate;		/* 8000 ... 48000 (Hz) */ | 
 | 173 | 	u8 data_format;		/* HARMONY_DF_xx_BIT_xxx */ | 
 | 174 | 	u8 sample_rate;		/* HARMONY_SR_xx_KHZ */ | 
 | 175 | 	u8 stereo_select;	/* HARMONY_SS_MONO or HARMONY_SS_STEREO */ | 
 | 176 | 	int format_initialized  :1; | 
 | 177 | 	int suspended_playing   :1; | 
 | 178 | 	int suspended_recording :1; | 
 | 179 | 	 | 
 | 180 | 	int blocked_playing     :1; | 
 | 181 | 	int blocked_recording   :1; | 
 | 182 | 	int audio_open		:1; | 
 | 183 | 	int mixer_open		:1; | 
 | 184 | 	 | 
 | 185 | 	wait_queue_head_t wq_play, wq_record; | 
 | 186 | 	int first_filled_play;	/* first buffer containing data (next to play) */ | 
 | 187 | 	int nb_filled_play;  | 
 | 188 | 	int play_offset; | 
 | 189 | 	int first_filled_record; | 
 | 190 | 	int nb_filled_record; | 
 | 191 | 		 | 
 | 192 | 	int dsp_unit, mixer_unit; | 
 | 193 | }; | 
 | 194 |  | 
 | 195 |  | 
 | 196 | static struct harmony_dev harmony; | 
 | 197 |  | 
 | 198 |  | 
 | 199 | /* | 
 | 200 |  * Dynamic sound buffer allocation and DMA memory | 
 | 201 |  */ | 
 | 202 |  | 
 | 203 | struct harmony_buffer { | 
 | 204 | 	unsigned char *addr; | 
 | 205 | 	dma_addr_t dma_handle; | 
 | 206 | 	int dma_coherent;	/* Zero if dma_alloc_coherent() fails */ | 
 | 207 | 	unsigned int len; | 
 | 208 | }; | 
 | 209 |  | 
 | 210 | /* | 
 | 211 |  * Harmony memory buffers | 
 | 212 |  */ | 
 | 213 |  | 
 | 214 | static struct harmony_buffer played_buf, recorded_buf, silent, graveyard; | 
 | 215 |  | 
 | 216 |  | 
 | 217 | #define CHECK_WBACK_INV_OFFSET(b,offset,len) \ | 
 | 218 |         do { if (!b.dma_coherent) \ | 
 | 219 | 		dma_cache_wback_inv((unsigned long)b.addr+offset,len); \ | 
 | 220 | 	} while (0)  | 
 | 221 |  | 
 | 222 | 	 | 
 | 223 | static int __init harmony_alloc_buffer(struct harmony_buffer *b,  | 
 | 224 | 		unsigned int buffer_count) | 
 | 225 | { | 
 | 226 | 	b->len = buffer_count * HARMONY_BUF_SIZE; | 
 | 227 | 	b->addr = dma_alloc_coherent(&harmony.dev->dev,  | 
 | 228 | 			  b->len, &b->dma_handle, GFP_KERNEL|GFP_DMA); | 
 | 229 | 	if (b->addr && b->dma_handle) { | 
 | 230 | 		b->dma_coherent = 1; | 
 | 231 | 		DPRINTK(KERN_INFO PFX "coherent memory: 0x%lx, played_buf: 0x%lx\n", | 
 | 232 | 				(unsigned long)b->dma_handle, (unsigned long)b->addr); | 
 | 233 | 	} else { | 
 | 234 | 		b->dma_coherent = 0; | 
 | 235 | 		/* kmalloc()ed memory will HPMC on ccio machines ! */ | 
 | 236 | 		b->addr = kmalloc(b->len, GFP_KERNEL); | 
 | 237 | 		if (!b->addr) { | 
 | 238 | 			printk(KERN_ERR PFX "couldn't allocate memory\n"); | 
 | 239 | 			return -EBUSY; | 
 | 240 | 		} | 
 | 241 | 		b->dma_handle = __pa(b->addr); | 
 | 242 | 	} | 
 | 243 | 	return 0; | 
 | 244 | } | 
 | 245 |  | 
 | 246 | static void __exit harmony_free_buffer(struct harmony_buffer *b) | 
 | 247 | { | 
 | 248 | 	if (!b->addr) | 
 | 249 | 		return; | 
 | 250 |  | 
 | 251 | 	if (b->dma_coherent) | 
 | 252 | 		dma_free_coherent(&harmony.dev->dev, | 
 | 253 | 				b->len, b->addr, b->dma_handle); | 
 | 254 | 	else | 
 | 255 | 		kfree(b->addr); | 
 | 256 |  | 
 | 257 | 	memset(b, 0, sizeof(*b)); | 
 | 258 | } | 
 | 259 |  | 
 | 260 |  | 
 | 261 |  | 
 | 262 | /* | 
 | 263 |  * Low-Level sound-chip programming | 
 | 264 |  */ | 
 | 265 |  | 
 | 266 | static void __inline__ harmony_wait_CNTL(void) | 
 | 267 | { | 
 | 268 | 	/* Wait until we're out of control mode */ | 
 | 269 | 	while (gsc_readl(&harmony.hpa->cntl) & CNTL_C) | 
 | 270 | 		/* wait */ ; | 
 | 271 | } | 
 | 272 |  | 
 | 273 |  | 
 | 274 | static void harmony_update_control(void)  | 
 | 275 | { | 
 | 276 | 	u32 default_cntl; | 
 | 277 | 	 | 
 | 278 | 	/* Set CNTL */ | 
 | 279 | 	default_cntl = (CNTL_C |  		/* The C bit */ | 
 | 280 | 		(harmony.data_format << 6) |	/* Set the data format */ | 
 | 281 | 		(harmony.stereo_select << 5) |	/* Stereo select */ | 
 | 282 | 		(harmony.sample_rate));		/* Set sample rate */ | 
 | 283 | 	harmony.format_initialized = 1; | 
 | 284 | 	 | 
 | 285 | 	/* initialize CNTL */ | 
 | 286 | 	gsc_writel(default_cntl, &harmony.hpa->cntl); | 
 | 287 | } | 
 | 288 |  | 
 | 289 | static void harmony_set_control(u8 data_format, u8 sample_rate, u8 stereo_select)  | 
 | 290 | { | 
 | 291 | 	harmony.sample_rate = sample_rate; | 
 | 292 | 	harmony.data_format = data_format; | 
 | 293 | 	harmony.stereo_select = stereo_select; | 
 | 294 | 	harmony_update_control(); | 
 | 295 | } | 
 | 296 |  | 
 | 297 | static void harmony_set_rate(u8 data_rate)  | 
 | 298 | { | 
 | 299 | 	harmony.sample_rate = data_rate; | 
 | 300 | 	harmony_update_control(); | 
 | 301 | } | 
 | 302 |  | 
 | 303 | static int harmony_detect_rate(int *freq) | 
 | 304 | { | 
 | 305 | 	int newrate; | 
 | 306 | 	switch (*freq) { | 
 | 307 | 	case 8000:	newrate = HARMONY_SR_8KHZ;	break; | 
 | 308 | 	case 16000:	newrate = HARMONY_SR_16KHZ;	break;  | 
 | 309 | 	case 27428:	newrate = HARMONY_SR_27KHZ;	break;  | 
 | 310 | 	case 32000:	newrate = HARMONY_SR_32KHZ;	break;  | 
 | 311 | 	case 48000:	newrate = HARMONY_SR_48KHZ;	break;  | 
 | 312 | 	case 9600:	newrate = HARMONY_SR_9KHZ;	break;  | 
 | 313 | 	case 5512:	newrate = HARMONY_SR_5KHZ;	break;  | 
 | 314 | 	case 11025:	newrate = HARMONY_SR_11KHZ;	break;  | 
 | 315 | 	case 18900:	newrate = HARMONY_SR_18KHZ;	break;  | 
 | 316 | 	case 22050:	newrate = HARMONY_SR_22KHZ;	break;  | 
 | 317 | 	case 37800:	newrate = HARMONY_SR_37KHZ;	break;  | 
 | 318 | 	case 44100:	newrate = HARMONY_SR_44KHZ;	break;  | 
 | 319 | 	case 33075:	newrate = HARMONY_SR_33KHZ;	break;  | 
 | 320 | 	case 6615:	newrate = HARMONY_SR_6KHZ;	break;  | 
 | 321 | 	default:	newrate = HARMONY_SR_8KHZ;  | 
 | 322 | 			*freq = 8000;			break; | 
 | 323 | 	} | 
 | 324 | 	return newrate; | 
 | 325 | } | 
 | 326 |  | 
 | 327 | static void harmony_set_format(u8 data_format)  | 
 | 328 | { | 
 | 329 | 	harmony.data_format = data_format; | 
 | 330 | 	harmony_update_control(); | 
 | 331 | } | 
 | 332 |  | 
 | 333 | static void harmony_set_stereo(u8 stereo_select)  | 
 | 334 | { | 
 | 335 | 	harmony.stereo_select = stereo_select; | 
 | 336 | 	harmony_update_control(); | 
 | 337 | } | 
 | 338 |  | 
 | 339 | static void harmony_disable_interrupts(void)  | 
 | 340 | { | 
 | 341 | 	harmony_wait_CNTL(); | 
 | 342 | 	gsc_writel(0, &harmony.hpa->dstatus);  | 
 | 343 | } | 
 | 344 |  | 
 | 345 | static void harmony_enable_interrupts(void)  | 
 | 346 | { | 
 | 347 | 	harmony_wait_CNTL(); | 
 | 348 | 	gsc_writel(DSTATUS_IE, &harmony.hpa->dstatus);  | 
 | 349 | } | 
 | 350 |  | 
 | 351 | /* | 
 | 352 |  * harmony_silence() | 
 | 353 |  * | 
 | 354 |  * This subroutine fills in a buffer starting at location start and | 
 | 355 |  * silences for length bytes.  This references the current | 
 | 356 |  * configuration of the audio format. | 
 | 357 |  * | 
 | 358 |  */ | 
 | 359 |  | 
 | 360 | static void harmony_silence(struct harmony_buffer *buffer, int start, int length)  | 
 | 361 | { | 
 | 362 | 	u8 silence_char; | 
 | 363 |  | 
 | 364 | 	/* Despite what you hear, silence is different in | 
 | 365 | 	   different audio formats.  */ | 
 | 366 | 	switch (harmony.data_format) { | 
 | 367 | 		case HARMONY_DF_8BIT_ULAW:	silence_char = 0x55; break; | 
 | 368 | 		case HARMONY_DF_8BIT_ALAW:	silence_char = 0xff; break; | 
 | 369 | 		case HARMONY_DF_16BIT_LINEAR:	/* fall through */ | 
 | 370 | 		default:			silence_char = 0; | 
 | 371 | 	} | 
 | 372 |  | 
 | 373 | 	memset(buffer->addr+start, silence_char, length); | 
 | 374 | } | 
 | 375 |  | 
 | 376 |  | 
 | 377 | static int harmony_audio_open(struct inode *inode, struct file *file) | 
 | 378 | { | 
 | 379 | 	if (harmony.audio_open)  | 
 | 380 | 		return -EBUSY; | 
 | 381 | 	 | 
 | 382 | 	harmony.audio_open = 1; | 
 | 383 | 	harmony.suspended_playing = harmony.suspended_recording = 1; | 
 | 384 | 	harmony.blocked_playing   = harmony.blocked_recording   = 0; | 
 | 385 | 	harmony.first_filled_play = harmony.first_filled_record = 0; | 
 | 386 | 	harmony.nb_filled_play    = harmony.nb_filled_record    = 0; | 
 | 387 | 	harmony.play_offset = 0; | 
 | 388 | 	init_waitqueue_head(&harmony.wq_play); | 
 | 389 | 	init_waitqueue_head(&harmony.wq_record); | 
 | 390 | 	 | 
 | 391 | 	/* Start off in a balanced mode. */ | 
 | 392 | 	harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO); | 
 | 393 | 	harmony_update_control(); | 
 | 394 | 	harmony.format_initialized = 0; | 
 | 395 |  | 
 | 396 | 	/* Clear out all the buffers and flush to cache */ | 
 | 397 | 	harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); | 
 | 398 | 	CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); | 
 | 399 | 	 | 
 | 400 | 	return 0; | 
 | 401 | } | 
 | 402 |  | 
 | 403 | /* | 
 | 404 |  * Release (close) the audio device. | 
 | 405 |  */ | 
 | 406 |  | 
 | 407 | static int harmony_audio_release(struct inode *inode, struct file *file) | 
 | 408 | { | 
 | 409 | 	if (!harmony.audio_open)  | 
 | 410 | 		return -EBUSY; | 
 | 411 | 	 | 
 | 412 | 	harmony.audio_open = 0; | 
 | 413 |  | 
 | 414 | 	return 0; | 
 | 415 | } | 
 | 416 |  | 
 | 417 | /* | 
 | 418 |  * Read recorded data off the audio device. | 
 | 419 |  */ | 
 | 420 |  | 
 | 421 | static ssize_t harmony_audio_read(struct file *file, | 
 | 422 |                                 char *buffer, | 
 | 423 |                                 size_t size_count, | 
 | 424 |                                 loff_t *ppos) | 
 | 425 | { | 
 | 426 | 	int total_count = (int) size_count; | 
 | 427 | 	int count = 0; | 
 | 428 | 	int buf_to_read; | 
 | 429 |  | 
 | 430 | 	while (count<total_count) { | 
 | 431 | 		/* Wait until we're out of control mode */ | 
 | 432 | 		harmony_wait_CNTL(); | 
 | 433 | 		 | 
 | 434 | 		/* Figure out which buffer to fill in */ | 
 | 435 | 		if (harmony.nb_filled_record <= 2) { | 
 | 436 | 			harmony.blocked_recording = 1; | 
 | 437 | 		        if (harmony.suspended_recording) { | 
 | 438 | 				harmony.suspended_recording = 0; | 
 | 439 | 				harmony_enable_interrupts(); | 
 | 440 | 			} | 
 | 441 | 							 | 
 | 442 | 			interruptible_sleep_on(&harmony.wq_record); | 
 | 443 | 			harmony.blocked_recording = 0; | 
 | 444 | 		} | 
 | 445 | 		 | 
 | 446 | 		if (harmony.nb_filled_record < 2) | 
 | 447 | 			return -EBUSY; | 
 | 448 | 		 | 
 | 449 | 		buf_to_read = harmony.first_filled_record; | 
 | 450 |  | 
 | 451 | 		/* Copy the page to an aligned buffer */ | 
 | 452 | 		if (copy_to_user(buffer+count, recorded_buf.addr + | 
 | 453 | 				 (HARMONY_BUF_SIZE*buf_to_read), | 
 | 454 | 				 HARMONY_BUF_SIZE)) { | 
 | 455 | 			count = -EFAULT; | 
 | 456 | 			break; | 
 | 457 | 		} | 
 | 458 | 		 | 
 | 459 | 		harmony.nb_filled_record--; | 
 | 460 | 		harmony.first_filled_record++; | 
 | 461 | 		harmony.first_filled_record %= MAX_BUFS; | 
 | 462 | 				 | 
 | 463 | 		count += HARMONY_BUF_SIZE; | 
 | 464 | 	} | 
 | 465 | 	return count; | 
 | 466 | } | 
 | 467 |  | 
 | 468 |  | 
 | 469 |  | 
 | 470 |  | 
 | 471 | /* | 
 | 472 |  * Here is the place where we try to recognize file format. | 
 | 473 |  * Sun/NeXT .au files begin with the string .snd | 
 | 474 |  * At offset 12 is specified the encoding. | 
 | 475 |  * At offset 16 is specified speed rate | 
 | 476 |  * At Offset 20 is specified the numbers of voices | 
 | 477 |  */ | 
 | 478 |  | 
 | 479 | #define four_bytes_to_u32(start) (file_header[start] << 24)|\ | 
 | 480 |                                   (file_header[start+1] << 16)|\ | 
 | 481 |                                   (file_header[start+2] << 8)|\ | 
 | 482 |                                   (file_header[start+3]); | 
 | 483 |  | 
 | 484 | #define test_rate(tested,real_value,harmony_value) if ((tested)<=(real_value))\ | 
 | 485 |                                                      | 
 | 486 |  | 
 | 487 | static int harmony_format_auto_detect(const char *buffer, int block_size) | 
 | 488 | { | 
 | 489 | 	u8 file_header[24]; | 
 | 490 | 	u32 start_string; | 
 | 491 | 	int ret = 0; | 
 | 492 | 	 | 
 | 493 | 	if (block_size>24) { | 
 | 494 | 		if (copy_from_user(file_header, buffer, sizeof(file_header))) | 
 | 495 | 			ret = -EFAULT; | 
 | 496 | 			 | 
 | 497 | 		start_string = four_bytes_to_u32(0); | 
 | 498 | 		 | 
 | 499 | 		if ((file_header[4]==0) && (start_string==0x2E736E64)) { | 
 | 500 | 			u32 format; | 
 | 501 | 			u32 nb_voices; | 
 | 502 | 			u32 speed; | 
 | 503 | 			 | 
 | 504 | 			format = four_bytes_to_u32(12); | 
 | 505 | 			nb_voices = four_bytes_to_u32(20); | 
 | 506 | 			speed = four_bytes_to_u32(16); | 
 | 507 | 			 | 
 | 508 | 			switch (format) { | 
 | 509 | 			case HARMONY_MAGIC_8B_ULAW: | 
 | 510 | 				harmony.data_format = HARMONY_DF_8BIT_ULAW; | 
 | 511 | 				break; | 
 | 512 | 			case HARMONY_MAGIC_8B_ALAW: | 
 | 513 | 				harmony.data_format = HARMONY_DF_8BIT_ALAW; | 
 | 514 | 				break; | 
 | 515 | 			case HARMONY_MAGIC_16B_LINEAR: | 
 | 516 | 				harmony.data_format = HARMONY_DF_16BIT_LINEAR; | 
 | 517 | 				break; | 
 | 518 | 			default: | 
 | 519 | 				harmony_set_control(HARMONY_DF_16BIT_LINEAR, | 
 | 520 | 						HARMONY_SR_44KHZ, HARMONY_SS_STEREO); | 
 | 521 | 				goto out; | 
 | 522 | 			} | 
 | 523 | 			switch (nb_voices) { | 
 | 524 | 			case HARMONY_MAGIC_MONO: | 
 | 525 | 				harmony.stereo_select = HARMONY_SS_MONO; | 
 | 526 | 				break; | 
 | 527 | 			case HARMONY_MAGIC_STEREO: | 
 | 528 | 				harmony.stereo_select = HARMONY_SS_STEREO; | 
 | 529 | 				break; | 
 | 530 | 			default: | 
 | 531 | 				harmony.stereo_select = HARMONY_SS_MONO; | 
 | 532 | 				break; | 
 | 533 | 			} | 
 | 534 | 			harmony_set_rate(harmony_detect_rate(&speed)); | 
 | 535 | 			harmony.dac_rate = speed; | 
 | 536 | 			goto out; | 
 | 537 | 		} | 
 | 538 | 	} | 
 | 539 | 	harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO); | 
 | 540 | out: | 
 | 541 | 	return ret; | 
 | 542 | } | 
 | 543 | #undef four_bytes_to_u32 | 
 | 544 |  | 
 | 545 |  | 
 | 546 | static ssize_t harmony_audio_write(struct file *file, | 
 | 547 |                                  const char *buffer, | 
 | 548 |                                  size_t size_count, | 
 | 549 |                                  loff_t *ppos) | 
 | 550 | { | 
 | 551 | 	int total_count = (int) size_count; | 
 | 552 | 	int count = 0; | 
 | 553 | 	int frame_size; | 
 | 554 | 	int buf_to_fill; | 
 | 555 | 	int fresh_buffer; | 
 | 556 |  | 
 | 557 | 	if (!harmony.format_initialized) { | 
 | 558 | 		if (harmony_format_auto_detect(buffer, total_count)) | 
 | 559 | 			return -EFAULT; | 
 | 560 | 	} | 
 | 561 | 	 | 
 | 562 | 	while (count<total_count) { | 
 | 563 | 		/* Wait until we're out of control mode */ | 
 | 564 | 		harmony_wait_CNTL(); | 
 | 565 |  | 
 | 566 | 		/* Figure out which buffer to fill in */ | 
 | 567 | 		if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) { | 
 | 568 | 			harmony.blocked_playing = 1; | 
 | 569 | 			interruptible_sleep_on(&harmony.wq_play); | 
 | 570 | 			harmony.blocked_playing = 0; | 
 | 571 | 		} | 
 | 572 | 		if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) | 
 | 573 | 			return -EBUSY; | 
 | 574 | 		 | 
 | 575 | 		 | 
 | 576 | 		buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play);  | 
 | 577 | 		if (harmony.play_offset) { | 
 | 578 | 			buf_to_fill--; | 
 | 579 | 			buf_to_fill += MAX_BUFS; | 
 | 580 | 		} | 
 | 581 | 		buf_to_fill %= MAX_BUFS; | 
 | 582 | 		 | 
 | 583 | 		fresh_buffer = (harmony.play_offset == 0); | 
 | 584 | 		 | 
 | 585 | 		/* Figure out the size of the frame */ | 
 | 586 | 		if ((total_count-count) >= HARMONY_BUF_SIZE - harmony.play_offset) { | 
 | 587 | 			frame_size = HARMONY_BUF_SIZE - harmony.play_offset; | 
 | 588 | 		} else { | 
 | 589 | 			frame_size = total_count - count; | 
 | 590 | 			/* Clear out the buffer, since there we'll only be  | 
 | 591 | 			   overlaying part of the old buffer with the new one */ | 
 | 592 | 			harmony_silence(&played_buf,  | 
 | 593 | 				HARMONY_BUF_SIZE*buf_to_fill+frame_size+harmony.play_offset, | 
 | 594 | 				HARMONY_BUF_SIZE-frame_size-harmony.play_offset); | 
 | 595 | 		} | 
 | 596 |  | 
 | 597 | 		/* Copy the page to an aligned buffer */ | 
 | 598 | 		if (copy_from_user(played_buf.addr +(HARMONY_BUF_SIZE*buf_to_fill) + harmony.play_offset,  | 
 | 599 | 				   buffer+count, frame_size)) | 
 | 600 | 			return -EFAULT; | 
 | 601 | 		CHECK_WBACK_INV_OFFSET(played_buf, (HARMONY_BUF_SIZE*buf_to_fill + harmony.play_offset),  | 
 | 602 | 				frame_size); | 
 | 603 | 	 | 
 | 604 | 		if (fresh_buffer) | 
 | 605 | 			harmony.nb_filled_play++; | 
 | 606 | 		 | 
 | 607 | 		count += frame_size; | 
 | 608 | 		harmony.play_offset += frame_size; | 
 | 609 | 		harmony.play_offset %= HARMONY_BUF_SIZE; | 
 | 610 | 		if (harmony.suspended_playing && (harmony.nb_filled_play>=4)) | 
 | 611 | 			harmony_enable_interrupts(); | 
 | 612 | 	} | 
 | 613 | 	 | 
 | 614 | 	return count; | 
 | 615 | } | 
 | 616 |  | 
 | 617 | static unsigned int harmony_audio_poll(struct file *file, | 
 | 618 |                                      struct poll_table_struct *wait) | 
 | 619 | { | 
 | 620 | 	unsigned int mask = 0; | 
 | 621 | 	 | 
 | 622 | 	if (file->f_mode & FMODE_READ) { | 
 | 623 | 		if (!harmony.suspended_recording) | 
 | 624 | 			poll_wait(file, &harmony.wq_record, wait); | 
 | 625 | 		if (harmony.nb_filled_record) | 
 | 626 | 			mask |= POLLIN | POLLRDNORM; | 
 | 627 | 	} | 
 | 628 |  | 
 | 629 | 	if (file->f_mode & FMODE_WRITE) { | 
 | 630 | 		if (!harmony.suspended_playing) | 
 | 631 | 			poll_wait(file, &harmony.wq_play, wait); | 
 | 632 | 		if (harmony.nb_filled_play) | 
 | 633 | 			mask |= POLLOUT | POLLWRNORM; | 
 | 634 | 	} | 
 | 635 |  | 
 | 636 | 	return mask; | 
 | 637 | } | 
 | 638 |  | 
 | 639 | static int harmony_audio_ioctl(struct inode *inode, | 
 | 640 |                                 struct file *file, | 
 | 641 | 				unsigned int cmd, | 
 | 642 |                                 unsigned long arg) | 
 | 643 | { | 
 | 644 | 	int ival, new_format; | 
 | 645 | 	int frag_size, frag_buf; | 
 | 646 | 	struct audio_buf_info info; | 
 | 647 | 	 | 
 | 648 | 	switch (cmd) { | 
 | 649 | 	case OSS_GETVERSION: | 
 | 650 | 		return put_user(SOUND_VERSION, (int *) arg); | 
 | 651 |  | 
 | 652 | 	case SNDCTL_DSP_GETCAPS: | 
 | 653 | 		ival = DSP_CAP_DUPLEX; | 
 | 654 | 		return put_user(ival, (int *) arg); | 
 | 655 |  | 
 | 656 | 	case SNDCTL_DSP_GETFMTS: | 
 | 657 | 		ival = (AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW );  | 
 | 658 | 		return put_user(ival, (int *) arg); | 
 | 659 | 	 | 
 | 660 | 	case SNDCTL_DSP_SETFMT: | 
 | 661 | 		if (get_user(ival, (int *) arg))  | 
 | 662 | 			return -EFAULT; | 
 | 663 | 		if (ival != AFMT_QUERY) { | 
 | 664 | 			switch (ival) { | 
 | 665 | 			case AFMT_MU_LAW:	new_format = HARMONY_DF_8BIT_ULAW; break; | 
 | 666 | 			case AFMT_A_LAW:	new_format = HARMONY_DF_8BIT_ALAW; break; | 
 | 667 | 			case AFMT_S16_BE:	new_format = HARMONY_DF_16BIT_LINEAR; break; | 
 | 668 | 			default: { | 
 | 669 | 				DPRINTK(KERN_WARNING PFX  | 
 | 670 | 					"unsupported sound format 0x%04x requested.\n", | 
 | 671 | 					ival); | 
 | 672 | 				ival = AFMT_S16_BE; | 
 | 673 | 				return put_user(ival, (int *) arg); | 
 | 674 | 			} | 
 | 675 | 			} | 
 | 676 | 			harmony_set_format(new_format); | 
 | 677 | 			return 0; | 
 | 678 | 		} else { | 
 | 679 | 			switch (harmony.data_format) { | 
 | 680 | 			case HARMONY_DF_8BIT_ULAW:	ival = AFMT_MU_LAW; break; | 
 | 681 | 			case HARMONY_DF_8BIT_ALAW:	ival = AFMT_A_LAW;  break; | 
 | 682 | 			case HARMONY_DF_16BIT_LINEAR:	ival = AFMT_U16_BE; break; | 
 | 683 | 			default: ival = 0; | 
 | 684 | 			} | 
 | 685 | 			return put_user(ival, (int *) arg); | 
 | 686 | 		} | 
 | 687 |  | 
 | 688 | 	case SOUND_PCM_READ_RATE: | 
 | 689 | 		ival = harmony.dac_rate; | 
 | 690 | 		return put_user(ival, (int *) arg); | 
 | 691 |  | 
 | 692 | 	case SNDCTL_DSP_SPEED: | 
 | 693 | 		if (get_user(ival, (int *) arg)) | 
 | 694 | 			return -EFAULT; | 
 | 695 | 		harmony_set_rate(harmony_detect_rate(&ival)); | 
 | 696 | 		harmony.dac_rate = ival; | 
 | 697 | 		return put_user(ival, (int*) arg); | 
 | 698 |  | 
 | 699 | 	case SNDCTL_DSP_STEREO: | 
 | 700 | 		if (get_user(ival, (int *) arg)) | 
 | 701 | 			return -EFAULT; | 
 | 702 | 		if (ival != 0 && ival != 1) | 
 | 703 | 			return -EINVAL; | 
 | 704 | 		harmony_set_stereo(ival); | 
 | 705 |  		return 0; | 
 | 706 |   | 
 | 707 |  	case SNDCTL_DSP_CHANNELS: | 
 | 708 |  		if (get_user(ival, (int *) arg)) | 
 | 709 |  			return -EFAULT; | 
 | 710 |  		if (ival != 1 && ival != 2) { | 
 | 711 |  			ival = harmony.stereo_select == HARMONY_SS_MONO ? 1 : 2; | 
 | 712 |  			return put_user(ival, (int *) arg); | 
 | 713 |  		} | 
 | 714 |  		harmony_set_stereo(ival-1); | 
 | 715 |  		return 0; | 
 | 716 |  | 
 | 717 | 	case SNDCTL_DSP_GETBLKSIZE: | 
 | 718 | 		ival = HARMONY_BUF_SIZE; | 
 | 719 | 		return put_user(ival, (int *) arg); | 
 | 720 | 		 | 
 | 721 |         case SNDCTL_DSP_NONBLOCK: | 
 | 722 |                 file->f_flags |= O_NONBLOCK; | 
 | 723 |                 return 0; | 
 | 724 |  | 
 | 725 |         case SNDCTL_DSP_RESET: | 
 | 726 | 		if (!harmony.suspended_recording) { | 
 | 727 | 			/* TODO: stop_recording() */ | 
 | 728 | 		} | 
 | 729 | 		return 0; | 
 | 730 |  | 
 | 731 | 	case SNDCTL_DSP_SETFRAGMENT: | 
 | 732 | 		if (get_user(ival, (int *)arg)) | 
 | 733 | 			return -EFAULT; | 
 | 734 | 		frag_size = ival & 0xffff; | 
 | 735 | 		frag_buf = (ival>>16) & 0xffff; | 
 | 736 | 		/* TODO: We use hardcoded fragment sizes and numbers for now */ | 
 | 737 | 		frag_size = 12;  /* 4096 == 2^12 */ | 
 | 738 | 		frag_buf  = MAX_BUFS; | 
 | 739 | 		ival = (frag_buf << 16) + frag_size; | 
 | 740 | 		return put_user(ival, (int *) arg); | 
 | 741 | 		 | 
 | 742 | 	case SNDCTL_DSP_GETOSPACE: | 
 | 743 | 		if (!(file->f_mode & FMODE_WRITE)) | 
 | 744 | 			return -EINVAL; | 
 | 745 | 		info.fragstotal = MAX_BUFS; | 
 | 746 |                 info.fragments = MAX_BUFS - harmony.nb_filled_play; | 
 | 747 | 		info.fragsize = HARMONY_BUF_SIZE; | 
 | 748 |                 info.bytes = info.fragments * info.fragsize; | 
 | 749 | 		return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0; | 
 | 750 |  | 
 | 751 | 	case SNDCTL_DSP_GETISPACE: | 
 | 752 | 		if (!(file->f_mode & FMODE_READ)) | 
 | 753 | 			return -EINVAL; | 
 | 754 | 		info.fragstotal = MAX_BUFS; | 
 | 755 |                 info.fragments = /*MAX_BUFS-*/ harmony.nb_filled_record; | 
 | 756 | 		info.fragsize = HARMONY_BUF_SIZE; | 
 | 757 |                 info.bytes = info.fragments * info.fragsize; | 
 | 758 | 		return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0; | 
 | 759 | 	 | 
 | 760 | 	case SNDCTL_DSP_SYNC: | 
 | 761 | 		return 0; | 
 | 762 | 	} | 
 | 763 | 	 | 
 | 764 | 	return -EINVAL; | 
 | 765 | } | 
 | 766 |  | 
 | 767 |  | 
 | 768 | /* | 
 | 769 |  * harmony_interrupt() | 
 | 770 |  * | 
 | 771 |  * harmony interruption service routine | 
 | 772 |  *  | 
 | 773 |  */ | 
 | 774 |  | 
 | 775 | static irqreturn_t harmony_interrupt(int irq, void *dev, struct pt_regs *regs) | 
 | 776 | { | 
 | 777 | 	u32 dstatus; | 
 | 778 | 	struct harmony_hpa *hpa; | 
 | 779 |  | 
 | 780 | 	/* Setup the hpa */ | 
 | 781 | 	hpa = ((struct harmony_dev *)dev)->hpa; | 
 | 782 | 	harmony_wait_CNTL(); | 
 | 783 |  | 
 | 784 | 	/* Read dstatus and pcuradd (the current address) */ | 
 | 785 | 	dstatus = gsc_readl(&hpa->dstatus); | 
 | 786 | 	 | 
 | 787 | 	/* Turn off interrupts */ | 
 | 788 | 	harmony_disable_interrupts(); | 
 | 789 | 	 | 
 | 790 | 	/* Check if this is a request to get the next play buffer */ | 
 | 791 | 	if (dstatus & DSTATUS_PN) { | 
 | 792 | 		if (!harmony.nb_filled_play) { | 
 | 793 | 			harmony.suspended_playing = 1; | 
 | 794 | 			gsc_writel((unsigned long)silent.dma_handle, &hpa->pnxtadd); | 
 | 795 | 						 | 
 | 796 | 			if (!harmony.suspended_recording) | 
 | 797 | 				harmony_enable_interrupts(); | 
 | 798 | 		} else { | 
 | 799 | 			harmony.suspended_playing = 0; | 
 | 800 | 			gsc_writel((unsigned long)played_buf.dma_handle +  | 
 | 801 | 					(HARMONY_BUF_SIZE*harmony.first_filled_play), | 
 | 802 | 					&hpa->pnxtadd); | 
 | 803 | 			harmony.first_filled_play++; | 
 | 804 | 			harmony.first_filled_play %= MAX_BUFS; | 
 | 805 | 			harmony.nb_filled_play--; | 
 | 806 | 			 | 
 | 807 | 		       	harmony_enable_interrupts(); | 
 | 808 | 		} | 
 | 809 | 		 | 
 | 810 | 		if (harmony.blocked_playing) | 
 | 811 | 			wake_up_interruptible(&harmony.wq_play); | 
 | 812 | 	} | 
 | 813 | 	 | 
 | 814 | 	/* Check if we're being asked to fill in a recording buffer */ | 
 | 815 | 	if (dstatus & DSTATUS_RN) { | 
 | 816 | 		if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording) | 
 | 817 | 		{ | 
 | 818 | 			harmony.nb_filled_record = 0; | 
 | 819 | 			harmony.first_filled_record = 0; | 
 | 820 | 			harmony.suspended_recording = 1; | 
 | 821 | 			gsc_writel((unsigned long)graveyard.dma_handle, &hpa->rnxtadd); | 
 | 822 | 			if (!harmony.suspended_playing) | 
 | 823 | 				harmony_enable_interrupts(); | 
 | 824 | 		} else { | 
 | 825 | 			int buf_to_fill; | 
 | 826 | 			buf_to_fill = (harmony.first_filled_record+harmony.nb_filled_record) % MAX_BUFS; | 
 | 827 | 			CHECK_WBACK_INV_OFFSET(recorded_buf, HARMONY_BUF_SIZE*buf_to_fill, HARMONY_BUF_SIZE); | 
 | 828 | 			gsc_writel((unsigned long)recorded_buf.dma_handle + | 
 | 829 | 					HARMONY_BUF_SIZE*buf_to_fill, | 
 | 830 | 					&hpa->rnxtadd); | 
 | 831 | 			harmony.nb_filled_record++; | 
 | 832 | 			harmony_enable_interrupts(); | 
 | 833 | 		} | 
 | 834 |  | 
 | 835 | 		if (harmony.blocked_recording && harmony.nb_filled_record>3) | 
 | 836 | 			wake_up_interruptible(&harmony.wq_record); | 
 | 837 | 	} | 
 | 838 | 	return IRQ_HANDLED; | 
 | 839 | } | 
 | 840 |  | 
 | 841 | /* | 
 | 842 |  * Sound playing functions | 
 | 843 |  */ | 
 | 844 |  | 
 | 845 | static struct file_operations harmony_audio_fops = { | 
 | 846 | 	.owner		= THIS_MODULE, | 
 | 847 | 	.llseek		= no_llseek, | 
 | 848 | 	.read		= harmony_audio_read, | 
 | 849 | 	.write		= harmony_audio_write, | 
 | 850 | 	.poll		= harmony_audio_poll, | 
 | 851 | 	.ioctl		= harmony_audio_ioctl, | 
 | 852 | 	.open		= harmony_audio_open, | 
 | 853 | 	.release	= harmony_audio_release, | 
 | 854 | }; | 
 | 855 |  | 
 | 856 | static int harmony_audio_init(void) | 
 | 857 | { | 
 | 858 | 	/* Request that IRQ */ | 
 | 859 | 	if (request_irq(harmony.dev->irq, harmony_interrupt, 0 ,"harmony", &harmony)) { | 
 | 860 | 		printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony.dev->irq); | 
 | 861 | 		return -EFAULT; | 
 | 862 | 	} | 
 | 863 |  | 
 | 864 |    	harmony.dsp_unit = register_sound_dsp(&harmony_audio_fops, -1); | 
 | 865 | 	if (harmony.dsp_unit < 0) { | 
 | 866 | 		printk(KERN_ERR PFX "Error registering dsp\n"); | 
 | 867 | 		free_irq(harmony.dev->irq, &harmony); | 
 | 868 | 		return -EFAULT; | 
 | 869 | 	} | 
 | 870 | 	 | 
 | 871 | 	/* Clear the buffers so you don't end up with crap in the buffers. */  | 
 | 872 | 	harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); | 
 | 873 |  | 
 | 874 | 	/* Make sure this makes it to cache */ | 
 | 875 | 	CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS); | 
 | 876 |  | 
 | 877 | 	/* Clear out the silent buffer and flush to cache */ | 
 | 878 | 	harmony_silence(&silent, 0, HARMONY_BUF_SIZE); | 
 | 879 | 	CHECK_WBACK_INV_OFFSET(silent, 0, HARMONY_BUF_SIZE); | 
 | 880 | 	 | 
 | 881 | 	harmony.audio_open = 0; | 
 | 882 | 	 | 
 | 883 | 	return 0; | 
 | 884 | } | 
 | 885 |  | 
 | 886 |  | 
 | 887 | /* | 
 | 888 |  * mixer functions  | 
 | 889 |  */ | 
 | 890 |  | 
 | 891 | static void harmony_mixer_set_gain(void) | 
 | 892 | { | 
 | 893 | 	harmony_wait_CNTL(); | 
 | 894 | 	gsc_writel(harmony.current_gain, &harmony.hpa->gainctl); | 
 | 895 | } | 
 | 896 |  | 
 | 897 | /*  | 
 | 898 |  *  Read gain of selected channel. | 
 | 899 |  *  The OSS rate is from 0 (silent) to 100 -> need some conversions | 
 | 900 |  * | 
 | 901 |  *  The harmony gain are attenuation for output and monitor gain. | 
 | 902 |  *                   is amplifaction for input gain | 
 | 903 |  */ | 
 | 904 | #define to_harmony_level(level,max) ((level)*max/100) | 
 | 905 | #define to_oss_level(level,max) ((level)*100/max) | 
 | 906 |  | 
 | 907 | static int harmony_mixer_get_level(int channel) | 
 | 908 | { | 
 | 909 | 	int left_level; | 
 | 910 | 	int right_level; | 
 | 911 |  | 
 | 912 | 	switch (channel) { | 
 | 913 | 		case SOUND_MIXER_VOLUME: | 
 | 914 | 			left_level  = (harmony.current_gain & GAIN_LO_MASK) >> GAIN_LO_SHIFT; | 
 | 915 | 			right_level = (harmony.current_gain & GAIN_RO_MASK) >> GAIN_RO_SHIFT; | 
 | 916 | 			left_level  = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL); | 
 | 917 | 			right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL); | 
 | 918 | 			return (right_level << 8)+left_level; | 
 | 919 | 			 | 
 | 920 | 		case SOUND_MIXER_IGAIN: | 
 | 921 | 			left_level = (harmony.current_gain & GAIN_LI_MASK) >> GAIN_LI_SHIFT; | 
 | 922 | 			right_level= (harmony.current_gain & GAIN_RI_MASK) >> GAIN_RI_SHIFT; | 
 | 923 | 			left_level = to_oss_level(left_level, MAX_INPUT_LEVEL); | 
 | 924 | 			right_level= to_oss_level(right_level, MAX_INPUT_LEVEL); | 
 | 925 | 			return (right_level << 8)+left_level; | 
 | 926 | 			 | 
 | 927 | 		case SOUND_MIXER_MONITOR: | 
 | 928 | 			left_level = (harmony.current_gain & GAIN_MA_MASK) >> GAIN_MA_SHIFT; | 
 | 929 | 			left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL); | 
 | 930 | 			return (left_level << 8)+left_level; | 
 | 931 | 	} | 
 | 932 | 	return -EINVAL; | 
 | 933 | } | 
 | 934 |  | 
 | 935 |  | 
 | 936 |  | 
 | 937 | /* | 
 | 938 |  * Some conversions for the same reasons. | 
 | 939 |  * We give back the new real value(s) due to | 
 | 940 |  * the rescale. | 
 | 941 |  */ | 
 | 942 |  | 
 | 943 | static int harmony_mixer_set_level(int channel, int value) | 
 | 944 | { | 
 | 945 | 	int left_level; | 
 | 946 | 	int right_level; | 
 | 947 | 	int new_left_level; | 
 | 948 | 	int new_right_level; | 
 | 949 |  | 
 | 950 | 	right_level = (value & 0x0000ff00) >> 8; | 
 | 951 | 	left_level = value & 0x000000ff; | 
 | 952 | 	if (right_level > 100) right_level = 100; | 
 | 953 | 	if (left_level > 100) left_level = 100; | 
 | 954 |    | 
 | 955 | 	switch (channel) { | 
 | 956 | 		case SOUND_MIXER_VOLUME: | 
 | 957 | 			right_level = to_harmony_level(100-right_level, MAX_OUTPUT_LEVEL); | 
 | 958 | 			left_level  = to_harmony_level(100-left_level, MAX_OUTPUT_LEVEL); | 
 | 959 | 			new_right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL); | 
 | 960 | 			new_left_level  = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL); | 
 | 961 | 			harmony.current_gain = (harmony.current_gain & ~(GAIN_LO_MASK | GAIN_RO_MASK))  | 
 | 962 | 					| (left_level << GAIN_LO_SHIFT) | (right_level << GAIN_RO_SHIFT); | 
 | 963 | 			harmony_mixer_set_gain(); | 
 | 964 | 			return (new_right_level << 8) + new_left_level; | 
 | 965 | 			 | 
 | 966 | 		case SOUND_MIXER_IGAIN: | 
 | 967 | 			right_level = to_harmony_level(right_level, MAX_INPUT_LEVEL); | 
 | 968 | 			left_level  = to_harmony_level(left_level, MAX_INPUT_LEVEL); | 
 | 969 | 			new_right_level = to_oss_level(right_level, MAX_INPUT_LEVEL); | 
 | 970 | 			new_left_level  = to_oss_level(left_level, MAX_INPUT_LEVEL); | 
 | 971 | 			harmony.current_gain = (harmony.current_gain & ~(GAIN_LI_MASK | GAIN_RI_MASK)) | 
 | 972 | 					| (left_level << GAIN_LI_SHIFT) | (right_level << GAIN_RI_SHIFT); | 
 | 973 | 			harmony_mixer_set_gain(); | 
 | 974 | 			return (new_right_level << 8) + new_left_level; | 
 | 975 | 	 | 
 | 976 | 		case SOUND_MIXER_MONITOR: | 
 | 977 | 			left_level = to_harmony_level(100-left_level, MAX_MONITOR_LEVEL); | 
 | 978 | 			new_left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL); | 
 | 979 | 			harmony.current_gain = (harmony.current_gain & ~GAIN_MA_MASK) | (left_level << GAIN_MA_SHIFT); | 
 | 980 | 			harmony_mixer_set_gain(); | 
 | 981 | 			return (new_left_level << 8) + new_left_level; | 
 | 982 | 	} | 
 | 983 |  | 
 | 984 | 	return -EINVAL; | 
 | 985 | } | 
 | 986 |  | 
 | 987 | #undef to_harmony_level | 
 | 988 | #undef to_oss_level | 
 | 989 |  | 
 | 990 | /*  | 
 | 991 |  * Return the selected input device (mic or line) | 
 | 992 |  */ | 
 | 993 |  | 
 | 994 | static int harmony_mixer_get_recmask(void)  | 
 | 995 | { | 
 | 996 | 	int current_input_line; | 
 | 997 | 	 | 
 | 998 | 	current_input_line = (harmony.current_gain & GAIN_IS_MASK)  | 
 | 999 | 				    >> GAIN_IS_SHIFT; | 
 | 1000 | 	if (current_input_line)  | 
 | 1001 | 		return SOUND_MASK_MIC; | 
 | 1002 |  | 
 | 1003 | 	return SOUND_MASK_LINE; | 
 | 1004 | } | 
 | 1005 |  | 
 | 1006 | /* | 
 | 1007 |  * Set the input (only one at time, arbitrary priority to line in) | 
 | 1008 |  */ | 
 | 1009 |  | 
 | 1010 | static int harmony_mixer_set_recmask(int recmask) | 
 | 1011 | { | 
 | 1012 | 	int new_input_line; | 
 | 1013 | 	int new_input_mask; | 
 | 1014 | 	int current_input_line; | 
 | 1015 | 	 | 
 | 1016 | 	current_input_line = (harmony.current_gain & GAIN_IS_MASK) | 
 | 1017 | 				    >> GAIN_IS_SHIFT; | 
 | 1018 | 	if ((current_input_line && ((recmask & SOUND_MASK_LINE) || !(recmask & SOUND_MASK_MIC))) || | 
 | 1019 | 		(!current_input_line && ((recmask & SOUND_MASK_LINE) && !(recmask & SOUND_MASK_MIC)))) { | 
 | 1020 | 		new_input_line = 0; | 
 | 1021 | 		new_input_mask = SOUND_MASK_LINE; | 
 | 1022 | 	} else { | 
 | 1023 | 		new_input_line = 1; | 
 | 1024 | 		new_input_mask = SOUND_MASK_MIC; | 
 | 1025 | 	} | 
 | 1026 | 	harmony.current_gain = ((harmony.current_gain & ~GAIN_IS_MASK) |  | 
 | 1027 | 				(new_input_line << GAIN_IS_SHIFT )); | 
 | 1028 | 	harmony_mixer_set_gain(); | 
 | 1029 | 	return new_input_mask; | 
 | 1030 | } | 
 | 1031 |  | 
 | 1032 |  | 
 | 1033 | /*  | 
 | 1034 |  * give the active outlines | 
 | 1035 |  */ | 
 | 1036 |  | 
 | 1037 | static int harmony_mixer_get_outmask(void) | 
 | 1038 | { | 
 | 1039 | 	int outmask = 0; | 
 | 1040 | 	 | 
 | 1041 | 	if (harmony.current_gain & GAIN_SE_MASK) outmask |= MASK_INTERNAL; | 
 | 1042 | 	if (harmony.current_gain & GAIN_LE_MASK) outmask |= MASK_LINEOUT; | 
 | 1043 | 	if (harmony.current_gain & GAIN_HE_MASK) outmask |= MASK_HEADPHONES; | 
 | 1044 | 	 | 
 | 1045 | 	return outmask; | 
 | 1046 | } | 
 | 1047 |  | 
 | 1048 |  | 
 | 1049 | static int harmony_mixer_set_outmask(int outmask) | 
 | 1050 | { | 
 | 1051 | 	if (outmask & MASK_INTERNAL)  | 
 | 1052 | 		harmony.current_gain |= GAIN_SE_MASK; | 
 | 1053 | 	else  | 
 | 1054 | 		harmony.current_gain &= ~GAIN_SE_MASK; | 
 | 1055 | 	 | 
 | 1056 | 	if (outmask & MASK_LINEOUT)  | 
 | 1057 | 		harmony.current_gain |= GAIN_LE_MASK; | 
 | 1058 | 	else  | 
 | 1059 | 		harmony.current_gain &= ~GAIN_LE_MASK; | 
 | 1060 | 	 | 
 | 1061 | 	if (outmask & MASK_HEADPHONES)  | 
 | 1062 | 		harmony.current_gain |= GAIN_HE_MASK;  | 
 | 1063 | 	else  | 
 | 1064 | 		harmony.current_gain &= ~GAIN_HE_MASK; | 
 | 1065 | 	 | 
 | 1066 | 	harmony_mixer_set_gain(); | 
 | 1067 |  | 
 | 1068 | 	return (outmask & (MASK_INTERNAL | MASK_LINEOUT | MASK_HEADPHONES)); | 
 | 1069 | } | 
 | 1070 |  | 
 | 1071 | /* | 
 | 1072 |  * This code is inspired from sb_mixer.c | 
 | 1073 |  */ | 
 | 1074 |  | 
 | 1075 | static int harmony_mixer_ioctl(struct inode * inode, struct file * file, | 
 | 1076 | 		unsigned int cmd, unsigned long arg) | 
 | 1077 | { | 
 | 1078 | 	int val; | 
 | 1079 | 	int ret; | 
 | 1080 |  | 
 | 1081 | 	if (cmd == SOUND_MIXER_INFO) { | 
 | 1082 | 		mixer_info info; | 
 | 1083 | 		memset(&info, 0, sizeof(info)); | 
 | 1084 |                 strncpy(info.id, "harmony", sizeof(info.id)-1); | 
 | 1085 |                 strncpy(info.name, "Harmony audio", sizeof(info.name)-1); | 
 | 1086 |                 info.modify_counter = 1; /* ? */ | 
 | 1087 |                 if (copy_to_user((void *)arg, &info, sizeof(info))) | 
 | 1088 |                         return -EFAULT; | 
 | 1089 | 		return 0; | 
 | 1090 | 	} | 
 | 1091 | 	 | 
 | 1092 | 	if (cmd == OSS_GETVERSION) | 
 | 1093 | 		return put_user(SOUND_VERSION, (int *)arg); | 
 | 1094 |  | 
 | 1095 | 	/* read */ | 
 | 1096 | 	val = 0; | 
 | 1097 | 	if (_SIOC_DIR(cmd) & _SIOC_WRITE) | 
 | 1098 | 		if (get_user(val, (int *)arg)) | 
 | 1099 | 			return -EFAULT; | 
 | 1100 |  | 
 | 1101 | 	switch (cmd) { | 
 | 1102 | 	case MIXER_READ(SOUND_MIXER_CAPS): | 
 | 1103 | 		ret = SOUND_CAP_EXCL_INPUT; | 
 | 1104 | 		break; | 
 | 1105 | 	case MIXER_READ(SOUND_MIXER_STEREODEVS): | 
 | 1106 | 		ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN; | 
 | 1107 | 		break; | 
 | 1108 | 		 | 
 | 1109 | 	case MIXER_READ(SOUND_MIXER_RECMASK): | 
 | 1110 | 		ret = SOUND_MASK_MIC | SOUND_MASK_LINE; | 
 | 1111 | 		break; | 
 | 1112 | 	case MIXER_READ(SOUND_MIXER_DEVMASK): | 
 | 1113 | 		ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN | | 
 | 1114 | 			SOUND_MASK_MONITOR; | 
 | 1115 | 		break; | 
 | 1116 | 	case MIXER_READ(SOUND_MIXER_OUTMASK): | 
 | 1117 | 		ret = MASK_INTERNAL | MASK_LINEOUT | | 
 | 1118 | 			MASK_HEADPHONES; | 
 | 1119 | 		break; | 
 | 1120 | 		 | 
 | 1121 | 	case MIXER_WRITE(SOUND_MIXER_RECSRC): | 
 | 1122 | 		ret = harmony_mixer_set_recmask(val); | 
 | 1123 | 		break; | 
 | 1124 | 	case MIXER_READ(SOUND_MIXER_RECSRC): | 
 | 1125 | 		ret = harmony_mixer_get_recmask(); | 
 | 1126 | 		break; | 
 | 1127 | 	       | 
 | 1128 | 	case MIXER_WRITE(SOUND_MIXER_OUTSRC): | 
 | 1129 | 		ret = harmony_mixer_set_outmask(val); | 
 | 1130 | 		break; | 
 | 1131 | 	case MIXER_READ(SOUND_MIXER_OUTSRC): | 
 | 1132 | 		ret = harmony_mixer_get_outmask(); | 
 | 1133 | 		break; | 
 | 1134 | 	 | 
 | 1135 | 	case MIXER_WRITE(SOUND_MIXER_VOLUME): | 
 | 1136 | 	case MIXER_WRITE(SOUND_MIXER_IGAIN): | 
 | 1137 | 	case MIXER_WRITE(SOUND_MIXER_MONITOR): | 
 | 1138 | 		ret = harmony_mixer_set_level(cmd & 0xff, val); | 
 | 1139 | 		break; | 
 | 1140 |  | 
 | 1141 | 	case MIXER_READ(SOUND_MIXER_VOLUME): | 
 | 1142 | 	case MIXER_READ(SOUND_MIXER_IGAIN): | 
 | 1143 | 	case MIXER_READ(SOUND_MIXER_MONITOR): | 
 | 1144 | 		ret = harmony_mixer_get_level(cmd & 0xff); | 
 | 1145 | 		break; | 
 | 1146 |  | 
 | 1147 | 	default: | 
 | 1148 | 		return -EINVAL; | 
 | 1149 | 	} | 
 | 1150 |  | 
 | 1151 | 	if (put_user(ret, (int *)arg)) | 
 | 1152 | 		return -EFAULT; | 
 | 1153 | 	return 0; | 
 | 1154 | } | 
 | 1155 |  | 
 | 1156 |  | 
 | 1157 | static int harmony_mixer_open(struct inode *inode, struct file *file) | 
 | 1158 | { | 
 | 1159 | 	if (harmony.mixer_open)  | 
 | 1160 | 		return -EBUSY; | 
 | 1161 | 	harmony.mixer_open = 1; | 
 | 1162 | 	return 0; | 
 | 1163 | } | 
 | 1164 |  | 
 | 1165 | static int harmony_mixer_release(struct inode *inode, struct file *file) | 
 | 1166 | { | 
 | 1167 | 	if (!harmony.mixer_open)  | 
 | 1168 | 		return -EBUSY; | 
 | 1169 | 	harmony.mixer_open = 0; | 
 | 1170 | 	return 0; | 
 | 1171 | } | 
 | 1172 |  | 
 | 1173 | static struct file_operations harmony_mixer_fops = { | 
 | 1174 | 	.owner		= THIS_MODULE, | 
 | 1175 | 	.llseek		= no_llseek, | 
 | 1176 | 	.open		= harmony_mixer_open, | 
 | 1177 | 	.release	= harmony_mixer_release, | 
 | 1178 | 	.ioctl		= harmony_mixer_ioctl, | 
 | 1179 | }; | 
 | 1180 |  | 
 | 1181 |  | 
 | 1182 | /* | 
 | 1183 |  * Mute all the output and reset Harmony. | 
 | 1184 |  */ | 
 | 1185 |  | 
 | 1186 | static void __init harmony_mixer_reset(void) | 
 | 1187 | { | 
 | 1188 | 	harmony.current_gain = GAIN_TOTAL_SILENCE; | 
 | 1189 | 	harmony_mixer_set_gain(); | 
 | 1190 | 	harmony_wait_CNTL(); | 
 | 1191 | 	gsc_writel(1, &harmony.hpa->reset); | 
 | 1192 | 	mdelay(50);		/* wait 50 ms */ | 
 | 1193 | 	gsc_writel(0, &harmony.hpa->reset); | 
 | 1194 | 	harmony.current_gain = GAIN_DEFAULT; | 
 | 1195 | 	harmony_mixer_set_gain(); | 
 | 1196 | } | 
 | 1197 |  | 
 | 1198 | static int __init harmony_mixer_init(void) | 
 | 1199 | { | 
 | 1200 | 	/* Register the device file operations */ | 
 | 1201 | 	harmony.mixer_unit = register_sound_mixer(&harmony_mixer_fops, -1); | 
 | 1202 | 	if (harmony.mixer_unit < 0) { | 
 | 1203 | 		printk(KERN_WARNING PFX "Error Registering Mixer Driver\n"); | 
 | 1204 | 		return -EFAULT; | 
 | 1205 | 	} | 
 | 1206 |    | 
 | 1207 | 	harmony_mixer_reset(); | 
 | 1208 | 	harmony.mixer_open = 0; | 
 | 1209 | 	 | 
 | 1210 | 	return 0; | 
 | 1211 | } | 
 | 1212 |  | 
 | 1213 |  | 
 | 1214 |  | 
 | 1215 | /*  | 
 | 1216 |  * This is the callback that's called by the inventory hardware code  | 
 | 1217 |  * if it finds a match to the registered driver.  | 
 | 1218 |  */ | 
 | 1219 | static int __devinit | 
 | 1220 | harmony_driver_probe(struct parisc_device *dev) | 
 | 1221 | { | 
 | 1222 | 	u8	id; | 
 | 1223 | 	u8	rev; | 
 | 1224 | 	u32	cntl; | 
 | 1225 | 	int	ret; | 
 | 1226 |  | 
 | 1227 | 	if (harmony.hpa) { | 
 | 1228 | 		/* We only support one Harmony at this time */ | 
 | 1229 | 		printk(KERN_ERR PFX "driver already registered\n"); | 
 | 1230 | 		return -EBUSY; | 
 | 1231 | 	} | 
 | 1232 |  | 
 | 1233 | 	if (!dev->irq) { | 
 | 1234 | 		printk(KERN_ERR PFX "no irq found\n"); | 
 | 1235 | 		return -ENODEV; | 
 | 1236 | 	} | 
 | 1237 |  | 
 | 1238 | 	/* Set the HPA of harmony */ | 
| Stuart Brady | 49efdd4 | 2006-01-10 20:47:58 -0500 | [diff] [blame] | 1239 | 	harmony.hpa = (struct harmony_hpa *)dev->hpa.start; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1240 | 	harmony.dev = dev; | 
 | 1241 |  | 
 | 1242 | 	/* Grab the ID and revision from the device */ | 
 | 1243 | 	id = gsc_readb(&harmony.hpa->id); | 
 | 1244 | 	if ((id | 1) != 0x15) { | 
 | 1245 | 		printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", id); | 
 | 1246 | 		return -EBUSY; | 
 | 1247 | 	} | 
 | 1248 | 	cntl = gsc_readl(&harmony.hpa->cntl); | 
 | 1249 | 	rev = (cntl>>20) & 0xff; | 
 | 1250 |  | 
 | 1251 | 	printk(KERN_INFO "Lasi Harmony Audio driver " HARMONY_VERSION ", " | 
 | 1252 | 			"h/w id %i, rev. %i at 0x%lx, IRQ %i\n", | 
| Stuart Brady | 49efdd4 | 2006-01-10 20:47:58 -0500 | [diff] [blame] | 1253 | 			id, rev, dev->hpa.start, harmony.dev->irq); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1254 | 	 | 
 | 1255 | 	/* Make sure the control bit isn't set, although I don't think it  | 
 | 1256 | 	   ever is. */ | 
 | 1257 | 	if (cntl & CNTL_C) { | 
 | 1258 | 		printk(KERN_WARNING PFX "CNTL busy\n"); | 
 | 1259 | 		harmony.hpa = 0; | 
 | 1260 | 		return -EBUSY; | 
 | 1261 | 	} | 
 | 1262 |  | 
 | 1263 | 	/* Initialize the memory buffers */ | 
 | 1264 | 	if (harmony_alloc_buffer(&played_buf, MAX_BUFS) ||  | 
 | 1265 | 	    harmony_alloc_buffer(&recorded_buf, MAX_BUFS) || | 
 | 1266 | 	    harmony_alloc_buffer(&graveyard, 1) || | 
 | 1267 | 	    harmony_alloc_buffer(&silent, 1)) { | 
 | 1268 | 		ret = -EBUSY; | 
 | 1269 | 		goto out_err; | 
 | 1270 | 	} | 
 | 1271 |  | 
 | 1272 | 	/* Initialize /dev/mixer and /dev/audio  */ | 
 | 1273 | 	if ((ret=harmony_mixer_init()))  | 
 | 1274 | 		goto out_err; | 
 | 1275 | 	if ((ret=harmony_audio_init()))  | 
 | 1276 | 		goto out_err; | 
 | 1277 |  | 
 | 1278 | 	return 0; | 
 | 1279 |  | 
 | 1280 | out_err: | 
 | 1281 | 	harmony.hpa = 0; | 
 | 1282 | 	harmony_free_buffer(&played_buf); | 
 | 1283 | 	harmony_free_buffer(&recorded_buf); | 
 | 1284 | 	harmony_free_buffer(&graveyard); | 
 | 1285 | 	harmony_free_buffer(&silent); | 
 | 1286 | 	return ret; | 
 | 1287 | } | 
 | 1288 |  | 
 | 1289 |  | 
 | 1290 | static struct parisc_device_id harmony_tbl[] = { | 
 | 1291 |  /* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, Bushmaster/Flounder */ | 
 | 1292 |  { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */ | 
 | 1293 |  { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */ | 
 | 1294 |  { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */ | 
 | 1295 |  { 0, } | 
 | 1296 | }; | 
 | 1297 |  | 
 | 1298 | MODULE_DEVICE_TABLE(parisc, harmony_tbl); | 
 | 1299 |  | 
 | 1300 | static struct parisc_driver harmony_driver = { | 
 | 1301 | 	.name		= "Lasi Harmony", | 
 | 1302 | 	.id_table	= harmony_tbl, | 
 | 1303 | 	.probe		= harmony_driver_probe, | 
 | 1304 | }; | 
 | 1305 |  | 
 | 1306 | static int __init init_harmony(void) | 
 | 1307 | { | 
 | 1308 | 	return register_parisc_driver(&harmony_driver); | 
 | 1309 | } | 
 | 1310 |  | 
 | 1311 | static void __exit cleanup_harmony(void) | 
 | 1312 | { | 
 | 1313 | 	free_irq(harmony.dev->irq, &harmony); | 
 | 1314 | 	unregister_sound_mixer(harmony.mixer_unit); | 
 | 1315 | 	unregister_sound_dsp(harmony.dsp_unit); | 
 | 1316 | 	harmony_free_buffer(&played_buf); | 
 | 1317 | 	harmony_free_buffer(&recorded_buf); | 
 | 1318 | 	harmony_free_buffer(&graveyard); | 
 | 1319 | 	harmony_free_buffer(&silent); | 
 | 1320 | 	unregister_parisc_driver(&harmony_driver); | 
 | 1321 | } | 
 | 1322 |  | 
 | 1323 |  | 
 | 1324 | MODULE_AUTHOR("Alex DeVries <alex@onefishtwo.ca>"); | 
 | 1325 | MODULE_DESCRIPTION("Harmony sound driver"); | 
 | 1326 | MODULE_LICENSE("GPL"); | 
 | 1327 |  | 
 | 1328 | module_init(init_harmony); | 
 | 1329 | module_exit(cleanup_harmony); | 
 | 1330 |  |