Linux下MCP2515驱动解析

拿到一个设备驱动,首先要看的是设备初始化函数。

  1. static int __init mcp251x_init(void)  
  2. {  
  3.     int ret;  
  4.     can_class = class_create(THIS_MODULE, "can");  
  5.     if (IS_ERR(can_class))  
  6.         return PTR_ERR(can_class);  
  7.     ret = alloc_chrdev_region(&devid, 0, CAN_DEV_MAX, DRIVER_NAME);  
  8.     if (ret < 0)  
  9.     {  
  10.         printk(KERN_ERR "%s: failed to allocate char dev region\n", __FILE__);  
  11.         class_destroy(can_class);  
  12.         return ret;  
  13.     }  
  14.   
  15.     return spi_register_driver(&mcp251x_driver);  
  16. }  

class_create()用于自动创建设备节点,我们可以暂时不看,有兴趣的可以看看Linux源码。alloc_chrdev_region()自动为DRIVER_NAME分配设备号。在这里,我们真正关心的是spi_register_driver()函数和mcp251x_driver结构体的内容。
我们先看spi_register_driver()的内容。

  1. /** 
  2.  * spi_register_driver - register a SPI driver 
  3.  * @sdrv: the driver to register 
  4.  * Context: can sleep 
  5.  */  
  6. int spi_register_driver(struct spi_driver *sdrv)  
  7. {  
  8.     sdrv->driver.bus = &spi_bus_type;  
  9.     if (sdrv->probe)  
  10.         sdrv->driver.probe = spi_drv_probe;  
  11.     if (sdrv->remove)  
  12.         sdrv->driver.remove = spi_drv_remove;  
  13.     if (sdrv->shutdown)  
  14.         sdrv->driver.shutdown = spi_drv_shutdown;  
  15.     return driver_register(&sdrv->driver);  
  16. }  

spi_register_driver()完成了驱动在总线的挂载以及spi驱动函数probe, remove, shutdown的赋值。那mcp251x_driver是什么样的结构体,里面又存储了什么内容呢?

  1. static struct spi_driver mcp251x_driver = {  
  2.     .driver = {  
  3.                .name = DRIVER_NAME,  
  4.                .bus = &spi_bus_type,  
  5.                .owner = THIS_MODULE,  
  6.                },  
  7.     .probe = mcp251x_probe,  
  8.     .remove = __devexit_p(mcp251x_remove),  
  9. #ifdef CONFIG_PM  
  10.     .suspend = mcp251x_suspend,  
  11.     .resume = mcp251x_resume,  
  12. #endif  
  13. };  

mcp251x_driver是结构体spi_driver的实例,在mcp251x_driver里面完成了mcp251x驱动函数probe, remove, suspend, resume的赋值。

在进入mcp251x的驱动函数之前,我们还是先看看mcp251x的结构吧!

  1. struct mcp251x  
  2. {  
  3.     struct cdev cdev;  
  4.     struct class_device *class_dev;  
  5.     struct semaphore lock;      /* semaphore for spi bus share. */  
  6.     struct semaphore rxblock;   /* semaphore for ring buffer of receive. */  
  7.     struct semaphore txblock;   /* semaphore for ring buffer of send. */  
  8.   
  9.     uint8_t *spi_transfer_buf;  /* temp buffer for spi bus transfer. */  
  10.   
  11.     struct can_frame rxb[MCP251X_BUF_LEN];  /* ring buffer for receive. */  
  12.     struct can_frame txb[MCP251X_BUF_LEN];  /* ring buffer for send. */  
  13.   
  14.     int txbin;                  /* pos of in for ring buffer of sned. */  
  15.     int txbout;                 /* pos of out for ring buffer of send. */  
  16.     int rxbin;                  /* pos of in for ring buffer of receive. */  
  17.     int rxbout;                 /* pos of out for ring buffer of receive. */  
  18.   
  19.     int bit_rate;               /* save bit rate of current set. */  
  20.     int count;                  /* count of the device opened. */  
  21.   
  22.     wait_queue_head_t wq;       /* queue for read process. */  
  23.   
  24.     struct work_struct irq_work;    /* bottom half of interrupt task. */  
  25.   
  26.     struct spi_device *spi;     /* save the point of struce spi_device. */  
  27.     struct can_filter filter;   /* save the filter data of current set. */  
  28. };  
