• linux enc28j60网卡驱动移植(硬件spi和模拟spi)


    本来想移植DM9000网卡的驱动,无奈硬件出了点问题,通过杜邦线链接开发板和DM9000网卡模块,系统上电,还没加载网卡驱动就直接崩溃了,找不到原因。。。刚好手上有一个enc28j60的网卡模块,于是就着手移植enc28j60的驱动。

    其实移植enc28j60的驱动也十分简单,网上有现成的,只需要分配一些硬件资源即可。

    由于我的内核版本老到掉牙,没有自带enc28j60的驱动,只能在网上找一个:

    enc28j60.c

    http://git.ti.com/ti-linux-kernel/ti-linux-kernel/blobs/7dac6f8df607929e51f4fd598d80bd009c45a9f8/drivers/net/enc28j60.c

    enc28j60_hw.h

    http://git.ti.com/ti-linux-kernel/ti-linux-kernel/blobs/7dac6f8df607929e51f4fd598d80bd009c45a9f8/drivers/net/enc28j60_hw.h

    由于这个驱动是支持较新的内核,移植到2.6.22.6,只要改动3个地方好了。

     1 ... ...
     2 
     3 static int enc28j60_set_hw_macaddr(struct net_device *ndev)
     4 {
     5     ... ...
     6     
     7     if (!priv->hw_enable) {
     8         if (netif_msg_drv(priv)) {
     9             /* [cgw]: 屏蔽一下几行 */
    10             //DECLARE_MAC_BUF(mac);
    11             //printk(KERN_INFO DRV_NAME
    12             //    ": %s: Setting MAC address to %s
    ",
    13             //    ndev->name, print_mac(mac, ndev->dev_addr));
    14         }
    15     }
    16 
    17     ... ...
    18 }
    19 
    20 ... ...
    21 
    22 static void dump_packet(const char *msg, int len, const char *data)
    23 {
    24     printk(KERN_DEBUG DRV_NAME ": %s - packet len:%d
    ", msg, len);
    25     /* [cgw]: 屏蔽一下几行 */
    26     //print_hex_dump(KERN_DEBUG, "pk data: ", DUMP_PREFIX_OFFSET, 16, 1,
    27     //        data, len, true);
    28 }
    29 
    30 ... ...
    31     
    32 static int enc28j60_net_open(struct net_device *dev)
    33 {
    34     ... ...
    35 
    36     if (!is_valid_ether_addr(dev->dev_addr)) {
    37         if (netif_msg_ifup(priv)) {
    38             /* [cgw]: 屏蔽一下几行 */
    39             //DECLARE_MAC_BUF(mac);
    40             //dev_err(&dev->dev, "invalid MAC address %s
    ",
    41             //    print_mac(mac, dev->dev_addr));
    42         }
    43         return -EADDRNOTAVAIL;
    44     }
    45 
    46     ... ...
    47 }
    48 
    49 ... ...


    都是些打印相关的东西,屏蔽掉就好。

    spi的框架可以参考这里:http://www.cnblogs.com/hackfun/p/6082489.html

    这里只列出配置spi硬件资源的代码,只需要写一个spi_platform_dev.c文件就行了。模拟spi的模式下,spi_platform_dev.c和http://www.cnblogs.com/hackfun/p/6082489.html这里的spi_platform_dev.c文件相似,只需要增加一个外部中断入口给enc28j60用于接收中断,和更改spi的模式等。

    模拟spi的模式下的spi_platform_dev.c

      1 #include <linux/module.h>
      2 #include <linux/version.h>
      3 
      4 #include <linux/init.h>
      5 
      6 #include <linux/kernel.h>
      7 #include <linux/types.h>
      8 #include <linux/interrupt.h>
      9 #include <linux/list.h>
     10 #include <linux/timer.h>
     11 #include <linux/init.h>
     12 #include <linux/serial_core.h>
     13 #include <linux/platform_device.h>
     14 #include <linux/irq.h>
     15 
     16 #include <asm/gpio.h>
     17 #include <asm/io.h>
     18 #include <asm/arch/regs-gpio.h>
     19 
     20 #include <linux/spi/spi.h>
     21 #include <linux/spi/spi_bitbang.h>
     22 
     23 #include <asm/arch/regs-spi.h>
     24 #include <asm/arch/spi.h>
     25 #include <asm/arch/spi-gpio.h>
     26 
     27 
     28 static struct spi_board_info board_info[1] = {
     29     {
     30     .modalias = "enc28j60",    /* [cgw]: spi设备名,和设备驱动名对应 */
     31     .bus_num = 0,                 /* [cgw]: spi总线号,即spi0 */
     32     .chip_select = 2,             /* [cgw]: spi总线上的设备号,即spi0.2 */
     33     .max_speed_hz    = 50000,     /* [cgw]: spi时钟 */
     34     .mode = SPI_MODE_0,           /* [cgw]: spi数据模式 */
     35     .irq = IRQ_EINT2,
     36     },
     37 };
     38 
     39 
     40 static void enc28j60_chip_select(struct s3c2410_spigpio_info *spi, int cs)
     41 {
     42     /* [cgw]: 选中设备号为2的spi设备 */
     43     if (spi->board_info->chip_select == 2) {
     44         s3c2410_gpio_cfgpin(S3C2410_GPG2, S3C2410_GPIO_OUTPUT);
     45         /* [cgw]: 选中设备 */
     46         if (BITBANG_CS_ACTIVE == cs) {
     47             s3c2410_gpio_setpin(S3C2410_GPG2, 0);
     48         /* [cgw]: 释放设备 */
     49         } else if (BITBANG_CS_INACTIVE == cs) {
     50             s3c2410_gpio_setpin(S3C2410_GPG2, 1);
     51         }
     52     }
     53 }
     54 
     55 /* [cgw]:  */
     56 static struct s3c2410_spigpio_info spi_dev = {
     57     .pin_clk = S3C2410_GPG7,
     58     .pin_mosi = S3C2410_GPG6,
     59     .pin_miso = S3C2410_GPG5,
     60     .board_size = 1,                    /* [cgw]: 设置板上spi接口数量为1 */
     61     .board_info = &board_info[0],
     62     .chip_select = enc28j60_chip_select
     63 };
     64 
     65 static void spi_dev_release(struct device * dev)
     66 {
     67     printk("spi_dev_release! 
    ");
     68 }
     69 
     70 /* [cgw]: 分配一个平台设备 */
     71 static struct platform_device spi_platform_dev = {
     72     .name         = "s3c24xx-spi-gpio",        /* [cgw]: 设置平台设备名,和平台驱动名对应 */
     73     .id           = -1,
     74     .dev = { 
     75         .release = spi_dev_release,
     76         .platform_data = (void *)&spi_dev,      /* [cgw]: 通过platform_data传递spi_dev给平台驱动
     77                                                 * 平台驱动可以访问spi_dev
     78                                                 */
     79     },
     80 };
     81 
     82 
     83 static int spi_dev_init(void)
     84 {
     85     s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
     86 
     87     /* [cgw]: 注册spi_platform_dev平台设备 */
     88     platform_device_register(&spi_platform_dev);
     89     return 0;
     90 }
     91 
     92 static void spi_dev_exit(void)
     93 {
     94     /* [cgw]: 注销spi_platform_dev平台设备 */
     95     platform_device_unregister(&spi_platform_dev);
     96 }
     97 
     98 module_init(spi_dev_init);
     99 module_exit(spi_dev_exit);
    100 
    101 MODULE_LICENSE("GPL");

    makefile:

    KERN_DIR = /work/system/linux-2.6.22.6
    
    all:
        make -C $(KERN_DIR) M=`pwd` modules 
    
    clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf modules.order
    
    obj-m    += spi_platform_dev.o
    obj-m    += spi_s3c24xx_gpio.o
    obj-m    += spi_bitbang.o
    obj-m    += enc28j60.o

    硬件spi的模式下的spi_platform_dev.c

      1 #include <linux/module.h>
      2 #include <linux/version.h>
      3 
      4 #include <linux/init.h>
      5 
      6 #include <linux/kernel.h>
      7 #include <linux/types.h>
      8 #include <linux/interrupt.h>
      9 #include <linux/list.h>
     10 #include <linux/timer.h>
     11 #include <linux/init.h>
     12 #include <linux/serial_core.h>
     13 #include <linux/platform_device.h>
     14 #include <linux/irq.h>
     15 
     16 #include <asm/gpio.h>
     17 #include <asm/io.h>
     18 #include <asm/arch/regs-gpio.h>
     19 
     20 #include <linux/spi/spi.h>
     21 #include <linux/spi/spi_bitbang.h>
     22 
     23 #include <asm/arch/regs-spi.h>
     24 #include <asm/arch/spi.h>
     25 #include <asm/arch/spi-gpio.h>
     26 
     27 
     28 /* SPI (1) */
     29 
     30 static struct resource s3c_spi1_resource[] = {
     31     [0] = {
     32         .start = S3C2410_PA_SPI + S3C2410_SPI1,
     33         .end   = S3C2410_PA_SPI + S3C2410_SPI1 + 0x1f,
     34         .flags = IORESOURCE_MEM,
     35     },
     36     [1] = {
     37         .start = IRQ_SPI1,
     38         .end   = IRQ_SPI1,
     39         .flags = IORESOURCE_IRQ,
     40     }
     41 
     42 };
     43 
     44 
     45 static struct spi_board_info board_info[1] = {
     46     {
     47     .modalias = "enc28j60",    /* [cgw]: spi设备名,和设备驱动名对应 */
     48     .bus_num = 0,                 /* [cgw]: spi总线号,即spi0 */
     49     .chip_select = 2,             /* [cgw]: spi总线上的设备号,即spi0.2 */
     50     .max_speed_hz    = 50000,     /* [cgw]: spi时钟 */
     51     .mode = SPI_MODE_0,           /* [cgw]: spi数据模式 */
     52     .irq = IRQ_EINT2,
     53     },
     54 };
     55 
     56 static struct s3c2410_spi_info spi_info = {
     57     .pin_cs = S3C2410_GPG2,    /* simple gpio cs */
     58     .board_size = ARRAY_SIZE(board_info),
     59     .board_info = &board_info[0],
     60     .set_cs = NULL
     61 };
     62 
     63 
     64 static void spi_dev_release(struct device * dev)
     65 {
     66     printk("spi_dev_release! 
    ");
     67 }
     68 
     69 /* [cgw]: 分配一个平台设备 */
     70 static struct platform_device spi_platform_dev = {
     71     .name         = "s3c2410-spi",        /* [cgw]: 设置平台设备名,和平台驱动名对应 */
     72     .id           = 1,
     73     .num_resources      = ARRAY_SIZE(s3c_spi1_resource),
     74     .resource      = s3c_spi1_resource,
     75     .dev = { 
     76         .release = spi_dev_release,
     77         .platform_data = &spi_info,
     78         //.dma_mask = &s3c_device_spi1_dmamask,
     79         //.coherent_dma_mask = 0xffffffffUL
     80     },
     81 };
     82 
     83 
     84 static int spi_dev_init(void)
     85 {
     86     /* [cgw]: 注册spi_platform_dev平台设备 */
     87     platform_device_register(&spi_platform_dev);
     88     return 0;
     89 }
     90 
     91 static void spi_dev_exit(void)
     92 {
     93     /* [cgw]: 注销spi_platform_dev平台设备 */
     94     platform_device_unregister(&spi_platform_dev);
     95 }
     96 
     97 module_init(spi_dev_init);
     98 module_exit(spi_dev_exit);
     99 
    100 MODULE_LICENSE("GPL");

    makefile:

    KERN_DIR = /work/system/linux-2.6.22.6
    
    all:
        make -C $(KERN_DIR) M=`pwd` modules 
    
    clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf modules.order
    
    obj-m    += spi_platform_dev.o
    obj-m    += spi_s3c24xx.o
    obj-m    += spi_bitbang.o
    obj-m    += enc28j60.o


    加载spi平台设备时(platform_device),应注意模拟spi时应加载spi_s3c24xx_gpio.c,硬件spi时应加载spi_s3c24xx.c

    如:

    模拟spi:

    1 # insmod spi_bitbang.ko
    2 # insmod spi_platform_dev.ko
    3 # insmod spi_s3c24xx_gpio.ko
    4 # insmod enc28j60.ko


    硬件spi:

    1 # insmod spi_bitbang.ko
    2 # insmod spi_platform_dev.ko
    3 # insmod spi_s3c24xx.ko
    4 # insmod enc28j60.ko


    其中spi_bitbang.c , spi_s3c24xx_gpio.c , spi_s3c24xx.c为内核原生源文件,不需要改动。

    硬件spi时,加载驱动的实例:

    谢谢!

  • 相关阅读:
    instanceof方法
    Java 实现接口计算圆柱的体积和面积并添加颜色
    Java代码执行顺序
    Java饿汉单例模式
    斐波那契数(动态规划和递归)
    Java 接口实现计算器加减乘除(字符交互界面)
    局部内部类详解_转载
    Java引用类型
    递归打印字符串
    时间复杂度
  • 原文地址:https://www.cnblogs.com/hackfun/p/6260396.html
Copyright © 2020-2023  润新知