⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ibmcsiti.c

📁 tlv320aic23的源码
💻 C
📖 第 1 页 / 共 5 页
字号:

static struct i2c_client_address_data ibmcsi_i2c_address_data = {
	.normal_i2c		= normal_i2c,
	.normal_i2c_range	= dummy_i2c_addrlist,
	.probe			= dummy_i2c_addrlist,
	.probe_range		= dummy_i2c_addrlist,
	.ignore			= dummy_i2c_addrlist,
	.ignore_range		= dummy_i2c_addrlist,
	.force			= dummy_i2c_addrlist,
};

static int ibmcsi_i2c_id; /* = 0 */

static int ibmcsi_i2c_attach_adapter(struct i2c_adapter *adap)
{
	return i2c_probe(adap, &ibmcsi_i2c_address_data,
			 &ibmcsi_i2c_detect_client);
}

static int ibmcsi_i2c_detach_client(struct i2c_client *client)
{
	printk(KERN_WARNING "ibmcsiti: ibmcsi_i2c_detach_client() called. "
	       "Don't know how to cope :-(\n");
	return 0;
}

static void ibmcsi_i2c_inc_use(struct i2c_client *client)
{
	MOD_INC_USE_COUNT;
}

static void ibmcsi_i2c_dec_use(struct i2c_client *client)
{
	MOD_DEC_USE_COUNT;
}

static int ibmcsi_i2c_detect_client(struct i2c_adapter *adap, int addr, 
				    unsigned short flags, int kind)
{
	int err = 0;
	struct i2c_client *client;
	struct ibmcsiti_state *data;
	
	printk("ibmcsi_i2c_detect_client(): addr=%x\n", addr);

	if (! i2c_check_functionality(adap, I2C_FUNC_I2C)) {
		printk(KERN_ERR "ibmcsiti: I2C bus lacks functionality\n");
		return -ENODEV;
	}

	/* FIXME: Check the I2C adapter is the one we expect? */

	/* This device is write-only, and hence undetectable.  We just
	 * assume we've been called with the right address... (did I
	 * mention the i2c infrastructure was crap?) */	
	
	client = kmalloc(sizeof(struct i2c_client)
			 + sizeof(struct ibmcsiti_state), GFP_KERNEL);

	if (! client)
		return -ENOMEM;

	/* This is tricky, but it will set the data to the right value. */
	client->data = client + 1;
	data = (struct ibmcsiti_state *)client->data;
	
	client->addr = addr;
	client->adapter = adap;
	client->driver = &ibmcsiti_i2c_driver;
	client->flags = 0;
	strcpy(client->name, "Arctic-2 codec");
	client->id = ibmcsi_i2c_id++; /* FIXME: Racy? */
	
	/* Tell the i2c layer a new client has arrived */
	err = i2c_attach_client(client);
	if (err) {
		printk(KERN_ERR "ibmcsiti: Could not attach I2C client\n");
		goto fail;
	}

	/* Now set up the device */
	err = ibmcsiti_i2c_init(client);
	if (err) {
		i2c_detach_client(client); /* FIXME: ugly, do better */
		goto fail;
	}

	return 0;

 fail:	
	if (client)
		kfree(client);

	return err;
}

/*****************************************************************************/
/*	Part I : DSP device /dev/dsp					     */
/*****************************************************************************/


