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

📄 gsc_hpdi.c

📁 rtlinux-3.2源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		{			buffer_offset = 0;			buffer_index++;		}		DEBUG_PRINT(" desc %i\n", i );		DEBUG_PRINT(" start addr virt 0x%p, phys 0x%lx\n", priv(dev)->desc_dio_buffer[ i ],			(unsigned long)priv(dev)->dma_desc[ i ].pci_start_addr );		DEBUG_PRINT(" next 0x%lx\n", (unsigned long)priv(dev)->dma_desc[ i ].next );	}	priv(dev)->num_dma_descriptors = i;	// fix last descriptor to point back to first	priv(dev)->dma_desc[ i - 1 ].next =		priv(dev)->dma_desc_phys_addr | next_bits;	DEBUG_PRINT(" desc %i next fixup 0x%lx\n", i - 1,		(unsigned long) priv(dev)->dma_desc[ i - 1 ].next );	priv(dev)->block_size = transfer_size;	return transfer_size;}static int hpdi_attach(comedi_device *dev, comedi_devconfig *it){	struct pci_dev* pcidev;	int i;	int retval;	printk( "comedi%d: gsc_hpdi\n", dev->minor );	if( alloc_private( dev, sizeof( hpdi_private ) ) < 0 )		return -ENOMEM;	pcidev = NULL;	for( i = 0; i < num_boards() && dev->board_ptr == NULL; i++ )	{		do		{			pcidev = pci_find_subsys( PCI_VENDOR_ID_PLX, hpdi_boards[ i ].device_id,				PCI_VENDOR_ID_PLX, hpdi_boards[ i ].subdevice_id, pcidev );			// was a particular bus/slot requested?			if( it->options[0] || it->options[1] )			{				// are we on the wrong bus/slot?				if( pcidev->bus->number != it->options[0] ||					PCI_SLOT( pcidev->devfn ) != it->options[1] )					continue;			}			if( pcidev )			{				dev->board_ptr = hpdi_boards + i;				break;			}		}while( pcidev != NULL );	}	if( dev->board_ptr == NULL )	{		printk("gsc_hpdi: no hpdi card found\n");		return -EIO;	}	printk("gsc_hpdi: found %s on bus %i, slot %i\n", board( dev )->name,		pcidev->bus->number, PCI_SLOT(pcidev->devfn));	if( pci_enable_device( pcidev ) )		return -EIO;	pci_set_master( pcidev );	priv(dev)->hw_dev = pcidev;	//Initialize dev->board_name	dev->board_name = board(dev)->name;	if( pci_request_regions( pcidev, driver_hpdi.driver_name ) )	{		/* Couldn't allocate io space */		printk(KERN_WARNING " failed to allocate io memory\n");		return -EIO;	}	priv(dev)->plx9080_phys_iobase = pci_resource_start(pcidev, PLX9080_BADDRINDEX);	priv(dev)->hpdi_phys_iobase = pci_resource_start(pcidev, HPDI_BADDRINDEX);	// remap, won't work with 2.0 kernels but who cares	priv(dev)->plx9080_iobase = (unsigned long) ioremap( priv(dev)->plx9080_phys_iobase,		pci_resource_len( pcidev, PLX9080_BADDRINDEX ) );	priv(dev)->hpdi_iobase = (unsigned long) ioremap( priv(dev)->hpdi_phys_iobase,		pci_resource_len( pcidev, HPDI_BADDRINDEX ) );	DEBUG_PRINT(" plx9080 remapped to 0x%lx\n", priv(dev)->plx9080_iobase);	DEBUG_PRINT(" hpdi remapped to 0x%lx\n", priv(dev)->hpdi_iobase);	// get irq	if( comedi_request_irq( pcidev->irq, handle_interrupt, SA_SHIRQ, driver_hpdi.driver_name,		 dev ) )	{		printk( " unable to allocate irq %d\n", pcidev->irq );		return -EINVAL;	}	dev->irq = pcidev->irq;	printk(" irq %i\n", dev->irq);	init_plx9080(dev);	// alocate pci dma buffers	for( i = 0; i < NUM_DMA_BUFFERS; i++ )	{		priv(dev)->dio_buffer[ i ] = pci_alloc_consistent( priv(dev)->hw_dev,			DMA_BUFFER_SIZE, &priv(dev)->dio_buffer_phys_addr[ i ] );		DEBUG_PRINT( "dio_buffer at virt 0x%p, phys 0x%lx\n",			priv(dev)->dio_buffer[ i ], (unsigned long) priv(dev)->dio_buffer_phys_addr[ i ]);	}	// allocate dma descriptors	priv(dev)->dma_desc = pci_alloc_consistent( priv(dev)->hw_dev,		sizeof( struct plx_dma_desc ) * NUM_DMA_DESCRIPTORS,		&priv(dev)->dma_desc_phys_addr);	if( priv(dev)->dma_desc_phys_addr & 0xf )	{		printk(" dma descriptors not quad-word aligned (bug)\n");		return -EIO;	}	retval = setup_dma_descriptors( dev, 0x1000 );	if( retval < 0 )		return retval;	retval = setup_subdevices( dev );	if( retval < 0 )		return retval;	return init_hpdi( dev );}static int hpdi_detach(comedi_device *dev){	unsigned int i;	printk( "comedi%d: gsc_hpdi: remove\n", dev->minor );	if( dev->irq )		comedi_free_irq( dev->irq, dev );	if( priv(dev) )	{		if( priv(dev)->hw_dev )		{			if(priv(dev)->plx9080_iobase)			{				disable_plx_interrupts( dev );				iounmap( (void*) priv(dev)->plx9080_iobase );			}			if( priv(dev)->hpdi_iobase )				iounmap((void*)priv(dev)->hpdi_iobase);			if( priv(dev)->plx9080_phys_iobase ||				priv(dev)->hpdi_phys_iobase )				pci_release_regions( priv(dev)->hw_dev );			// free pci dma buffers			for( i = 0; i < NUM_DMA_BUFFERS; i++ )			{				if( priv(dev)->dio_buffer[ i ] )					pci_free_consistent( priv(dev)->hw_dev, DMA_BUFFER_SIZE,						priv(dev)->dio_buffer[ i ], priv(dev)->dio_buffer_phys_addr[ i ] );			}			// free dma descriptors			if( priv(dev)->dma_desc )				pci_free_consistent( priv(dev)->hw_dev, sizeof( struct plx_dma_desc ) *				NUM_DMA_DESCRIPTORS, priv(dev)->dma_desc, priv(dev)->dma_desc_phys_addr );			pci_disable_device( priv(dev)->hw_dev );		}	}	return 0;}static int dio_config_block_size( comedi_device *dev, lsampl_t *data ){	unsigned int requested_block_size;	int retval;	requested_block_size = data[ 1 ];	retval = setup_dma_descriptors( dev, requested_block_size );	if( retval < 0 ) return retval;	data[ 1 ] = retval;	return 2;}static int di_cmd_test(comedi_device *dev,comedi_subdevice *s, comedi_cmd *cmd){	int err = 0;	int tmp;	int i;	/* step 1: make sure trigger sources are trivially valid */	tmp = cmd->start_src;	cmd->start_src &= TRIG_NOW;	if( !cmd->start_src || tmp != cmd->start_src ) err++;	tmp = cmd->scan_begin_src;	cmd->scan_begin_src &= TRIG_EXT;	if( !cmd->scan_begin_src || tmp != cmd->scan_begin_src ) err++;	tmp = cmd->convert_src;	cmd->convert_src &= TRIG_NOW;	if( !cmd->convert_src || tmp != cmd->convert_src ) err++;	tmp = cmd->scan_end_src;	cmd->scan_end_src &= TRIG_COUNT;	if( !cmd->scan_end_src || tmp != cmd->scan_end_src ) err++;	tmp=cmd->stop_src;	cmd->stop_src &= TRIG_COUNT | TRIG_NONE;	if( !cmd->stop_src || tmp != cmd->stop_src ) err++;	if(err) return 1;	/* step 2: make sure trigger sources are unique and mutually compatible */	// uniqueness check	if(cmd->stop_src != TRIG_COUNT &&		cmd->stop_src != TRIG_NONE ) err++;	if(err) return 2;	/* step 3: make sure arguments are trivially compatible */	if( !cmd->chanlist_len )	{		cmd->chanlist_len = 32;		err++;	}	if( cmd->scan_end_arg != cmd->chanlist_len )	{		cmd->scan_end_arg = cmd->chanlist_len;		err++;	}	switch(cmd->stop_src)	{		case TRIG_COUNT:			if(!cmd->stop_arg)			{				cmd->stop_arg = 1;				err++;			}			break;		case TRIG_NONE:			if(cmd->stop_arg != 0)			{				cmd->stop_arg = 0;				err++;			}			break;		default:			break;	}	if(err) return 3;	/* step 4: fix up any arguments */	if(err) return 4;	if( cmd->chanlist )	{		for( i = 1; i < cmd->chanlist_len; i++ )		{			if( CR_CHAN( cmd->chanlist[ i ] ) != i )			{				// XXX could support 8 channels or 16 channels				comedi_error( dev, "chanlist must be channels 0 to 31 in order" );				err++;				break;			}		}	}	if(err) return 5;	return 0;}static int hpdi_cmd_test( comedi_device *dev, comedi_subdevice *s, comedi_cmd *cmd ){	if( priv(dev)->dio_config_output )	{		return -EINVAL;	}else		return di_cmd_test( dev, s, cmd );}static inline void hpdi_writel( comedi_device *dev, uint32_t bits, unsigned int offset ){	writel( bits | priv(dev)->bits[ offset / sizeof( uint32_t ) ],		priv(dev)->hpdi_iobase + offset );}static int di_cmd(comedi_device *dev,comedi_subdevice *s){	uint32_t bits;	unsigned long flags;	comedi_async *async = s->async;	comedi_cmd *cmd = &async->cmd;	hpdi_writel( dev, RX_FIFO_RESET_BIT, BOARD_CONTROL_REG );	DEBUG_PRINT( "hpdi: in di_cmd\n");	abort_dma(dev, 0);	priv(dev)->dma_desc_index = 0;	// give location of first dma descriptor	bits = priv(dev)->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI;	writel( bits, priv(dev)->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG );	// spinlock for plx dma control/status reg	comedi_spin_lock_irqsave( &dev->spinlock, flags );	// enable dma transfer	writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG);	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	if( cmd->stop_src == TRIG_COUNT )		priv(dev)->dio_count = cmd->stop_arg;	else		priv(dev)->dio_count = 1;	// clear over/under run status flags	writel( RX_UNDERRUN_BIT | RX_OVERRUN_BIT, priv(dev)->hpdi_iobase + BOARD_STATUS_REG );	// enable interrupts	writel( intr_bit( RX_FULL_INTR ), priv(dev)->hpdi_iobase + INTERRUPT_CONTROL_REG );	DEBUG_PRINT( "hpdi: starting rx\n");	hpdi_writel( dev, RX_ENABLE_BIT, BOARD_CONTROL_REG );	return 0;}static int hpdi_cmd( comedi_device *dev, comedi_subdevice *s ){	if( priv(dev)->dio_config_output )	{		return -EINVAL;	}else		return di_cmd( dev, s );}static void drain_dma_buffers(comedi_device *dev, unsigned int channel){	comedi_async *async = dev->read_subdev->async;	uint32_t next_transfer_addr;	int j;	int num_samples = 0;	unsigned long pci_addr_reg;	if(channel)		pci_addr_reg = priv(dev)->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG;	else		pci_addr_reg = priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG;	// loop until we have read all the full buffers	j = 0;	for(next_transfer_addr = readl(pci_addr_reg);		(next_transfer_addr < priv(dev)->dma_desc[ priv(dev)->dma_desc_index ].pci_start_addr ||		next_transfer_addr >= priv(dev)->dma_desc[ priv(dev)->dma_desc_index ].pci_start_addr +		priv(dev)->block_size ) &&		j < priv(dev)->num_dma_descriptors;		j++ )	{		// transfer data from dma buffer to comedi buffer		num_samples = priv(dev)->block_size / sizeof( uint32_t );		if( async->cmd.stop_src == TRIG_COUNT )		{			if(num_samples > priv(dev)->dio_count)				num_samples = priv(dev)->dio_count;			priv(dev)->dio_count -= num_samples;		}		cfc_write_array_to_buffer( dev->read_subdev, priv(dev)->desc_dio_buffer[ priv(dev)->dma_desc_index ],			num_samples * sizeof( uint32_t ) );		priv(dev)->dma_desc_index++;		priv(dev)->dma_desc_index %= priv(dev)->num_dma_descriptors;		DEBUG_PRINT("next desc addr 0x%lx\n", (unsigned long)			priv(dev)->dma_desc[ priv(dev)->dma_desc_index ].next );		DEBUG_PRINT("pci addr reg 0x%x\n", next_transfer_addr);	}	// XXX check for buffer overrun somehow}static void handle_interrupt(int irq, void *d, struct pt_regs *regs){	comedi_device *dev = d;	comedi_subdevice *s = dev->read_subdev;	comedi_async *async = s->async;	uint32_t hpdi_intr_status, hpdi_board_status;	uint32_t plx_status;	uint32_t plx_bits;	uint8_t dma0_status, dma1_status;	unsigned long flags;	plx_status = readl( priv(dev)->plx9080_iobase + PLX_INTRCS_REG );	hpdi_intr_status = readl( priv(dev)->hpdi_iobase + INTERRUPT_STATUS_REG );	hpdi_board_status = readl( priv(dev)->hpdi_iobase + BOARD_STATUS_REG );	async->events = 0;	if( hpdi_intr_status )	{		DEBUG_PRINT("hpdi: intr status 0x%x, ", hpdi_intr_status);		writel( hpdi_intr_status, priv(dev)->hpdi_iobase + INTERRUPT_STATUS_REG );	}else if( ( plx_status & ( ICS_DMA0_A | ICS_DMA1_A | ICS_LIA ) ) == 0 )	{		return;	}	// spin lock makes sure noone else changes plx dma control reg	comedi_spin_lock_irqsave( &dev->spinlock, flags );	dma0_status = readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG);	if(plx_status & ICS_DMA0_A)	{	// dma chan 0 interrupt		writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG);		DEBUG_PRINT("dma0 status 0x%x\n", dma0_status);		if(dma0_status & PLX_DMA_EN_BIT)		{			drain_dma_buffers(dev, 0);		}		DEBUG_PRINT(" cleared dma ch0 interrupt\n");	}	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	// spin lock makes sure noone else changes plx dma control reg	comedi_spin_lock_irqsave( &dev->spinlock, flags );	dma1_status = readb(priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG);	if(plx_status & ICS_DMA1_A)	// XXX	{	// dma chan 1 interrupt		writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG);		DEBUG_PRINT("dma1 status 0x%x\n", dma1_status);		DEBUG_PRINT(" cleared dma ch1 interrupt\n");	}	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );	// clear possible plx9080 interrupt sources	if(plx_status & ICS_LDIA)	{ // clear local doorbell interrupt		plx_bits = readl(priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG);		writel(plx_bits, priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG);		DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits);	}	if( hpdi_board_status & RX_OVERRUN_BIT )	{		comedi_error(dev, "rx fifo overrun");		async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;		DEBUG_PRINT( "dma0_status 0x%x\n", (int)readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG));	}	if( hpdi_board_status & RX_UNDERRUN_BIT )	{		comedi_error(dev, "rx fifo underrun");		async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;	}	if( priv(dev)->dio_count == 0 )		async->events |= COMEDI_CB_EOA;	DEBUG_PRINT("board status 0x%x, ", hpdi_board_status);	DEBUG_PRINT("plx status 0x%x\n", plx_status);	if( async->events )		DEBUG_PRINT( " events 0x%x\n", async->events );	cfc_handle_events( dev, s );	return;}void abort_dma( comedi_device *dev, unsigned int channel ){	unsigned long flags;	// spinlock for plx dma control/status reg	comedi_spin_lock_irqsave( &dev->spinlock, flags );	plx9080_abort_dma( priv( dev )->plx9080_iobase, channel );	comedi_spin_unlock_irqrestore( &dev->spinlock, flags );}static int hpdi_cancel( comedi_device *dev, comedi_subdevice *s ){	hpdi_writel( dev, 0, BOARD_CONTROL_REG );		writel( 0, priv(dev)->hpdi_iobase + INTERRUPT_CONTROL_REG );	abort_dma(dev, 0);	return 0;}

⌨️ 快捷键说明

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