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

📄 pcilynx.c

📁 这个是uClinux下的ieee1394驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
                q += 2;                size -= 8;        }        if (!lynx->phyic.reg_1394a && isroot && phyid != 0) {                hpsb_selfid_received(host, lsid);        }        hpsb_selfid_complete(host, phyid, isroot);        if (host->in_bus_reset) return; /* in bus reset again */        if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER);        reg_set_bits(lynx, LINK_CONTROL,                     LINK_CONTROL_RCV_CMP_VALID | LINK_CONTROL_TX_ASYNC_EN                     | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_CYCTIMEREN);}/* This must be called with the respective queue_lock held. */static void send_next(struct ti_lynx *lynx, int what){        struct ti_pcl pcl;        struct lynx_send_data *d;        struct hpsb_packet *packet;        d = (what == hpsb_iso ? &lynx->iso_send : &lynx->async);        packet = driver_packet(d->queue.next);        d->header_dma = pci_map_single(lynx->dev, packet->header,                                       packet->header_size, PCI_DMA_TODEVICE);        if (packet->data_size) {                d->data_dma = pci_map_single(lynx->dev, packet->data,                                             packet->data_size,                                             PCI_DMA_TODEVICE);        } else {                d->data_dma = 0;        }        pcl.next = PCL_NEXT_INVALID;        pcl.async_error_next = PCL_NEXT_INVALID;#ifdef __BIG_ENDIAN        pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size;#else        pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size                 | PCL_BIGENDIAN;#endif        pcl.buffer[0].pointer = d->header_dma;        pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size;        pcl.buffer[1].pointer = d->data_dma;        switch (packet->type) {        case hpsb_async:                pcl.buffer[0].control |= PCL_CMD_XMT;                break;        case hpsb_iso:                pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE;                break;        case hpsb_raw:                pcl.buffer[0].control |= PCL_CMD_UNFXMT;                break;        }                        if (!packet->data_be) {                pcl.buffer[1].control |= PCL_BIGENDIAN;        }        put_pcl(lynx, d->pcl, &pcl);        run_pcl(lynx, d->pcl_start, d->channel);}/* called from subsystem core */static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet){        struct ti_lynx *lynx = host->hostdata;        struct lynx_send_data *d;        unsigned long flags;        if (packet->data_size >= 4096) {                PRINT(KERN_ERR, lynx->id, "transmit packet data too big (%Zd)",                      packet->data_size);                return 0;        }        switch (packet->type) {        case hpsb_async:        case hpsb_raw:                d = &lynx->async;                break;        case hpsb_iso:                d = &lynx->iso_send;                break;        default:                PRINT(KERN_ERR, lynx->id, "invalid packet type %d",                      packet->type);                return 0;        }        if (packet->tcode == TCODE_WRITEQ            || packet->tcode == TCODE_READQ_RESPONSE) {                cpu_to_be32s(&packet->header[3]);        }        spin_lock_irqsave(&d->queue_lock, flags);	list_add_tail(&packet->driver_list, &d->queue);	if (d->queue.next == &packet->driver_list)                send_next(lynx, packet->type);        spin_unlock_irqrestore(&d->queue_lock, flags);        return 1;}/* called from subsystem core */static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg){        struct ti_lynx *lynx = host->hostdata;        int retval = 0;        struct hpsb_packet *packet;	LIST_HEAD(packet_list);        unsigned long flags;        switch (cmd) {        case RESET_BUS:                if (reg_read(lynx, LINK_INT_STATUS) & LINK_INT_PHY_BUSRESET) {                        retval = 0;                        break;                }                if (arg) {                        arg = 3 << 6;                } else {                        arg = 1 << 6;                }                retval = get_phy_reg(lynx, 1);                arg |= (retval == -1 ? 63 : retval);                retval = 0;                PRINT(KERN_INFO, lynx->id, "resetting bus on request");                lynx->selfid_size = -1;                lynx->phy_reg0 = -1;                set_phy_reg(lynx, 1, arg);                break;        case GET_CYCLE_COUNTER:                retval = reg_read(lynx, CYCLE_TIMER);                break;                        case SET_CYCLE_COUNTER:                reg_write(lynx, CYCLE_TIMER, arg);                break;        case SET_BUS_ID:                reg_write(lynx, LINK_ID,                           (arg << 22) | (reg_read(lynx, LINK_ID) & 0x003f0000));                break;                        case ACT_CYCLE_MASTER:                if (arg) {                        reg_set_bits(lynx, LINK_CONTROL,                                     LINK_CONTROL_CYCMASTER);                } else {                        reg_clear_bits(lynx, LINK_CONTROL,                                       LINK_CONTROL_CYCMASTER);                }                break;        case CANCEL_REQUESTS:                spin_lock_irqsave(&lynx->async.queue_lock, flags);                reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0);		list_splice(&lynx->async.queue, &packet_list);		INIT_LIST_HEAD(&lynx->async.queue);                spin_unlock_irqrestore(&lynx->async.queue_lock, flags);		while (!list_empty(&packet_list)) {			packet = driver_packet(packet_list.next);			list_del(&packet->driver_list);			hpsb_packet_sent(host, packet, ACKX_ABORTED);		}                break;        case MODIFY_USAGE:                if (arg) {                        MOD_INC_USE_COUNT;                } else {                        MOD_DEC_USE_COUNT;                }                retval = 1;                break;        case ISO_LISTEN_CHANNEL:                spin_lock_irqsave(&lynx->iso_rcv.lock, flags);                                if (lynx->iso_rcv.chan_count++ == 0) {                        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),                                  DMA_WORD1_CMP_ENABLE_MASTER);                }                spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);                break;        case ISO_UNLISTEN_CHANNEL:                spin_lock_irqsave(&lynx->iso_rcv.lock, flags);                if (--lynx->iso_rcv.chan_count == 0) {                        reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ISO_RCV),                                  0);                }                spin_unlock_irqrestore(&lynx->iso_rcv.lock, flags);                break;        default:                PRINT(KERN_ERR, lynx->id, "unknown devctl command %d", cmd);                retval = -1;        }        return retval;}/*************************************** * IEEE-1394 functionality section END * ***************************************/#ifdef CONFIG_IEEE1394_PCILYNX_PORTS/* VFS functions for local bus / aux device access.  Access to those * is implemented as a character device instead of block devices * because buffers are not wanted for this.  Therefore llseek (from * VFS) can be used for these char devices with obvious effects. */static int mem_open(struct inode*, struct file*);static int mem_release(struct inode*, struct file*);static unsigned int aux_poll(struct file*, struct poll_table_struct*);static loff_t mem_llseek(struct file*, loff_t, int);static ssize_t mem_read (struct file*, char*, size_t, loff_t*);static ssize_t mem_write(struct file*, const char*, size_t, loff_t*);static struct file_operations aux_ops = {	.owner =	THIS_MODULE,        .read =         mem_read,        .write =        mem_write,        .poll =         aux_poll,        .llseek =       mem_llseek,        .open =         mem_open,        .release =      mem_release,};static void aux_setup_pcls(struct ti_lynx *lynx){        struct ti_pcl pcl;        pcl.next = PCL_NEXT_INVALID;        pcl.user_data = pcl_bus(lynx, lynx->dmem_pcl);        put_pcl(lynx, lynx->dmem_pcl, &pcl);}static int mem_open(struct inode *inode, struct file *file){        int cid = minor(inode->i_rdev);        enum { t_rom, t_aux, t_ram } type;        struct memdata *md;                if (cid < PCILYNX_MINOR_AUX_START) {                /* just for completeness */                return -ENXIO;        } else if (cid < PCILYNX_MINOR_ROM_START) {                cid -= PCILYNX_MINOR_AUX_START;                if (cid >= num_of_cards || !cards[cid].aux_port)                        return -ENXIO;                type = t_aux;        } else if (cid < PCILYNX_MINOR_RAM_START) {                cid -= PCILYNX_MINOR_ROM_START;                if (cid >= num_of_cards || !cards[cid].local_rom)                        return -ENXIO;                type = t_rom;        } else {                /* WARNING: Know what you are doing when opening RAM.                 * It is currently used inside the driver! */                cid -= PCILYNX_MINOR_RAM_START;                if (cid >= num_of_cards || !cards[cid].local_ram)                        return -ENXIO;                type = t_ram;        }        md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL);        if (md == NULL)                return -ENOMEM;        md->lynx = &cards[cid];        md->cid = cid;        switch (type) {        case t_rom:                md->type = rom;                break;        case t_ram:                md->type = ram;                break;        case t_aux:                atomic_set(&md->aux_intr_last_seen,                           atomic_read(&cards[cid].aux_intr_seen));                md->type = aux;                break;        }        file->private_data = md;        return 0;}static int mem_release(struct inode *inode, struct file *file){        kfree(file->private_data);        return 0;}static unsigned int aux_poll(struct file *file, poll_table *pt){        struct memdata *md = (struct memdata *)file->private_data;        int cid = md->cid;        unsigned int mask;        /* reading and writing is always allowed */        mask = POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM;        if (md->type == aux) {                poll_wait(file, &cards[cid].aux_intr_wait, pt);                if (atomic_read(&md->aux_intr_last_seen)                    != atomic_read(&cards[cid].aux_intr_seen)) {                        mask |= POLLPRI;                        atomic_inc(&md->aux_intr_last_seen);                }        }        return mask;}loff_t mem_llseek(struct file *file, loff_t offs, int orig){        loff_t newoffs;        switch (orig) {        case 0:                newoffs = offs;                break;        case 1:                newoffs = offs + file->f_pos;                break;        case 2:                newoffs = PCILYNX_MAX_MEMORY + 1 + offs;                break;        default:                return -EINVAL;        }        if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL;        file->f_pos = newoffs;        return newoffs;}/*  * do not DMA if count is too small because this will have a serious impact  * on performance - the value 2400 was found by experiment and may not work * everywhere as good as here - use mem_mindma option for modules to change  */short mem_mindma = 2400;MODULE_PARM(mem_mindma, "h");static ssize_t mem_dmaread(struct memdata *md, u32 physbuf, ssize_t count,                           int offset){        pcltmp_t pcltmp;        struct ti_pcl *pcl;        size_t retval;        int i;        DECLARE_WAITQUEUE(wait, current);        count &= ~3;        count = MIN(count, 53196);        retval = count;        if (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS))            & DMA_CHAN_CTRL_BUSY) {                PRINT(KERN_WARNING, md->lynx->id, "DMA ALREADY ACTIVE!");        }        reg_write(md->lynx, LBUS_ADDR, md->type | offset);        pcl = edit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp);        pcl->buffer[0].control = PCL_CMD_LBUS_TO_PCI | MIN(count, 4092);        pcl->buffer[0].pointer = physbuf;        count -= 4092;        i = 0;        while (count > 0) {                i++;                pcl->buffer[i].control = MIN(count, 4092);                pcl->buffer[i].pointer = physbuf + i * 4092;                count -= 4092;        }        pcl->buffer[i].control |= PCL_LAST_BUFF;        commit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp);        set_current_state(TASK_INTERRUPTIBLE);        add_wait_queue(&md->lynx->mem_dma_intr_wait, &wait);        run_sub_pcl(md->lynx, md->lynx->dmem_pcl, 2, CHANNEL_LOCALBUS);        schedule();        while (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS))               & DMA_CHAN_CTRL_BUSY) {                if (signal_pending(current)) {                        retval = -EINTR;                        break;                }                schedule();        }        reg_write(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS), 0);        remove_wait_queue(&md->lynx->mem_dma_intr_wait, &wait);        if (reg_read(md->lynx, DMA_CHAN_CTRL(CHANNEL_LOCALBUS))            & DMA_CHAN_CTRL_BUSY) {                PRINT(KERN_ERR, md->lynx->id, "DMA STILL ACTIVE!");        }

⌨️ 快捷键说明

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