static int ibmcsiti_dsp_open(struct inode *inode, struct file *file)
{
	int minor = MINOR(inode->i_rdev);
	DECLARE_WAITQUEUE(wait, current);
	unsigned long flags;
	struct list_head *list;
	struct ibmcsiti_state *s;

	for (list = devs.next; ; list = list->next) {
		if (list == &devs)
			return -ENODEV;
		s = list_entry(list, struct ibmcsiti_state, devs);
		if (!((s->dev_dsp ^ minor) & ~0xf))
			break;
	}

       	VALIDATE_STATE(s);

	file->private_data = s;

	/* wait for device to become free */
	down(&s->open_sem);
	while (s->open_mode & file->f_mode) {
		if (file->f_flags & O_NONBLOCK) {
			up(&s->open_sem);
			return -EBUSY;
		}
		add_wait_queue(&s->open_wait, &wait);
		set_current_state(TASK_INTERRUPTIBLE);
		up(&s->open_sem);
		schedule();
		remove_wait_queue(&s->open_wait, &wait);
		set_current_state(TASK_RUNNING);
		if (signal_pending(current))
			return -ERESTARTSYS;
		down(&s->open_sem);
	}
	s->open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE)); 
	spin_lock_irqsave(&s->lock, flags);

	/* FIXME: sampling rate hardcoded */

	{
	struct dma_sgdt *dacp, *adcp;

#define SGDT_COUNT ((PAGE_SIZE/2)/(sizeof(struct dma_sgdt)))

	if (file->f_mode & FMODE_WRITE) {
		s->dac_free_sgdt_q = (struct dma_sgdt *)(s->write_line);
	 	init_sgdt_q(s->dac_free_sgdt_q, SGDT_COUNT);
		/* Prepare default (anchor) descriptor for DAC */
		dacp = s->dac_active_sgdt_q = get_sgdt(&(s->dac_free_sgdt_q));

  		dacp->ccw = (unsigned int)IBMCSI_TXDMA_GO_NOI;

		dacp->nextP = virt_to_phys(dacp); /* Loop in on itself */

		dacp->srcP = virt_to_phys(&(dacp->dummy)); /* Point to dummy data */
		dacp->destP = CSI0_TBUF;
		dacp->dummy = 0;	/* Dummy neutral data (FIXME: currently assumes signed 16 format) */
		dacp->ctrl = 0x80000001; /* Link, count = 1 */
		s->dac_sgdt_lastV = dacp;
		printk("ibmcsi: s = %p dac free_sgdt_q = %p at %p lastV = %p at %p\n",
		       s, s->dac_free_sgdt_q, &s->dac_free_sgdt_q, s->dac_sgdt_lastV, 
		       &s->dac_sgdt_lastV); 
	}

   	if (file->f_mode & FMODE_READ) {
		s->adc_free_sgdt_q = (struct dma_sgdt *)(s->write_line) + SGDT_COUNT;
	 	init_sgdt_q(s->adc_free_sgdt_q, SGDT_COUNT);

#if 0
		/* Prepare default (anchor) descriptor for ADC */
		adcp = s->adc_active_sgdt_q = get_sgdt(&(s->adc_free_sgdt_q));
		adcp->ccw = (unsigned int)IBMCSI_RXDMA_GO_NOI;
		adcp->nextP = virt_to_phys(adcp);
		adcp->ctrl = 0x80000001;

		adcp->srcP = CSI0_RBUF;
		adcp->destP = virt_to_phys(&(adcp->dummy));

		s->adc_sgdt_lastV = adcp;
#endif
		printk("ibmcsi: s = %p adc free_sgdt_q = %p at %p lastV = %p at %p\n",
		       s, s->adc_free_sgdt_q, &s->adc_free_sgdt_q, s->adc_sgdt_lastV,
		       &s->adc_sgdt_lastV); 
	}


	} 

	if (file->f_mode & FMODE_READ) {
		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
		s->dma_adc.enabled = 1;
		/* FIXME: data format hardcoded */

		if ( !(IBMCSI_READ(CSI0_ER) & 1) ) { /* CSI currently not in use */ 
			IBMCSI_WRITE(CSI0_ER, 0); /* Clear enable reg, disable CSI */
			IBMCSI_WRITE(CSI0_SR, CSI_SR_TOD | CSI_SR_ROD); /* Clear CSI errors */
			mtdcr(IBMCSI_RXDMA_CR, 0); 	/* Disable DMA Rx */
			mtdcr(IBMCSI_DMA_SR, DCRN_DMA_SR_ALL(IBMCSI_RXDMA) | 
					     DCRN_DMA_SR_ALL(IBMCSI_TXDMA) ) ;
				 		/* Clear DMA status bits */
		} /* If currently active, assume it's working OK */ 

		init_timer(&s->adc_timer);
		s->adc_timer.function = ibmcsi_adc_timer;
		s->adc_timer.data = (unsigned long)s;
		s->adc_timer.expires = jiffies + ADC_TIMER_PERIOD;
		add_timer(&s->adc_timer);
	}

   	if (file->f_mode & FMODE_WRITE) {
		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags
			= s->dma_dac.subdivision = 0;
		s->dma_dac.enabled = 1;

		/* FIXME: data format hardcoded */

		s->dma_dac.hwptr = 0;
		s->dma_dac.swptr = 0;
		s->dma_dac.count = 0;
		s->dma_dac.sg_count = 0;

		if ( !(IBMCSI_READ(CSI0_ER) & 1) ) { /* CSI currently not in use */ 
			IBMCSI_WRITE(CSI0_ER, 0); /* Clear enable reg, disable CSI */
			IBMCSI_WRITE(CSI0_SR, CSI_SR_TOD | CSI_SR_ROD);	/* Clear CSI errors */
			mtdcr(IBMCSI_TXDMA_CR, 0);	/* Disable DMA Tx */
			mtdcr(IBMCSI_DMA_SR, DCRN_DMA_SR_ALL(IBMCSI_RXDMA) | 
					     DCRN_DMA_SR_ALL(IBMCSI_TXDMA) ) ;
				 		/* Clear DMA status bits */
		}

		init_timer(&s->dac_timer);
		s->dac_timer.function = ibmcsi_dac_timer;
		s->dac_timer.data = (unsigned long)s;
		s->dac_timer.expires = jiffies + DAC_TIMER_PERIOD;
		add_timer(&s->dac_timer);

		DBG(printk("ibmcsi: jiffies %d HZ %d timer %d\n", jiffies, HZ,
			   s->dac_timer.expires));
	}

   	spin_unlock_irqrestore(&s->lock, flags);
	up(&s->open_sem);
 	init_MUTEX(&s->dsp_sem);

	return 0;
}

