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

📄 pcilynx.c

📁 这个是uClinux下的ieee1394驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
        return retval;}static ssize_t mem_read(struct file *file, char *buffer, size_t count,                        loff_t *offset){        struct memdata *md = (struct memdata *)file->private_data;        ssize_t bcount;        size_t alignfix;	loff_t off = *offset; /* avoid useless 64bit-arithmetic */        ssize_t retval;        void *membase;	if (*offset != off)	/* Check for EOF before we trust wrap */		return 0;		/* FIXME: Signed wrap is undefined in C - wants fixing up */	if (off + count > off)		return 0;		        if ((off + count) > PCILYNX_MAX_MEMORY + 1) {                count = PCILYNX_MAX_MEMORY + 1 - off;        }        if (count == 0) {                return 0;        }        switch (md->type) {        case rom:                membase = md->lynx->local_rom;                break;        case ram:                membase = md->lynx->local_ram;                break;        case aux:                membase = md->lynx->aux_port;                break;        default:                panic("pcilynx%d: unsupported md->type %d in %s",                      md->lynx->id, md->type, __FUNCTION__);        }        down(&md->lynx->mem_dma_mutex);        if (count < mem_mindma) {                memcpy_fromio(md->lynx->mem_dma_buffer, membase+off, count);                goto out;        }        bcount = count;        alignfix = 4 - (off % 4);        if (alignfix != 4) {                if (bcount < alignfix) {                        alignfix = bcount;                }                memcpy_fromio(md->lynx->mem_dma_buffer, membase+off,                              alignfix);                if (bcount == alignfix) {                        goto out;                }                bcount -= alignfix;                off += alignfix;        }        while (bcount >= 4) {                retval = mem_dmaread(md, md->lynx->mem_dma_buffer_dma                                     + count - bcount, bcount, off);                if (retval < 0) return retval;                bcount -= retval;                off += retval;        }        if (bcount) {                memcpy_fromio(md->lynx->mem_dma_buffer + count - bcount,                              membase+off, bcount);        } out:        retval = copy_to_user(buffer, md->lynx->mem_dma_buffer, count);        up(&md->lynx->mem_dma_mutex);        if (retval < 0) return retval;        *offset += count;        return count;}static ssize_t mem_write(struct file *file, const char *buffer, size_t count,                          loff_t *offset){        struct memdata *md = (struct memdata *)file->private_data;        if (((*offset) + count) > PCILYNX_MAX_MEMORY+1) {                count = PCILYNX_MAX_MEMORY+1 - *offset;        }        if (count == 0 || *offset > PCILYNX_MAX_MEMORY) {                return -ENOSPC;        }        /* FIXME: dereferencing pointers to PCI mem doesn't work everywhere */        switch (md->type) {        case aux:                copy_from_user(md->lynx->aux_port+(*offset), buffer, count);                break;        case ram:                copy_from_user(md->lynx->local_ram+(*offset), buffer, count);                break;        case rom:                /* the ROM may be writeable */                copy_from_user(md->lynx->local_rom+(*offset), buffer, count);                break;        }        file->f_pos += count;        return count;}#endif /* CONFIG_IEEE1394_PCILYNX_PORTS *//******************************************************** * Global stuff (interrupt handler, init/shutdown code) * ********************************************************/static void lynx_irq_handler(int irq, void *dev_id,                             struct pt_regs *regs_are_unused){        struct ti_lynx *lynx = (struct ti_lynx *)dev_id;        struct hpsb_host *host = lynx->host;        u32 intmask;        u32 linkint;        linkint = reg_read(lynx, LINK_INT_STATUS);        intmask = reg_read(lynx, PCI_INT_STATUS);        PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask,               linkint);        if (!(intmask & PCI_INT_INT_PEND)) return;        reg_write(lynx, LINK_INT_STATUS, linkint);        reg_write(lynx, PCI_INT_STATUS, intmask);#ifdef CONFIG_IEEE1394_PCILYNX_PORTS        if (intmask & PCI_INT_AUX_INT) {                atomic_inc(&lynx->aux_intr_seen);                wake_up_interruptible(&lynx->aux_intr_wait);        }        if (intmask & PCI_INT_DMA_HLT(CHANNEL_LOCALBUS)) {                wake_up_interruptible(&lynx->mem_dma_intr_wait);        }#endif        if (intmask & PCI_INT_1394) {                if (linkint & LINK_INT_PHY_TIMEOUT) {                        PRINT(KERN_INFO, lynx->id, "PHY timeout occurred");                }                if (linkint & LINK_INT_PHY_BUSRESET) {                        PRINT(KERN_INFO, lynx->id, "bus reset interrupt");                        lynx->selfid_size = -1;                        lynx->phy_reg0 = -1;                        if (!host->in_bus_reset)                                hpsb_bus_reset(host);                }                if (linkint & LINK_INT_PHY_REG_RCVD) {                        u32 reg;                        spin_lock(&lynx->phy_reg_lock);                        reg = reg_read(lynx, LINK_PHY);                        spin_unlock(&lynx->phy_reg_lock);                        if (!host->in_bus_reset) {                                PRINT(KERN_INFO, lynx->id,                                      "phy reg received without reset");                        } else if (reg & 0xf00) {                                PRINT(KERN_INFO, lynx->id,                                      "unsolicited phy reg %d received",                                      (reg >> 8) & 0xf);                        } else {                                lynx->phy_reg0 = reg & 0xff;                                handle_selfid(lynx, host);                        }                }                if (linkint & LINK_INT_ISO_STUCK) {                        PRINT(KERN_INFO, lynx->id, "isochronous transmitter stuck");                }                if (linkint & LINK_INT_ASYNC_STUCK) {                        PRINT(KERN_INFO, lynx->id, "asynchronous transmitter stuck");                }                if (linkint & LINK_INT_SENT_REJECT) {                        PRINT(KERN_INFO, lynx->id, "sent reject");                }                if (linkint & LINK_INT_TX_INVALID_TC) {                        PRINT(KERN_INFO, lynx->id, "invalid transaction code");                }                if (linkint & LINK_INT_GRF_OVERFLOW) {                        /* flush FIFO if overflow happens during reset */                        if (host->in_bus_reset)                                reg_write(lynx, FIFO_CONTROL,                                          FIFO_CONTROL_GRF_FLUSH);                        PRINT(KERN_INFO, lynx->id, "GRF overflow");                }                if (linkint & LINK_INT_ITF_UNDERFLOW) {                        PRINT(KERN_INFO, lynx->id, "ITF underflow");                }                if (linkint & LINK_INT_ATF_UNDERFLOW) {                        PRINT(KERN_INFO, lynx->id, "ATF underflow");                }        }        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_RCV)) {                PRINTD(KERN_DEBUG, lynx->id, "iso receive");                spin_lock(&lynx->iso_rcv.lock);                lynx->iso_rcv.stat[lynx->iso_rcv.next] =                        reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ISO_RCV));                lynx->iso_rcv.used++;                lynx->iso_rcv.next = (lynx->iso_rcv.next + 1) % NUM_ISORCV_PCL;                if ((lynx->iso_rcv.next == lynx->iso_rcv.last)                    || !lynx->iso_rcv.chan_count) {                        PRINTD(KERN_DEBUG, lynx->id, "stopped");                        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV), 0);                }                run_sub_pcl(lynx, lynx->iso_rcv.pcl_start, lynx->iso_rcv.next,                            CHANNEL_ISO_RCV);                spin_unlock(&lynx->iso_rcv.lock);		tasklet_schedule(&lynx->iso_rcv.tq);        }        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) {                u32 ack;                struct hpsb_packet *packet;                                spin_lock(&lynx->async.queue_lock);                ack = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_SEND));		packet = driver_packet(lynx->async.queue.next);		list_del(&packet->driver_list);                pci_unmap_single(lynx->dev, lynx->async.header_dma,                                 packet->header_size, PCI_DMA_TODEVICE);                if (packet->data_size) {                        pci_unmap_single(lynx->dev, lynx->async.data_dma,                                         packet->data_size, PCI_DMA_TODEVICE);                }                if (!list_empty(&lynx->async.queue)) {                        send_next(lynx, hpsb_async);                }                spin_unlock(&lynx->async.queue_lock);                if (ack & DMA_CHAN_STAT_SPECIALACK) {                        ack = (ack >> 15) & 0xf;                        PRINTD(KERN_INFO, lynx->id, "special ack %d", ack);                        ack = (ack == 1 ? ACKX_TIMEOUT : ACKX_SEND_ERROR);                } else {                        ack = (ack >> 15) & 0xf;                }                                hpsb_packet_sent(host, packet, ack);        }        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) {                struct hpsb_packet *packet;                spin_lock(&lynx->iso_send.queue_lock);		packet = driver_packet(lynx->iso_send.queue.next);		list_del(&packet->driver_list);                pci_unmap_single(lynx->dev, lynx->iso_send.header_dma,                                 packet->header_size, PCI_DMA_TODEVICE);                if (packet->data_size) {                        pci_unmap_single(lynx->dev, lynx->iso_send.data_dma,                                         packet->data_size, PCI_DMA_TODEVICE);                }                if (!list_empty(&lynx->iso_send.queue)) {                        send_next(lynx, hpsb_iso);                }                spin_unlock(&lynx->iso_send.queue_lock);                hpsb_packet_sent(host, packet, ACK_COMPLETE);        }        if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) {                /* general receive DMA completed */                int stat = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_RCV));                PRINTD(KERN_DEBUG, lynx->id, "received packet size %d",                       stat & 0x1fff);                 if (stat & DMA_CHAN_STAT_SELFID) {                        lynx->selfid_size = stat & 0x1fff;                        handle_selfid(lynx, host);                } else {                        quadlet_t *q_data = lynx->rcv_page;                        if ((*q_data >> 4 & 0xf) == TCODE_READQ_RESPONSE                            || (*q_data >> 4 & 0xf) == TCODE_WRITEQ) {                                cpu_to_be32s(q_data + 3);                        }                        hpsb_packet_received(host, q_data, stat & 0x1fff, 0);                }                run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV);        }}static void iso_rcv_bh(struct ti_lynx *lynx){        unsigned int idx;        quadlet_t *data;        unsigned long flags;        spin_lock_irqsave(&lynx->iso_rcv.lock, flags);        while (lynx->iso_rcv.used) {                idx = lynx->iso_rcv.last;                spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);                data = lynx->iso_rcv.page[idx / ISORCV_PER_PAGE]                        + (idx % ISORCV_PER_PAGE) * MAX_ISORCV_SIZE;                if ((*data >> 16) + 4 != (lynx->iso_rcv.stat[idx] & 0x1fff)) {                        PRINT(KERN_ERR, lynx->id,                              "iso length mismatch 0x%08x/0x%08x", *data,                              lynx->iso_rcv.stat[idx]);                }                if (lynx->iso_rcv.stat[idx]                     & (DMA_CHAN_STAT_PCIERR | DMA_CHAN_STAT_PKTERR)) {                        PRINT(KERN_INFO, lynx->id,                              "iso receive error on %d to 0x%p", idx, data);                } else {                        hpsb_packet_received(lynx->host, data,                                             lynx->iso_rcv.stat[idx] & 0x1fff,                                             0);                }                spin_lock_irqsave(&lynx->iso_rcv.lock, flags);                lynx->iso_rcv.last = (idx + 1) % NUM_ISORCV_PCL;                lynx->iso_rcv.used--;        }        if (lynx->iso_rcv.chan_count) {                reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),                          DMA_WORD1_CMP_ENABLE_MASTER);        }        spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);}static void remove_card(struct pci_dev *dev){        struct ti_lynx *lynx;        int i;        lynx = pci_get_drvdata(dev);        if (!lynx) return;        pci_set_drvdata(dev, NULL);        switch (lynx->state) {        case is_host:                reg_write(lynx, PCI_INT_ENABLE, 0);                hpsb_remove_host(lynx->host);        case have_intr:                reg_write(lynx, PCI_INT_ENABLE, 0);                free_irq(lynx->dev->irq, lynx);        case have_iomappings:                reg_set_bits(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET);                /* Fix buggy cards with autoboot pin not tied low: */                reg_write(lynx, DMA0_CHAN_CTRL, 0);                iounmap(lynx->registers);                iounmap(lynx->local_rom);                iounmap(lynx->local_ram);                iounmap(lynx->aux_port);        case have_1394_buffers:                for (i = 0; i < ISORCV_PAGES; i++) {                        if (lynx->iso_rcv.page[i]) {                                pci_free_consistent(lynx->dev, PAGE_SIZE,                                                    lynx->iso_rcv.page[i],                                                    lynx->iso_rcv.page_dma[i]);                        }                }                pci_free_consistent(lynx->dev, PAGE_SIZE, lynx->rcv_page,                                    lynx->rcv_page_dma);        case have_aux_buf:#ifdef CONFIG_IEEE1394_PCILYNX_PORTS                pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer,                                    lynx->mem_dma_buffer_dma);#endif        case have_pcl_mem:#ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM                pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem,                                    lynx->pcl_mem_dma);#endif        case clear:                /* do nothing - already freed */                ;        }	tasklet_kill(&lynx->iso_rcv.tq);	hpsb_unref_host(lynx->host);}static int __devinit add_card(struct pci_dev *dev,                              const struct pci_device_id *devid_is_unused){#define FAIL(fmt, args...) do { \        PRINT_G(KERN_ERR, fmt , ## args); \        remove_card(dev); \        return error; \        } while (0)	struct hpsb_host *host;        struct ti_lynx *lynx; /* shortcut to currently handled device */        struct ti_pcl pcl;        u32 *pcli;        int i;        int error;        /* needed for i2c communication with serial eeprom */        struct i2c_adapter i2c_adapter;        struct i2c_algo_bit_data i2c_adapter_data;

⌨️ 快捷键说明

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