1/* 2 ********************************************************************** 3 * cardwi.c - PCM input HAL for emu10k1 driver 4 * Copyright 1999, 2000 Creative Labs, Inc. 5 * 6 ********************************************************************** 7 * 8 * Date Author Summary of changes 9 * ---- ------ ------------------ 10 * October 20, 1999 Bertrand Lee base code release 11 * 12 ********************************************************************** 13 * 14 * This program is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU General Public License as 16 * published by the Free Software Foundation; either version 2 of 17 * the License, or (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public 25 * License along with this program; if not, write to the Free 26 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 27 * USA. 28 * 29 ********************************************************************** 30 */ 31 32#include <linux/poll.h> 33#include "hwaccess.h" 34#include "timer.h" 35#include "recmgr.h" 36#include "audio.h" 37#include "cardwi.h" 38 39/** 40 * query_format - returns a valid sound format 41 * 42 * This function will return a valid sound format as close 43 * to the requested one as possible. 44 */ 45static void query_format(int recsrc, struct wave_format *wave_fmt) 46{ 47 48 switch (recsrc) { 49 case WAVERECORD_AC97: 50 51 if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2)) 52 wave_fmt->channels = 2; 53 54 if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2) 55 wave_fmt->samplingrate = 0xBB80; 56 else if (wave_fmt->samplingrate >= (0xAC44 + 0x7D00) / 2) 57 wave_fmt->samplingrate = 0xAC44; 58 else if (wave_fmt->samplingrate >= (0x7D00 + 0x5DC0) / 2) 59 wave_fmt->samplingrate = 0x7D00; 60 else if (wave_fmt->samplingrate >= (0x5DC0 + 0x5622) / 2) 61 wave_fmt->samplingrate = 0x5DC0; 62 else if (wave_fmt->samplingrate >= (0x5622 + 0x3E80) / 2) 63 wave_fmt->samplingrate = 0x5622; 64 else if (wave_fmt->samplingrate >= (0x3E80 + 0x2B11) / 2) 65 wave_fmt->samplingrate = 0x3E80; 66 else if (wave_fmt->samplingrate >= (0x2B11 + 0x1F40) / 2) 67 wave_fmt->samplingrate = 0x2B11; 68 else 69 wave_fmt->samplingrate = 0x1F40; 70 71 switch (wave_fmt->id) { 72 case AFMT_S16_LE: 73 wave_fmt->bitsperchannel = 16; 74 break; 75 case AFMT_U8: 76 wave_fmt->bitsperchannel = 8; 77 break; 78 default: 79 wave_fmt->id = AFMT_S16_LE; 80 wave_fmt->bitsperchannel = 16; 81 break; 82 } 83 84 break; 85 86 /* these can't be changed from the original values */ 87 case WAVERECORD_MIC: 88 case WAVERECORD_FX: 89 break; 90 91 default: 92 BUG(); 93 break; 94 } 95 96 wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3; 97 wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel; 98 wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate; 99 wave_fmt->bytespervoicesample = wave_fmt->bytespersample; 100} 101 102static int alloc_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer) 103{ 104 buffer->addr = pci_alloc_consistent(card->pci_dev, buffer->size * buffer->cov, 105 &buffer->dma_handle); 106 if (buffer->addr == NULL) 107 return -1; 108 109 return 0; 110} 111 112static void free_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer) 113{ 114 if (buffer->addr != NULL) 115 pci_free_consistent(card->pci_dev, buffer->size * buffer->cov, 116 buffer->addr, buffer->dma_handle); 117} 118 119int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev) 120{ 121 struct emu10k1_card *card = wave_dev->card; 122 struct wiinst *wiinst = wave_dev->wiinst; 123 struct wiinst **wiinst_tmp = NULL; 124 u16 delay; 125 unsigned long flags; 126 127 DPF(2, "emu10k1_wavein_open()\n"); 128 129 switch (wiinst->recsrc) { 130 case WAVERECORD_AC97: 131 wiinst_tmp = &card->wavein.ac97; 132 break; 133 case WAVERECORD_MIC: 134 wiinst_tmp = &card->wavein.mic; 135 break; 136 case WAVERECORD_FX: 137 wiinst_tmp = &card->wavein.fx; 138 break; 139 default: 140 BUG(); 141 break; 142 } 143 144 spin_lock_irqsave(&card->lock, flags); 145 if (*wiinst_tmp != NULL) { 146 spin_unlock_irqrestore(&card->lock, flags); 147 return -1; 148 } 149 150 *wiinst_tmp = wiinst; 151 spin_unlock_irqrestore(&card->lock, flags); 152 153 /* handle 8 bit recording */ 154 if (wiinst->format.bytesperchannel == 1) { 155 if (wiinst->buffer.size > 0x8000) { 156 wiinst->buffer.size = 0x8000; 157 wiinst->buffer.sizeregval = 0x1f; 158 } else 159 wiinst->buffer.sizeregval += 4; 160 161 wiinst->buffer.cov = 2; 162 } else 163 wiinst->buffer.cov = 1; 164 165 if (alloc_buffer(card, &wiinst->buffer) < 0) { 166 ERROR(); 167 return -1; 168 } 169 170 emu10k1_set_record_src(card, wiinst); 171 172 emu10k1_reset_record(card, &wiinst->buffer); 173 174 wiinst->buffer.hw_pos = 0; 175 wiinst->buffer.pos = 0; 176 wiinst->buffer.bytestocopy = 0; 177 178 delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec; 179 180 emu10k1_timer_install(card, &wiinst->timer, delay / 2); 181 182 wiinst->state = WAVE_STATE_OPEN; 183 184 return 0; 185} 186 187void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev) 188{ 189 struct emu10k1_card *card = wave_dev->card; 190 struct wiinst *wiinst = wave_dev->wiinst; 191 unsigned long flags; 192 193 DPF(2, "emu10k1_wavein_close()\n"); 194 195 emu10k1_wavein_stop(wave_dev); 196 197 emu10k1_timer_uninstall(card, &wiinst->timer); 198 199 free_buffer(card, &wiinst->buffer); 200 201 spin_lock_irqsave(&card->lock, flags); 202 switch (wave_dev->wiinst->recsrc) { 203 case WAVERECORD_AC97: 204 card->wavein.ac97 = NULL; 205 break; 206 case WAVERECORD_MIC: 207 card->wavein.mic = NULL; 208 break; 209 case WAVERECORD_FX: 210 card->wavein.fx = NULL; 211 break; 212 default: 213 BUG(); 214 break; 215 } 216 spin_unlock_irqrestore(&card->lock, flags); 217 218 wiinst->state = WAVE_STATE_CLOSED; 219} 220 221void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev) 222{ 223 struct emu10k1_card *card = wave_dev->card; 224 struct wiinst *wiinst = wave_dev->wiinst; 225 226 DPF(2, "emu10k1_wavein_start()\n"); 227 228 emu10k1_start_record(card, &wiinst->buffer); 229 emu10k1_timer_enable(wave_dev->card, &wiinst->timer); 230 231 wiinst->state |= WAVE_STATE_STARTED; 232} 233 234void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev) 235{ 236 struct emu10k1_card *card = wave_dev->card; 237 struct wiinst *wiinst = wave_dev->wiinst; 238 239 DPF(2, "emu10k1_wavein_stop()\n"); 240 241 if (!(wiinst->state & WAVE_STATE_STARTED)) 242 return; 243 244 emu10k1_timer_disable(card, &wiinst->timer); 245 emu10k1_stop_record(card, &wiinst->buffer); 246 247 wiinst->state &= ~WAVE_STATE_STARTED; 248} 249 250int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format) 251{ 252 struct emu10k1_card *card = wave_dev->card; 253 struct wiinst *wiinst = wave_dev->wiinst; 254 u16 delay; 255 256 DPF(2, "emu10k1_wavein_setformat()\n"); 257 258 if (wiinst->state & WAVE_STATE_STARTED) 259 return -1; 260 261 query_format(wiinst->recsrc, format); 262 263 if ((wiinst->format.samplingrate != format->samplingrate) 264 || (wiinst->format.bitsperchannel != format->bitsperchannel) 265 || (wiinst->format.channels != format->channels)) { 266 267 wiinst->format = *format; 268 269 if (wiinst->state == WAVE_STATE_CLOSED) 270 return 0; 271 272 wiinst->buffer.size *= wiinst->buffer.cov; 273 274 if (wiinst->format.bytesperchannel == 1) { 275 wiinst->buffer.cov = 2; 276 wiinst->buffer.size /= wiinst->buffer.cov; 277 } else 278 wiinst->buffer.cov = 1; 279 280 emu10k1_timer_uninstall(card, &wiinst->timer); 281 282 delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec; 283 284 emu10k1_timer_install(card, &wiinst->timer, delay / 2); 285 } 286 287 return 0; 288} 289 290void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size) 291{ 292 struct wavein_buffer *buffer = &wiinst->buffer; 293 294 *size = buffer->bytestocopy; 295 296 if (wiinst->mmapped) 297 return; 298 299 if (*size > buffer->size) { 300 *size = buffer->size; 301 buffer->pos = buffer->hw_pos; 302 buffer->bytestocopy = buffer->size; 303 DPF(1, "buffer overrun\n"); 304 } 305} 306 307static int copy_block(u8 __user *dst, u8 * src, u32 str, u32 len, u8 cov) 308{ 309 if (cov == 1) { 310 if (__copy_to_user(dst, src + str, len)) 311 return -EFAULT; 312 } else { 313 u8 byte; 314 u32 i; 315 316 src += 1 + 2 * str; 317 318 for (i = 0; i < len; i++) { 319 byte = src[2 * i] ^ 0x80; 320 if (__copy_to_user(dst + i, &byte, 1)) 321 return -EFAULT; 322 } 323 } 324 325 return 0; 326} 327 328int emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 __user *data, u32 * size) 329{ 330 struct wavein_buffer *buffer = &wiinst->buffer; 331 u32 sizetocopy, sizetocopy_now, start; 332 unsigned long flags; 333 int ret; 334 335 sizetocopy = min_t(u32, buffer->size, *size); 336 *size = sizetocopy; 337 338 if (!sizetocopy) 339 return 0; 340 341 spin_lock_irqsave(&wiinst->lock, flags); 342 start = buffer->pos; 343 buffer->pos += sizetocopy; 344 buffer->pos %= buffer->size; 345 buffer->bytestocopy -= sizetocopy; 346 sizetocopy_now = buffer->size - start; 347 348 spin_unlock_irqrestore(&wiinst->lock, flags); 349 350 if (sizetocopy > sizetocopy_now) { 351 sizetocopy -= sizetocopy_now; 352 353 ret = copy_block(data, buffer->addr, start, sizetocopy_now, 354 buffer->cov); 355 if (ret == 0) 356 ret = copy_block(data + sizetocopy_now, buffer->addr, 0, 357 sizetocopy, buffer->cov); 358 } else { 359 ret = copy_block(data, buffer->addr, start, sizetocopy, 360 buffer->cov); 361 } 362 363 return ret; 364} 365 366void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst) 367{ 368 u32 hw_pos; 369 u32 diff; 370 371 /* There is no actual start yet */ 372 if (!(wiinst->state & WAVE_STATE_STARTED)) { 373 hw_pos = wiinst->buffer.hw_pos; 374 } else { 375 /* hw_pos in byte units */ 376 hw_pos = sblive_readptr(card, wiinst->buffer.idxreg, 0) / wiinst->buffer.cov; 377 } 378 379 diff = (wiinst->buffer.size + hw_pos - wiinst->buffer.hw_pos) % wiinst->buffer.size; 380 wiinst->total_recorded += diff; 381 wiinst->buffer.bytestocopy += diff; 382 383 wiinst->buffer.hw_pos = hw_pos; 384} 385