static ssize_t ibmcsiti_dsp_read(struct file *file, char *buffer,
				 size_t count, loff_t *ppos)
{
	struct ibmcsiti_state *s = (struct ibmcsiti_state *)file->private_data;
	DECLARE_WAITQUEUE(wait, current);
	ssize_t ret = 0;
	unsigned long flags;
	unsigned swptr;
	int cnt;

	VALIDATE_STATE(s);
	if (ppos != &file->f_pos)
		return -ESPIPE;
	if (s->dma_adc.mapped)
		return -ENXIO;
	if (!access_ok(VERIFY_WRITE, buffer, count))
		return -EFAULT;

	down(&s->dsp_sem);

	if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
		goto out;

	add_wait_queue(&s->dma_adc.wait, &wait);
	while (count > 0) {
		spin_lock_irqsave(&s->lock, flags);

		swptr  = s->dma_adc.swptr;
		/* Record curent sgdt for this snapshot */ 

#if 0
		if (s->dma_adc.hwptr >= s->dma_adc.swptr)
			cnt = s->dma_adc.hwptr - swptr;
		else /* HWPTR wrapped */
			cnt = s->dma_adc.dmasize - swptr;

		if (s->dma_adc.count < cnt)
			cnt = s->dma_adc.count;

		if (cnt <= 0)
			set_current_state(TASK_INTERRUPTIBLE);

		if (cnt > count*2) /* cnt is raw (4 bytes per sample),
				    * count is cooked (2 bytes per
				    * sample) */
			cnt = count * 2;

#else /* Change to handle multiple interrupts before a successful read */ 

		cnt = s->dma_adc.count; /* Use the count accumulated
					 * by interrupt handler */

		/* cnt is raw (4 bytes per sample), count is cooked (2
		 * bytes per sample) */
		if (cnt > count*2)
			cnt = count * 2;
		
		if (cnt + swptr > s->dma_adc.dmasize)
			cnt = s->dma_adc.dmasize - swptr; 

		if (cnt > 0) { 
			s->dma_adc.swptr = (swptr + cnt) % s->dma_adc.dmasize;
			DBG(printk("%8.8x %8.8x\n",s->dma_adc.swptr, s->dma_adc.hwptr));
			if (s->dma_adc.swptr <= s->dma_adc.hwptr)  
				s->adc_sw_prev_sgdt = s->adc_hw_prev_sgdt; 
			s->dma_adc.count -= cnt;
		} else {
			set_current_state(TASK_INTERRUPTIBLE);
		}

#endif 
		spin_unlock_irqrestore(&s->lock, flags);

		if (cnt <= 0) { /* No data yet */

			if (s->dma_adc.enabled)
				start_adc(s);
			if (file->f_flags & O_NONBLOCK) {
				if (!ret)
					ret = -EAGAIN;
				goto out;
			}
			up(&s->dsp_sem);
			schedule();
			if (signal_pending(current)) {
				if (!ret)
					ret = -ERESTARTSYS;
				goto out;
			}
			down(&s->dsp_sem);
			if (s->dma_adc.mapped)
			{
				ret = -ENXIO;
				goto out;
			}
			continue;
		}

		if (copy_samples_to_user(buffer, s->dma_adc.rawbuf + swptr,
					 cnt/4, 0)) {
			ret = -EFAULT;
			goto out;
		}

#if 0 /* Change to handle multiple interrupts before read */ 
		swptr = (swptr + cnt) % s->dma_adc.dmasize;
		spin_lock_irqsave(&s->lock, flags);
		s->dma_adc.swptr = swptr;
		s->dma_adc.count -= cnt;
		spin_unlock_irqrestore(&s->lock, flags);
#endif

		count -= cnt/2;
		buffer += cnt/2;
		ret += cnt/2;
		if (s->dma_adc.enabled)
			start_adc(s);
	}
 out:
	up(&s->dsp_sem);
        remove_wait_queue(&s->dma_adc.wait, &wait);
	set_current_state(TASK_RUNNING);
	return ret;
}


static ssize_t ibmcsiti_dsp_write(struct file *file, const char *buffer,
				  size_t inbytes, loff_t *ppos)
{
	struct ibmcsiti_state *s = file->private_data;
	DECLARE_WAITQUEUE(wait, current);
	ssize_t ret = 0;
	unsigned long flags;
	unsigned swptr;
	size_t bytespersample, insamples, outsamples;
	long bufspace;

	VALIDATE_STATE(s);

	if (ppos != &file->f_pos)
		return -ESPIPE;
	if (s->dma_dac.mapped)
		return -ENXIO;
	if (! access_ok(VERIFY_READ, buffer, inbytes))
		return -EFAULT;

	down(&s->dsp_sem);

	bytespersample = s->outstereo ? 4 : 2;

	insamples = inbytes / bytespersample;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -