--- Linux/drivers/sound/i810_audio.c Tue Apr 17 18:06:46 2001 +++ linux/drivers/sound/i810_audio.c Tue Apr 17 18:14:17 2001 @@ -323,6 +323,10 @@ struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *); struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *); void (*free_pcm_channel)(struct i810_card *, int chan); + + /* We have a *very* long init time possibly, so use this to block */ + /* attempts to open our devices before we are ready (stops oops'es) */ + int initializing; }; static struct i810_card *devs = NULL; @@ -1738,7 +1742,9 @@ /* find an avaiable virtual channel (instance of /dev/dsp) */ while (card != NULL) { - for (i = 0; i < NR_HW_CH; i++) { + for (i = 0; i < 50 && card->initializing; i++) + schedule_timeout(HZ/20); + for (i = 0; i < NR_HW_CH && !card->initializing; i++) { if (card->states[i] == NULL) { state = card->states[i] = (struct i810_state *) kmalloc(sizeof(struct i810_state), GFP_KERNEL); @@ -1885,13 +1887,16 @@ int minor = MINOR(inode->i_rdev); struct i810_card *card = devs; - for (card = devs; card != NULL; card = card->next) - for (i = 0; i < NR_AC97; i++) + for (card = devs; card != NULL; card = card->next) { + for (i = 0; i < 50 && card->initializing; i++) + schedule_timeout(HZ/20); + for (i = 0; i < NR_AC97 && !card->initializing; i++) if (card->ac97_codec[i] != NULL && card->ac97_codec[i]->dev_mixer == minor) { file->private_data = card->ac97_codec[i]; return 0; } + } return -ENODEV; } @@ -2023,6 +2028,75 @@ return num_ac97; } +static void __init i810_configure_clocking (void) +{ + struct i810_card *card; + struct i810_state *state; + struct dmabuf *dmabuf; + unsigned int i, offset, new_offset; + unsigned long flags; + + card = devs; + /* We could try to set the clocking for multiple cards, but can you even have + * more than one i810 in a machine? Besides, clocking is global, so unless + * someone actually thinks more than one i810 in a machine is possible and + * decides to rewrite that little bit, setting the rate for more than one card + * is a waste of time. + */ + if(card != NULL) { + state = card->states[0] = (struct i810_state *) + kmalloc(sizeof(struct i810_state), GFP_KERNEL); + if (state == NULL) + return; + memset(state, 0, sizeof(struct i810_state)); + dmabuf = &state->dmabuf; + + dmabuf->write_channel = card->alloc_pcm_channel(card); + state->virt = 0; + state->card = card; + state->magic = I810_STATE_MAGIC; + init_waitqueue_head(&dmabuf->wait); + init_MUTEX(&state->open_sem); + dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT; + dmabuf->trigger = PCM_ENABLE_OUTPUT; + i810_set_dac_rate(state, 48000); + if(prog_dmabuf(state, 0) != 0) { + goto config_out_nodmabuf; + } + if(dmabuf->dmasize < 16384) { + goto config_out; + } + dmabuf->count = dmabuf->dmasize; + outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI); + save_flags(flags); + cli(); + start_dac(state); + offset = i810_get_dma_addr(state, 0); + mdelay(50); + new_offset = i810_get_dma_addr(state, 0); + stop_dac(state); + outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR); + restore_flags(flags); + i = new_offset - offset; +#ifdef DEBUG + printk("i810_audio: %d bytes in 50 milliseconds\n", i); +#endif + if(i == 0) + goto config_out; + i = i / 4 * 20; + if (i > 48500 || i < 47500) { + clocking = clocking * clocking / i; + printk("i810_audio: setting clocking to %d\n", clocking); + } +config_out: + dealloc_dmabuf(state); +config_out_nodmabuf: + state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num); + kfree(state); + card->states[0] = NULL; + } +} + /* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ @@ -2030,21 +2104,21 @@ { struct i810_card *card; - if (pci_enable_device(pci_dev)) - return -EIO; - - if (pci_set_dma_mask(pci_dev, I810_DMA_MASK)) { + if (!pci_dma_supported(pci_dev, I810_DMA_MASK)) { printk(KERN_ERR "intel810: architecture does not support" " 32bit PCI busmaster DMA\n"); return -ENODEV; } + if (pci_enable_device(pci_dev)) + return -EIO; if ((card = kmalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "i810_audio: out of memory\n"); return -ENOMEM; } memset(card, 0, sizeof(*card)); + card->initializing = 1; card->iobase = pci_resource_start (pci_dev, 1); card->ac97base = pci_resource_start (pci_dev, 0); card->pci_dev = pci_dev; @@ -2108,6 +2182,11 @@ return -ENODEV; } pci_dev->driver_data = card; + pci_dev->dma_mask = I810_DMA_MASK; + if(clocking == 48000) { + i810_configure_clocking(); + } + card->initializing = 0; return 0; } @@ -2146,75 +2225,6 @@ remove: i810_remove, }; -static void __init i810_configure_clocking (void) -{ - struct i810_card *card; - struct i810_state *state; - struct dmabuf *dmabuf; - unsigned int i, offset, new_offset; - unsigned long flags; - - card = devs; - /* We could try to set the clocking for multiple cards, but can you even have - * more than one i810 in a machine? Besides, clocking is global, so unless - * someone actually thinks more than one i810 in a machine is possible and - * decides to rewrite that little bit, setting the rate for more than one card - * is a waste of time. - */ - if(card != NULL) { - state = card->states[0] = (struct i810_state *) - kmalloc(sizeof(struct i810_state), GFP_KERNEL); - if (state == NULL) - return; - memset(state, 0, sizeof(struct i810_state)); - dmabuf = &state->dmabuf; - - dmabuf->write_channel = card->alloc_pcm_channel(card); - state->virt = 0; - state->card = card; - state->magic = I810_STATE_MAGIC; - init_waitqueue_head(&dmabuf->wait); - init_MUTEX(&state->open_sem); - dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT; - dmabuf->trigger = PCM_ENABLE_OUTPUT; - i810_set_dac_rate(state, 48000); - if(prog_dmabuf(state, 0) != 0) { - goto config_out_nodmabuf; - } - if(dmabuf->dmasize < 16384) { - goto config_out; - } - dmabuf->count = dmabuf->dmasize; - outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI); - save_flags(flags); - cli(); - start_dac(state); - offset = i810_get_dma_addr(state, 0); - mdelay(50); - new_offset = i810_get_dma_addr(state, 0); - stop_dac(state); - outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR); - restore_flags(flags); - i = new_offset - offset; -#ifdef DEBUG - printk("i810_audio: %d bytes in 50 milliseconds\n", i); -#endif - if(i == 0) - goto config_out; - i = i / 4 * 20; - if (i > 48500 || i < 47500) { - clocking = clocking * clocking / i; - printk("i810_audio: setting clocking to %d\n", clocking); - } -config_out: - dealloc_dmabuf(state); -config_out_nodmabuf: - state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num); - kfree(state); - card->states[0] = NULL; - } -} - static int __init i810_init_module (void) { if (!pci_present()) /* No PCI bus in this machine! */ @@ -2229,9 +2239,6 @@ } if(ftsodell != 0) { printk("i810_audio: ftsodell is now a deprecated option.\n"); - } - if(clocking == 48000) { - i810_configure_clocking(); } return 0; }