paep.c

来自「这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自」· C语言 代码 · 共 1,171 行 · 第 1/3 页

C
1,171
字号
		 *  timed out because the completion and timeout happened		 *  at about the same time. Therfore, we can't use information		 *  about the process (timeout) to tell what		 *  happened.		 */	if (dev_param_p->read_state == RS_DMA_COMPLETE) 	{				/* we did complete */#ifdef INSTRUMENT			++dev_param_p->read_dma_cnt;			dev_param_p->read_byte_cnt += count - dev_param_p->read_residual;#endif /* INSTRUMENT */			dev_param_p->read_state = RS_IDLE;			DPRINTK("copying 0x%08X bytes from 0x%p to 0x%p\n",					count, dev_param_p->read_dma_buf_p, buf_p);			copy_to_user(buf_p, dev_param_p->read_dma_buf_p, count - dev_param_p->read_residual);  	} 	else 	{				/* timeout or error */			dev_param_p->read_state = RS_IDLE;			return -ETIME;	}		/* Now that we're really done, */	return (count - dev_param_p->read_residual);}/* *  Write function * *  Since there is no supported way in Linux to DMA from a user space buffer *  to a PCI device, we have to copy the user data to a buffer and DMA from *  there. The best we can do is to allocate a buffer for this purpose and *  repeatedly copy and DMA through that buffer until all the user's data *  has been sent to the device. The size of the buffer may be set at module *  load time through the variable aep_dma_buff_order. */static ssize_t write_aep(struct file *file_p, const char *buf_p, size_t size, loff_t *ppos_p){        paep_unit_info_t *dev_param_p = file_p->private_data;        DMA_msg_t msg;        unsigned int targ_msg; /* address of message */        wait_queue_t local_wq;        assert(file_p && buf_p);            BANNER();        DPRINTK("file_p = %p, buf_p = %p, size = %d, ppos_p = %p\n", file_p, buf_p, size, ppos_p);        init_waitqueue_entry(&local_wq, current);        dev_param_p->write_fail_reason = 0;    #ifdef INSTRUMENT        ++dev_param_p->write_cnt;#endif /* INSTRUMENT */        down(&dev_param_p->aep_sem);            /*             *  Copy the user data into the buffer up to the buffer size             *  This may cause the calling process to suspend if it's             *  data is not paged in             */        copy_from_user(dev_param_p->write_dma_buf_p, buf_p, size); /* may suspend */               DPRINTK("setting up DMA\n");            /* Set up the DMA and initiate it */            make_dma_msg(&msg, DMA_DEVICE_WRITE, virt_to_bus(dev_param_p->write_dma_buf_p), size);        targ_msg = get_msg_ptr(dev_param_p);        exit_if_invalid_msg_ptr(targ_msg, dev_param_p);            /* Write the message we just made to the device */        write_dma_msg(&msg, dev_param_p, targ_msg);            add_wait_queue(&dev_param_p->wq, &local_wq);        current->state=TASK_INTERRUPTIBLE;            post_msg(targ_msg, dev_param_p);                /* Suspend the process with a timeout in case our device goes to lunch */        schedule_timeout(IO_TIMEOUT * HZ);        remove_wait_queue(&dev_param_p->wq, &local_wq);            /*             *  Determine whether we completed, or timed out. Note that             *  there is a small chance here that we both completed and             *  timed out because the completion and timeout happened             *  at about the same time. Therfore, we can't use information             *  about the process (timeout) to tell what             *  happened.             */        if (dev_param_p->write_state == WS_DMA_COMPLETE) 		{                DPRINTK("DMA completed normally\n");                dev_param_p->write_state = WS_IDLE;                up(&dev_param_p->aep_sem);#ifdef INSTRUMENT                ++dev_param_p->write_dma_cnt;                dev_param_p->write_byte_cnt += this_size;#endif /* INSTRUMENT */        } 		else if (dev_param_p->write_fail_reason == DMA_WRITE_ERROR) 		{                        dev_param_p->write_state = WS_IDLE;                up(&dev_param_p->aep_sem);                ERR_PRINTK("Write error (returning -EIO)\n");                return -EIO;                } 		else if (dev_param_p->write_fail_reason == DMA_WRITE_NO_SPACE) 		{	                      /* don't print this for now, as it saturates /var/log/messages with the vsa / sar                     * Not a driver issue. VF                      *  WARN_PRINTK("Write completed with no space on device (returning -EAGAIN)\n");                     */                         dev_param_p->write_state = WS_IDLE;                 up(&dev_param_p->aep_sem);                return -EAGAIN;        } else 		{                        WARN_PRINTK("Write completed with timeout (returning -ETIME)\n");                dev_param_p->write_state = WS_IDLE;                up(&dev_param_p->aep_sem);                return -ETIME;        }            return (size);}static size_t poll_aep(struct file *file_p, poll_table *wait){	paep_unit_info_t *dev_param_p = file_p->private_data;	unsigned int	mask = 0;	poll_wait(file_p, &dev_param_p->select_wq, wait);		if(dev_param_p->flags & READ_DATA_AVAILABLE){		mask = POLLIN | POLLRDNORM;	}	else{		mask = 0;	}	return(mask);}/* *  Open function Note that we do not request the IRQ here because of an errata that exists on the IXP1200's PCI interface.  The errata effectively means that the host has no way to turn off device interrupts so rather than request and return the irq in the open and release methods, we just grab an irq at init.  This problem manifested itself when a process using the device was killed, the release method waould be called and an interrupt would come in just after the irq was returned, resulting in a kernel crash */static int open_aep(struct inode *inode_p, struct file *file_p){        int retval = 0; /* success */        int unit_no;        struct pci_dev   *dev_p = NULL;        paep_unit_info_t *dev_param_p = NULL;        BANNER();        assert(inode_p && file_p);            unit_no = MINOR(inode_p->i_rdev);        exit_if_too_many_cards(unit_no);                if (unit_no >= nb_cards)        	return -ENODEV;            dev_p = dev_list_pp[unit_no];        dev_param_p = dev_p->driver_data;                DPRINTK("unit %d\n", unit_no);        if (dev_p == NULL)                return -ENODEV;        assert(dev_param_p);            file_p->private_data = dev_param_p;        down(&dev_param_p->aep_sem);        DPRINTK("entered mutex\n");            /* this is strictly an internal sanity check */        if ((dev_param_p->read_state != RS_IDLE) || (dev_param_p->write_state != WS_IDLE)) 		{                DPRINTK("invalid state(s) (failing)\n");                retval = -EBUSY;                goto open_release_mutex_and_exit;        }            /* only allow a single open of the device */        if (dev_param_p->flags & DEV_OPEN) 		{                DPRINTK("busy (failing)\n");#ifdef INSTRUMENT                ++dev_param_p->open_busy_cnt;#endif/*INSTRUMENT*/                retval = -EBUSY;                goto open_release_mutex_and_exit;        } else {                    /* Claim all the per-card resources we need                        interrupt - getting it here allows other cards to use it */                DPRINTK("allocating read buffer of order %d\n", dma_buff_order);                dev_param_p->read_dma_buf_p = (char *)__get_dma_pages(GFP_KERNEL, dma_buff_order);                if (!dev_param_p->read_dma_buf_p) 				{                                    ERR_PRINTK("Couldn't allocate memory for dma read buffer (returning -ENOMEM)\n");                        retval = -ENOMEM;                        goto open_release_mutex_and_exit;                }                        DPRINTK("allocated read buffer at 0x%p\n", dev_param_p->read_dma_buf_p);                DPRINTK("allocating write buffer of order %d\n", dma_buff_order);                        dev_param_p->write_dma_buf_p = (char *)__get_dma_pages(GFP_KERNEL, dma_buff_order);                if (!dev_param_p->write_dma_buf_p) 				{                                    ERR_PRINTK("Couldn't allocate memory for dma write buffer (returning -ENOMEM)\n");                        retval = -ENOMEM;                        goto open_release_mutex_and_exit;                }                        DPRINTK("allocated write buffer at 0x%p\n", dev_param_p->write_dma_buf_p);        }#ifdef INSTRUMENT        ++dev_param_p->open_cnt;#endif/*INSTRUMENT*/        MOD_INC_USE_COUNT;        dev_param_p->flags |= DEV_OPEN;            /*             * If the device was last closed while active, then we may have missed an interrupt,             * and there may be data on the device. We go ahead and set READ_DATA_AVAILABLE.             * If there isn't data on the device, the first read simply completes with             * zero bytes read             */		dev_param_p->flags |= READ_DATA_AVAILABLE;		up(&dev_param_p->read_sem);  open_release_mutex_and_exit:        up(&dev_param_p->aep_sem);        DPRINTK("left mutex and returning %d\n", retval);        return retval;}/* *  Release function */static int release_aep(struct inode *inode_p, struct file *file_p){        int unit_no;        int retval = 0;        struct pci_dev   *dev_p;        paep_unit_info_t *dev_param_p;        assert(inode_p && file_p);            BANNER();        unit_no = MINOR(inode_p->i_rdev);        exit_if_too_many_cards(unit_no);                dev_p = dev_list_pp[unit_no];        dev_param_p = dev_p->driver_data;            DPRINTK("unit %d\n", unit_no);            /* validity checks */        if (dev_param_p == 0)                return -EINVAL;            if (!(dev_param_p->flags & DEV_OPEN))                return -ENODEV;            /* enter the mutex for this device */        down(&dev_param_p->aep_sem);        dev_param_p->flags &= ~DEV_OPEN;              /* make the device available again */        dev_param_p->flags &= ~WAITING_FOR_READ_DATA; /* and reset this flag, too */            /*             * If the user process was interrupted, we may have to reset state.             * If the device is DEAD, the first operation on the next open will             * fail, and reset the state.             */            dev_param_p->write_state = WS_IDLE;        dev_param_p->read_state = RS_IDLE;        if (dev_param_p->read_dma_buf_p) {                        DPRINTK("freeing read buffer 0x%p\n", dev_param_p->read_dma_buf_p);                free_pages((unsigned long) dev_param_p->read_dma_buf_p, dma_buff_order);                dev_param_p->read_dma_buf_p = 0;        }        if (dev_param_p->write_dma_buf_p) {                        DPRINTK("freeing write buffer 0x%p\n", dev_param_p->write_dma_buf_p);                free_pages((unsigned long) dev_param_p->write_dma_buf_p, dma_buff_order);                dev_param_p->write_dma_buf_p = 0;        }#ifdef INSTRUMENT        ++dev_param_p->close_cnt;#endif/*INSTRUMENT*/            MOD_DEC_USE_COUNT;        dev_param_p->flags &= ~DEV_OPEN;        up(&dev_param_p->aep_sem);            DPRINTK("returning %d\n", retval);        return retval;}/* *  Interrupt handler routine * *  Called when: *  1) a DMA transfer has completed successfully *  2) a DMA transfer has completed unsuccessfully due to a bad transfer *  3) a DMA transfer has completed unsuccessfully due to lack of space *  4) the target has data to be read * */void aep_interrupt_handler(int irq, void *dev_id_p, struct pt_regs *regs_p){        register struct pci_dev   *dev_p = (struct pci_dev*) dev_id_p;        register paep_unit_info_t *dev_param_p = dev_p->driver_data;        u32 status;        assert(dev_id_p && regs_p);            BANNER();#ifdef INSTRUMENT        ++dev_param_p->interrupt_cnt;#endif /* INSTRUMENT */        status = read_pci_status(dev_p);             /* if it's anything but the doorbell int, then it's not ours */        if (!(status & PCI_DOORBELL_INT))                return;            /* figure out which doorbell interrupt woke us */        status = read_doorbell_status(dev_p);            /* -spc- We handle every possible interrupt here, so that if more             * than one cause has asserted we don't leave this handler without             * clearing it by setting the relevant doorbell bits              */        if (status & SIGNAL_DRIVER) {#ifdef INSTRUMENT                ++dev_param_p->SIGNAL_DRIVER_int_cnt;#endif/*INSTRUMENT*/                        acknowledge_irq(SIGNAL_DRIVER, dev_p);

⌨️ 快捷键说明

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