其中的很多结构体,我们暂时不管。下面开始进入正题。

  1. static int __devinit mcp251x_probe(struct spi_device *spi)  
  2. {  
  3.     struct mcp251x *chip;  
  4.     int ret = 0;  
  5.   
  6.     dev_dbg(&spi->dev, "%s: start\n", __FUNCTION__);  
  7.   
  8.     /* 申请内存资源 */  
  9.     chip = kmalloc(sizeof(struct mcp251x), GFP_KERNEL);  
  10.     if (!chip)  
  11.     {  
  12.         ret = -ENOMEM;  
  13.         goto error_alloc;  
  14.     }  
  15.   
  16.     /* 将mcp251x的设备信息保存到spi的设备结构体中 */  
  17.     dev_set_drvdata(&spi->dev, chip);  
  18.   
  19.     /* mcp251x结构体初始化 */  
  20.     chip->txbin = chip->txbout = 0;  
  21.     chip->rxbin = chip->rxbout = 0;  
  22.     chip->count = 0;  
  23.     chip->spi = spi;  
  24.     init_MUTEX(&chip->lock);  
  25.     init_MUTEX(&chip->txblock);  
  26.     init_MUTEX(&chip->rxblock);  
  27.     init_waitqueue_head(&chip->wq);  
  28.   
  29. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))  
  30.     INIT_WORK(&chip->irq_work, mcp251x_irq_handler);  
  31. #else  
  32.     INIT_WORK(&chip->irq_work, mcp251x_irq_handler, spi);  
  33. #endif  
  34.   
  35.     /* 为spi的buf分配空间 */  
  36.     chip->spi_transfer_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);  
  37.     if (!chip->spi_transfer_buf)  
  38.     {  
  39.         ret = -ENOMEM;  
  40.         goto error_buf;  
  41.     }  
  42.       
  43.     /* 输入模式,不使用内部上拉电阻 */  
  44.     at91_set_gpio_input(spi->irq, 0);  
  45.     /* 绑定输入函数mcp251x_irq,传递参数spi */  
  46.     /* mcp251x_irq函数我们等下再看,先放一放 */  
  47.     ret = request_irq(spi->irq, mcp251x_irq, IRQF_SAMPLE_RANDOM, DRIVER_NAME, spi);  
  48.     if (ret < 0)  
  49.     {  
  50.         dev_err(&spi->dev, "request irq %d failed (ret = %d)\n", spi->irq, ret);  
  51.         goto error_irq;  
  52.     }  
  53.   
  54.     if (can_minor > CAN_DEV_MAX)  
  55.         goto error_register;  
  56.   
  57.     if (can_major)  
  58.     {  
  59.         devid = MKDEV(can_major, can_minor++);  
  60.         ret = register_chrdev_region(devid, 0, DRIVER_NAME);  
  61.     }  
  62.     else  
  63.     {  
  64.         ret = alloc_chrdev_region(&devid, can_minor, 0, DRIVER_NAME);  
  65.         can_major = MAJOR(devid);  
  66.     }  
  67.   
  68.     if (ret < 0)  
  69.     {  
  70.         dev_err(&spi->dev, "register char device region (%d:%d) failed (ret = %d)\n", MAJOR(devid),  
  71.                 MINOR(devid), ret);  
  72.         goto error_register;  
  73.     }  
  74.   
  75.     /* 字符设备的初始化以及添加到内核 */  
  76.     cdev_init(&chip->cdev, &mcp251x_fops);  
  77.     chip->cdev.owner = THIS_MODULE;  
  78.     ret = cdev_add(&chip->cdev, devid, 1);  
  79.     if (ret < 0)  
  80.     {  
  81.         dev_err(&spi->dev, "register char device failed (ret = %d)\n", ret);  
  82.         goto error_devadd;  
  83.     }  
  84.   
  85.     dev_info(&spi->dev, "device register at dev(%d:%d)\n", MAJOR(devid), MINOR(devid));  
  86.   
  87.     /* 自动创建设备文件 */  
  88.     chip->class_dev = device_create(can_class, NULL,  
  89.                                     MKDEV(MAJOR(devid), can_minor), &spi->dev, "can%d", can_minor);  
  90.     if (IS_ERR(chip->class_dev))  
  91.     {  
  92.         dev_err(&spi->dev, "cannot create CAN class device\n");  
  93.         ret = PTR_ERR(chip->class_dev);  
  94.         goto error_class_reg;  
  95.     }  
  96.   
  97.     /* mcp251x初始化设置 */  
  98.     mcp251x_hw_init(spi);  
  99.     mcp251x_set_bit_rate(spi, 125000);  /* A reasonable default */  
  100.     mcp251x_hw_sleep(spi);  
  101.   
  102.     return 0;  
  103.   
  104.   error_class_reg:  
  105.     cdev_del(&chip->cdev);  
  106.   error_devadd:  
  107.     unregister_chrdev_region(devid, 0);  
  108.   error_register:  
  109.     free_irq(spi->irq, spi);  
  110.   error_irq:  
  111.     kfree(chip->spi_transfer_buf);  
  112.   error_buf:  
  113.     kfree(chip);  
  114.   error_alloc:  
  115.     return ret;  
  116. }  
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值