中文字幕 另类精品,亚洲欧美一区二区蜜桃,日本在线精品视频免费,孩交精品乱子片免费

<sup id="3hn2b"></sup>

    1. <sub id="3hn2b"><ol id="3hn2b"></ol></sub><legend id="3hn2b"></legend>

      1. <xmp id="3hn2b"></xmp>

      2. 新聞中心

        EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > ARM-Linux驅(qū)動(dòng)--DM9000網(wǎng)卡驅(qū)動(dòng)分析(二)

        ARM-Linux驅(qū)動(dòng)--DM9000網(wǎng)卡驅(qū)動(dòng)分析(二)

        作者: 時(shí)間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
        硬件平臺(tái):FL2440(s3c2440
        內(nèi)核版本:2.6.35
        主機(jī)平臺(tái):Ubuntu 11.04
        內(nèi)核版本:2.6.39
        原創(chuàng)作品,轉(zhuǎn)載請(qǐng)標(biāo)明出處http://blog.csdn.net/yming0221/article/details/6612623
        下面開始分析具體的代碼,這里由于使DM9000驅(qū)動(dòng)更容易理解,在不影響基本的功能的前提下,這里將盡可能的簡(jiǎn)化該驅(qū)動(dòng)(如:去掉該驅(qū)動(dòng)中支持電源管理的功能)
        分析該驅(qū)動(dòng)
        1、首先看一下該驅(qū)動(dòng)的平臺(tái)設(shè)備驅(qū)動(dòng)的結(jié)構(gòu)體定義
        view plainprint?
        static struct platform_driver dm9000_driver = {
        .driver = {
        .name = "dm9000",
        .owner = THIS_MODULE,
        },
        .probe = dm9000_probe,
        .remove = __devexit_p(dm9000_drv_remove),
        };
        在執(zhí)行insmod后內(nèi)核自動(dòng)那個(gè)執(zhí)行下面的函數(shù)
        view plainprint?
        static int __init
        dm9000_init(void)
        {
        printk(KERN_INFO "%s Ethernet Driver, V%sn", CARDNAME, DRV_VERSION);
        return platform_driver_register(&dm9000_driver);
        }
        調(diào)用函數(shù)platform_driver_register()函數(shù)注冊(cè)驅(qū)動(dòng)。
        3、自動(dòng)執(zhí)行驅(qū)動(dòng)的probe函數(shù),進(jìn)行資源的探測(cè)和申請(qǐng)資源。
        其中BWSCON為總線寬度 等待控制寄存器
        其中第[19:18]位的作用如下
        下面函數(shù)中將兩位設(shè)置為11,也就是WAIT使能,bank4使用UB/LB。
        alloc_etherdev()函數(shù)分配一個(gè)網(wǎng)絡(luò)設(shè)備的結(jié)構(gòu)體,原型在include/linux/etherdevice.h
        原型如下:
        view plainprint?
        extern struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count);
        #define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
        該函數(shù)中需要將獲得的資源信息存儲(chǔ)在一個(gè)結(jié)構(gòu)體中,定義如下:
        view plainprint?
        typedef struct board_info {
        void __iomem *io_addr;
        void __iomem *io_data;
        u16 irq;
        u16 tx_pkt_cnt;
        u16 queue_pkt_len;
        u16 queue_start_addr;
        u16 queue_ip_summed;
        u16 dbug_cnt;
        u8 io_mode;
        u8 phy_addr;
        u8 imr_all;
        unsigned int flags;
        unsigned int in_suspend :1;
        unsigned int wake_supported :1;
        int debug_level;
        enum dm9000_type type;
        void (*inblk)(void __iomem *port, void *data, int length);
        void (*outblk)(void __iomem *port, void *data, int length);
        void (*dumpblk)(void __iomem *port, int length);
        struct device *dev;
        struct resource *addr_res;
        struct resource *data_res;
        struct resource *addr_req;
        struct resource *data_req;
        struct resource *irq_res;
        int irq_wake;
        struct mutex addr_lock;
        struct delayed_work phy_poll;
        struct net_device *ndev;
        spinlock_t lock;
        struct mii_if_info mii;
        u32 msg_enable;
        u32 wake_state;
        int rx_csum;
        int can_csum;
        int ip_summed;
        } board_info_t;
        下面是probe函數(shù),
        其中有個(gè)函數(shù)db = netdev_priv(ndev)
        該函數(shù)實(shí)際上是返回網(wǎng)卡私有成員的數(shù)據(jù)結(jié)構(gòu)地址
        函數(shù)如下,定義在include/linux/net_device.h中
        view plainprint?
        static inline void *netdev_priv(const struct net_device *dev)
        {
        return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
        }
        view plainprint?
        static int __devinit
        dm9000_probe(struct platform_device *pdev)
        {
        struct dm9000_plat_data *pdata = pdev->dev.platform_data;
        struct board_info *db;
        struct net_device *ndev;
        const unsigned char *mac_src;
        int ret = 0;
        int iosize;
        int i;
        u32 id_val;
        unsigned char ne_def_eth_mac_addr[]={0x00,0x12,0x34,0x56,0x80,0x49};
        static void *bwscon;
        static void *gpfcon;
        static void *extint0;
        static void *intmsk;
        #define BWSCON (0x48000000)
        #define GPFCON (0x56000050)
        #define EXTINT0 (0x56000088)
        #define INTMSK (0x4A000008)
        bwscon=ioremap_nocache(BWSCON,0x0000004);
        gpfcon=ioremap_nocache(GPFCON,0x0000004);
        extint0=ioremap_nocache(EXTINT0,0x0000004);
        intmsk=ioremap_nocache(INTMSK,0x0000004);
        writel( readl(bwscon)|0xc0000,bwscon);
        writel( (readl(gpfcon) & ~(0x3 << 14)) | (0x2 << 14), gpfcon);
        writel( readl(gpfcon) | (0x1 << 7), gpfcon); // Disable pull-up,不使能上拉
        writel( (readl(extint0) & ~(0xf << 28)) | (0x4 << 28), extint0); //rising edge,設(shè)置上升沿觸發(fā)中斷
        writel( (readl(intmsk)) & ~0x80, intmsk);
        ndev = alloc_etherdev(sizeof(struct board_info));
        if (!ndev) {
        dev_err(&pdev->dev, "could not allocate device.n");
        return -ENOMEM;
        }
        SET_NETDEV_DEV(ndev, &pdev->dev);
        dev_dbg(&pdev->dev, "dm9000_probe()n");
        db = netdev_priv(ndev);
        db->dev = &pdev->dev;
        db->ndev = ndev;
        spin_lock_init(&db->lock);
        mutex_init(&db->addr_lock);
        INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
        db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (db->addr_res == NULL || db->data_res == NULL ||
        db->irq_res == NULL) {
        dev_err(db->dev, "insufficient resourcesn");
        ret = -ENOENT;
        goto out;
        }
        db->irq_wake = platform_get_irq(pdev, 1);
        if (db->irq_wake >= 0) {
        dev_dbg(db->dev, "wakeup irq %dn", db->irq_wake);
        ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
        IRQF_SHARED, dev_name(db->dev), ndev);
        if (ret) {
        dev_err(db->dev, "cannot get wakeup irq (%d)n", ret);
        } else {
        ret = set_irq_wake(db->irq_wake, 1);
        if (ret) {
        dev_err(db->dev, "irq %d cannot set wakeup (%d)n",
        db->irq_wake, ret);
        ret = 0;
        } else {
        set_irq_wake(db->irq_wake, 0);
        db->wake_supported = 1;
        }
        }
        }
        iosize = resource_size(db->addr_res);
        db->addr_req = request_mem_region(db->addr_res->start, iosize,
        pdev->name);
        if (db->addr_req == NULL) {
        dev_err(db->dev, "cannot claim address reg arean");
        ret = -EIO;
        goto out;
        }
        db->io_addr = ioremap(db->addr_res->start, iosize);
        if (db->io_addr == NULL) {
        dev_err(db->dev, "failed to ioremap address regn");
        ret = -EINVAL;
        goto out;
        }
        iosize = resource_size(db->data_res);
        db->data_req = request_mem_region(db->data_res->start, iosize,
        pdev->name);
        if (db->data_req == NULL) {
        dev_err(db->dev, "cannot claim data reg arean");
        ret = -EIO;
        goto out;
        }
        db->io_data = ioremap(db->data_res->start, iosize);
        if (db->io_data == NULL) {
        dev_err(db->dev, "failed to ioremap data regn");
        ret = -EINVAL;
        goto out;
        }
        ndev->base_addr = (unsigned long)db->io_addr;
        ndev->irq = db->irq_res->start;
        dm9000_set_io(db, iosize);
        if (pdata != NULL) {
        if (pdata->flags & DM9000_PLATF_8BITONLY)
        dm9000_set_io(db, 1);
        if (pdata->flags & DM9000_PLATF_16BITONLY)
        dm9000_set_io(db, 2);
        if (pdata->flags & DM9000_PLATF_32BITONLY)
        dm9000_set_io(db, 4);
        if (pdata->inblk != NULL)
        db->inblk = pdata->inblk;
        if (pdata->outblk != NULL)
        db->outblk = pdata->outblk;
        if (pdata->dumpblk != NULL)
        db->dumpblk = pdata->dumpblk;
        db->flags = pdata->flags;
        }
        #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
        db->flags |= DM9000_PLATF_SIMPLE_PHY;
        #endif
        dm9000_reset(db);
        for (i = 0; i < 8; i++) {
        id_val = ior(db, DM9000_VIDL);
        id_val |= (u32)ior(db, DM9000_VIDH) << 8;
        id_val |= (u32)ior(db, DM9000_PIDL) << 16;
        id_val |= (u32)ior(db, DM9000_PIDH) << 24;
        if (id_val == DM9000_ID)
        break;
        dev_err(db->dev, "read wrong id 0xxn", id_val);
        }
        if (id_val != DM9000_ID) {
        dev_err(db->dev, "wrong id: 0xxn", id_val);
        ret = -ENODEV;
        goto out;
        }
        id_val = ior(db, DM9000_CHIPR);
        dev_dbg(db->dev, "dm9000 revision 0xxn", id_val);
        switch (id_val) {
        case CHIPR_DM9000A:
        db->type = TYPE_DM9000A;
        break;
        case CHIPR_DM9000B:
        db->type = TYPE_DM9000B;
        break;
        default:
        dev_dbg(db->dev, "ID x => defaulting to DM9000En", id_val);
        db->type = TYPE_DM9000E;
        }
        if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
        db->can_csum = 1;
        db->rx_csum = 1;
        ndev->features |= NETIF_F_IP_CSUM;
        }
        ether_setup(ndev);
        ndev->netdev_ops = &dm9000_netdev_ops;
        ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
        ndev->ethtool_ops = &dm9000_ethtool_ops;
        db->msg_enable = NETIF_MSG_LINK;
        db->mii.phy_id_mask = 0x1f;
        db->mii.reg_num_mask = 0x1f;
        db->mii.force_media = 0;
        db->mii.full_duplex = 0;
        db->mii.dev = ndev;
        db->mii.mdio_read = dm9000_phy_read;
        db->mii.mdio_write = dm9000_phy_write;
        mac_src = "eeprom";
        for (i = 0; i < 6; i += 2)
        dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
        if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
        mac_src = "platform data";
        memcpy(ndev->dev_addr, pdata->dev_addr, 6);
        }
        if (!is_valid_ether_addr(ndev->dev_addr)) {
        mac_src = "chip";
        for (i = 0; i < 6; i++)
        ndev->dev_addr[i] = ne_def_eth_mac_addr[i];
        }
        if (!is_valid_ether_addr(ndev->dev_addr))
        dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
        "set using ifconfign", ndev->name);
        platform_set_drvdata(pdev, ndev);
        ret = register_netdev(ndev);
        if (ret == 0)
        printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)n",
        ndev->name, dm9000_type_to_char(db->type),
        db->io_addr, db->io_data, ndev->irq,
        ndev->dev_addr, mac_src);
        return 0;
        out:
        dev_err(db->dev, "not found (%d).n", ret);
        dm9000_release_board(pdev, db);
        free_netdev(ndev);
        return ret;
        }
        這樣,最后完成了網(wǎng)絡(luò)設(shè)備的數(shù)據(jù)保存到總線上,將網(wǎng)絡(luò)設(shè)備注冊(cè)到內(nèi)核。
        4、設(shè)備的移除函數(shù)
        view plainprint?
        static int __devexit
        dm9000_drv_remove(struct platform_device *pdev)
        {
        struct net_device *ndev = platform_get_drvdata(pdev);
        platform_set_drvdata(pdev, NULL);
        unregister_netdev(ndev);
        dm9000_release_board(pdev, (board_info_t *) netdev_priv(ndev));
        free_netdev(ndev);
        dev_dbg(&pdev->dev, "released and freed devicen");
        return 0;
        }


        評(píng)論


        技術(shù)專區(qū)

        關(guān)閉