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

📄 pcilynx.c

📁 这个是uClinux下的ieee1394驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * ti_pcilynx.c - Texas Instruments PCILynx driver * Copyright (C) 1999,2000 Andreas Bombe <andreas.bombe@munich.netsurf.de>, *                         Stephan Linz <linz@mazet.de> *                         Manfred Weihs <weihs@ict.tuwien.ac.at> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/wait.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/fs.h>#include <linux/poll.h>#include <asm/byteorder.h>#include <asm/atomic.h>#include <asm/io.h>#include <asm/uaccess.h>#include "ieee1394.h"#include "ieee1394_types.h"#include "hosts.h"#include "ieee1394_core.h"#include "highlevel.h"#include "pcilynx.h"#include <linux/i2c.h>#include <linux/i2c-algo-bit.h>/* print general (card independent) information */#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)/* print card specific information */#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)#ifdef CONFIG_IEEE1394_VERBOSEDEBUG#define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args)#define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args)#else#define PRINT_GD(level, fmt, args...) do {} while (0)#define PRINTD(level, card, fmt, args...) do {} while (0)#endif/* Module Parameters */MODULE_PARM(skip_eeprom,"i");MODULE_PARM_DESC(skip_eeprom, "Do not try to read bus info block from serial eeprom, but user generic one (default = 0).");static int skip_eeprom = 0;static struct hpsb_host_driver lynx_driver;static unsigned int card_id;/* * I2C stuff *//* the i2c stuff was inspired by i2c-philips-par.c */static void bit_setscl(void *data, int state){	if (state) {		  ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000040;	} else {		  ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000040;	}	reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);}static void bit_setsda(void *data, int state){	if (state) {		  ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000010;	} else {		  ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000010;	}	reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state);}static int bit_getscl(void *data){	return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000040;}static int bit_getsda(void *data){	return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010;}static int bit_reg(struct i2c_client *client){	return 0;}static int bit_unreg(struct i2c_client *client){	return 0;}static struct i2c_algo_bit_data bit_data = {	NULL,	bit_setsda,	bit_setscl,	bit_getsda,	bit_getscl,	5, 5, 100,		/*	waits, timeout */}; static struct i2c_adapter bit_ops = {	"PCILynx I2C adapter",	0xAA, //FIXME: probably we should get an id in i2c-id.h	NULL,	NULL,	NULL,	NULL,	bit_reg,	bit_unreg,};/* * PCL handling functions. */static pcl_t alloc_pcl(struct ti_lynx *lynx){        u8 m;        int i, j;        spin_lock(&lynx->lock);        /* FIXME - use ffz() to make this readable */        for (i = 0; i < (LOCALRAM_SIZE / 1024); i++) {                m = lynx->pcl_bmap[i];                for (j = 0; j < 8; j++) {                        if (m & 1<<j) {                                continue;                        }                        m |= 1<<j;                        lynx->pcl_bmap[i] = m;                        spin_unlock(&lynx->lock);                        return 8 * i + j;                }        }        spin_unlock(&lynx->lock);        return -1;}#if 0static void free_pcl(struct ti_lynx *lynx, pcl_t pclid){        int off, bit;        off = pclid / 8;        bit = pclid % 8;        if (pclid < 0) {                return;        }        spin_lock(&lynx->lock);        if (lynx->pcl_bmap[off] & 1<<bit) {                lynx->pcl_bmap[off] &= ~(1<<bit);        } else {                PRINT(KERN_ERR, lynx->id,                       "attempted to free unallocated PCL %d", pclid);        }        spin_unlock(&lynx->lock);}/* functions useful for debugging */        static void pretty_print_pcl(const struct ti_pcl *pcl){        int i;        printk("PCL next %08x, userdata %08x, status %08x, remtrans %08x, nextbuf %08x\n",               pcl->next, pcl->user_data, pcl->pcl_status,                pcl->remaining_transfer_count, pcl->next_data_buffer);        printk("PCL");        for (i=0; i<13; i++) {                printk(" c%x:%08x d%x:%08x",                       i, pcl->buffer[i].control, i, pcl->buffer[i].pointer);                if (!(i & 0x3) && (i != 12)) printk("\nPCL");        }        printk("\n");}        static void print_pcl(const struct ti_lynx *lynx, pcl_t pclid){        struct ti_pcl pcl;        get_pcl(lynx, pclid, &pcl);        pretty_print_pcl(&pcl);}#endif/*********************************** * IEEE-1394 functionality section * ***********************************/static int get_phy_reg(struct ti_lynx *lynx, int addr){        int retval;        int i = 0;        unsigned long flags;        if (addr > 15) {                PRINT(KERN_ERR, lynx->id,                      "%s: PHY register address %d out of range",		      __FUNCTION__, addr);                return -1;        }        spin_lock_irqsave(&lynx->phy_reg_lock, flags);        reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr));        do {                retval = reg_read(lynx, LINK_PHY);                if (i > 10000) {                        PRINT(KERN_ERR, lynx->id, "%s: runaway loop, aborting",			      __FUNCTION__);                        retval = -1;                        break;                }                i++;        } while ((retval & 0xf00) != LINK_PHY_RADDR(addr));        reg_write(lynx, LINK_INT_STATUS, LINK_INT_PHY_REG_RCVD);        spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);        if (retval != -1) {                return retval & 0xff;        } else {                return -1;        }}static int set_phy_reg(struct ti_lynx *lynx, int addr, int val){        unsigned long flags;        if (addr > 15) {                PRINT(KERN_ERR, lynx->id,                      "%s: PHY register address %d out of range", __FUNCTION__, addr);                return -1;        }        if (val > 0xff) {                PRINT(KERN_ERR, lynx->id,                      "%s: PHY register value %d out of range", __FUNCTION__, val);                return -1;        }        spin_lock_irqsave(&lynx->phy_reg_lock, flags);        reg_write(lynx, LINK_PHY, LINK_PHY_WRITE | LINK_PHY_ADDR(addr)                  | LINK_PHY_WDATA(val));        spin_unlock_irqrestore(&lynx->phy_reg_lock, flags);        return 0;}static int sel_phy_reg_page(struct ti_lynx *lynx, int page){        int reg;        if (page > 7) {                PRINT(KERN_ERR, lynx->id,                      "%s: PHY page %d out of range", __FUNCTION__, page);                return -1;        }        reg = get_phy_reg(lynx, 7);        if (reg != -1) {                reg &= 0x1f;                reg |= (page << 5);                set_phy_reg(lynx, 7, reg);                return 0;        } else {                return -1;        }}#if 0 /* not needed at this time */static int sel_phy_reg_port(struct ti_lynx *lynx, int port){        int reg;        if (port > 15) {                PRINT(KERN_ERR, lynx->id,                      "%s: PHY port %d out of range", __FUNCTION__, port);                return -1;        }        reg = get_phy_reg(lynx, 7);        if (reg != -1) {                reg &= 0xf0;                reg |= port;                set_phy_reg(lynx, 7, reg);                return 0;        } else {                return -1;        }}#endifstatic u32 get_phy_vendorid(struct ti_lynx *lynx){        u32 pvid = 0;        sel_phy_reg_page(lynx, 1);        pvid |= (get_phy_reg(lynx, 10) << 16);        pvid |= (get_phy_reg(lynx, 11) << 8);        pvid |= get_phy_reg(lynx, 12);        PRINT(KERN_INFO, lynx->id, "PHY vendor id 0x%06x", pvid);        return pvid;}static u32 get_phy_productid(struct ti_lynx *lynx){        u32 id = 0;        sel_phy_reg_page(lynx, 1);        id |= (get_phy_reg(lynx, 13) << 16);        id |= (get_phy_reg(lynx, 14) << 8);        id |= get_phy_reg(lynx, 15);        PRINT(KERN_INFO, lynx->id, "PHY product id 0x%06x", id);        return id;}static quadlet_t generate_own_selfid(struct ti_lynx *lynx,                                     struct hpsb_host *host){        quadlet_t lsid;        char phyreg[7];        int i;        phyreg[0] = lynx->phy_reg0;        for (i = 1; i < 7; i++) {                phyreg[i] = get_phy_reg(lynx, i);        }        /* FIXME? We assume a TSB21LV03A phy here.  This code doesn't support           more than 3 ports on the PHY anyway. */        lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22);        lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */        lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */        lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */        /* lsid |= 1 << 11; *//* set contender (hack) */        lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */        for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */                if (phyreg[3 + i] & 0x4) {                        lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3)                                << (6 - i*2);                } else {                        lsid |= 1 << (6 - i*2);                }        }        cpu_to_be32s(&lsid);        PRINT(KERN_DEBUG, lynx->id, "generated own selfid 0x%x", lsid);        return lsid;}static void handle_selfid(struct ti_lynx *lynx, struct hpsb_host *host){        quadlet_t *q = lynx->rcv_page;        int phyid, isroot, size;        quadlet_t lsid = 0;        int i;        if (lynx->phy_reg0 == -1 || lynx->selfid_size == -1) return;        size = lynx->selfid_size;        phyid = lynx->phy_reg0;        i = (size > 16 ? 16 : size) / 4 - 1;        while (i >= 0) {                cpu_to_be32s(&q[i]);                i--;        }                if (!lynx->phyic.reg_1394a) {                lsid = generate_own_selfid(lynx, host);        }        isroot = (phyid & 2) != 0;        phyid >>= 2;        PRINT(KERN_INFO, lynx->id, "SelfID process finished (phyid %d, %s)",              phyid, (isroot ? "root" : "not root"));        reg_write(lynx, LINK_ID, (0xffc0 | phyid) << 16);        if (!lynx->phyic.reg_1394a && !size) {                hpsb_selfid_received(host, lsid);        }        while (size > 0) {                struct selfid *sid = (struct selfid *)q;                if (!lynx->phyic.reg_1394a && !sid->extended                     && (sid->phy_id == (phyid + 1))) {                        hpsb_selfid_received(host, lsid);                }                if (q[0] == ~q[1]) {                        PRINT(KERN_DEBUG, lynx->id, "SelfID packet 0x%x rcvd",                              q[0]);                        hpsb_selfid_received(host, q[0]);                } else {                        PRINT(KERN_INFO, lynx->id,                              "inconsistent selfid 0x%x/0x%x", q[0], q[1]);                }

⌨️ 快捷键说明

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