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

📄 mcp2515.c

📁 spi接口的 LINUX CAN driver
💻 C
📖 第 1 页 / 共 2 页
字号:
	dev_dbg(&spi->dev, "%s: failed: ret = %d\n", __FUNCTION__, ret);    frame->header.id = (rx_buf[0] << 3) | (rx_buf[1] >> 5);    frame->header.ide = (rx_buf[1] >> 3) & 0x1;    frame->header.srr = (rx_buf[1] >> 4) & 0x1;    if (frame->header.ide == 1)	frame->header.eid = (rx_buf[1] << 16) | (rx_buf[2] << 8) | rx_buf[3];    else	frame->header.eid = 0;    frame->header.rtr = (rx_buf[4] >> 6) & 0x1;    frame->header.rb1 = (rx_buf[4] >> 5) & 0x1;    frame->header.rb0 = (rx_buf[4] >> 4) & 0x1;    frame->header.dlc = rx_buf[4] & 0x0f;    memcpy(frame->data, rx_buf + 5, CAN_FRAME_MAX_DATA_LEN);    up(&chip->lock);    /* update pos of ring buffer */    chip->rxbin++;    if (chip->rxbin >= MCP251X_BUF_LEN)	chip->rxbin = 0;			    up(&chip->rxblock);    return 0;}/* ........................................................................ *//* bottom half task for interrupt */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))static void mcp251x_irq_handler(struct work_struct *work){    struct mcp251x *chip = container_of(work, struct mcp251x, irq_work);    struct spi_device *spi = chip->spi;#elsestatic void mcp251x_irq_handler(void *dev_id){    struct spi_device *spi = dev_id;    struct mcp251x *chip = dev_get_drvdata(&spi->dev);#endif    uint8_t intf, rxs;    for(;;) {			intf = mcp251x_read_reg(spi, CANINTF);	if (intf == 0x00)	    break;	dev_dbg(&spi->dev, "interrupt:%s%s%s%s%s%s%s%s\n",		(intf & CANINTF_MERRF) ? " MERR":"",		(intf & CANINTF_WAKIF) ? " WAK":"",		(intf & CANINTF_ERRIF) ? " ERR":"",		(intf & CANINTF_TX2IF) ? " TX2":"",		(intf & CANINTF_TX1IF) ? " TX1":"",		(intf & CANINTF_TX0IF) ? " TX0":"",		(intf & CANINTF_RX1IF) ? " RX1":"",		(intf & CANINTF_RX0IF) ? " RX0":"");				rxs = mcp251x_read_state(spi, INSTRUCTION_RX_STATE); 	dev_dbg(&spi->dev, "rx_state:%s%s\n",		(rxs & RX_STATE_IDE) ? " IDE":"",		(rxs & RX_STATE_RTR) ? " RTR":"");				if (intf & CANINTF_MERRF) {#if 0	    uint8_t txbnctrl;	    /* if there are no pending Tx buffers, restart queue */	    txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));	    if (!(txbnctrl & TXBCTRL_TXREQ))		netif_wake_queue(&chip->can->ndev);#endif	}	if (intf & CANINTF_ERRIF) {	    uint8_t eflg = mcp251x_read_reg(spi, EFLG);	    	    dev_dbg(&spi->dev, "EFLG = 0x%02x\n", eflg);	    	    if (eflg & (EFLG_RX0OVR | EFLG_RX1OVR)) {#if 0		if (eflg & EFLG_RX0OVR)		    chip->stats.rx_over_errors++;		if (eflg & EFLG_RX1OVR)		    chip->stats.rx_over_errors++;#endif		    mcp251x_write_reg(spi, EFLG, 0x00);	    }	}	if (intf & CANINTF_TX0IF) /* If ready to send, copy data to send buffer. */	    mcp251x_hw_tx(spi, 0);	if (intf & CANINTF_TX1IF)	    mcp251x_hw_tx(spi, 1);	if (intf & CANINTF_TX2IF)	    mcp251x_hw_tx(spi, 2);	if (intf & CANINTF_RX0IF) /* If received data, copy data to ring buffer. */	    mcp251x_hw_rx(spi, 0);	if (intf & CANINTF_RX1IF)	    mcp251x_hw_rx(spi, 1);		mcp251x_write_bits(spi, CANINTF, intf, 0x00);		/* If ring buffer of receive is not empty, wake up the read queue. */	if (chip->rxbin != chip->rxbout)	    wake_up_interruptible(&chip->wq);    }}static irqreturn_t mcp251x_irq(int irq, void *dev_id, struct pt_regs *regs){    struct spi_device *spi = dev_id;    struct mcp251x *chip = dev_get_drvdata(&spi->dev);    /* Can't do anything in interrupt context so fire of the interrupt     * handling workqueue. */    schedule_work(&chip->irq_work);    return IRQ_HANDLED;}/* ........................................................................ */static int mcp251x_open(struct inode *inode, struct file *file){    struct mcp251x *chip = container_of(inode->i_cdev, struct mcp251x, cdev);    struct spi_device *spi = chip->spi;    struct mcp251x_platform_data *pdata = spi->dev.platform_data;	    file->private_data = chip;    if (!chip->count) {			if (pdata->transceiver_enable)	    pdata->transceiver_enable(1);	mcp251x_hw_wakeup(spi);	/* Enable interrupts */	mcp251x_write_reg(spi, CANINTE,			  CANINTE_ERRIE | CANINTE_TX2IE			  | CANINTE_TX1IE | CANINTE_TX0IE			  | CANINTE_RX1IE | CANINTE_RX0IE);	/* put device into normal mode */	mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_NORMAL);	mcp251x_write_reg(spi, RXBCTRL(0), RXBCTRL_BULK);    }	    chip->count++;	    return 0;}static int mcp251x_release(struct inode *inode, struct file *file){	    struct mcp251x *chip = container_of(inode->i_cdev, struct mcp251x, cdev);    struct spi_device *spi = chip->spi;    struct mcp251x_platform_data *pdata = spi->dev.platform_data;    chip->count--;	    if (chip->count)	return 0;    /* disable and clear pending interrupts */    mcp251x_write_reg(spi, CANINTE, 0x00);    mcp251x_write_reg(spi, CANINTF, 0x00);    /* go to sleep */    mcp251x_hw_sleep(spi);    if (pdata->transceiver_enable)	pdata->transceiver_enable(0);		    return 0;}static int mcp251x_write(struct file *file, const char __user *buf, size_t count, loff_t *ofs){	    struct mcp251x *chip = file->private_data;    struct spi_device *spi = chip->spi;    struct can_frame *frame;    int ret;    uint8_t txreq;    if (count < sizeof(struct can_frame))	return -EINVAL;    if (down_interruptible(&chip->txblock))	return -ERESTARTSYS;	    frame = &chip->txb[chip->txbin];    ret = copy_from_user(frame, buf, sizeof(struct can_frame));    chip->txbin++;    if (chip->txbin >= MCP251X_BUF_LEN)	chip->txbin = 0;	    up(&chip->txblock);	    txreq = mcp251x_read_state(spi, INSTRUCTION_CAN_STATE);    if (!(txreq & CAN_STATE_TX0REQ))	mcp251x_hw_tx(spi, 0);		    if (!(txreq & CAN_STATE_TX1REQ))	mcp251x_hw_tx(spi, 1);    if (!(txreq & CAN_STATE_TX2REQ))	mcp251x_hw_tx(spi, 2);	    return count;}static ssize_t mcp251x_read(struct file *file, char __user *buf, size_t count, loff_t *ofs){	    struct mcp251x *chip = file->private_data;    struct can_frame *frame;	    if (count != sizeof(struct can_frame))	return -EINVAL;		    if (down_interruptible(&chip->rxblock))	return -ERESTARTSYS;	    while (chip->rxbin == chip->rxbout) {	up(&chip->rxblock);	if (file->f_flags & O_NONBLOCK)	    return -EAGAIN;	if (wait_event_interruptible(chip->wq, (chip->rxbin != chip->rxbout)))	    return -ERESTARTSYS;	if (down_interruptible(&chip->rxblock))	    return -ERESTARTSYS;    }	    frame = &chip->rxb[chip->rxbout];    if (copy_to_user(buf, frame, sizeof(struct can_frame))) {	up(&chip->rxblock);	return -EFAULT;    }	    chip->rxbout++;    if(chip->rxbout >= MCP251X_BUF_LEN)	chip->rxbout = 0;		    up(&chip->rxblock);		    return count;    #if 0retry:    if (chip->rxbin != chip->rxbout) {			down(&chip->rxblock);			frame = &chip->rxb[chip->rxbout];	if (copy_to_user(buf, frame, sizeof(struct can_frame))) {	    up(&chip->rxblock);	    return -EFAULT;	}	chip->rxbout++;	if(chip->rxbout >= MCP251X_BUF_LEN)	    chip->rxbout = 0;			up(&chip->rxblock);			return count;    }    else {	if (file->f_flags & O_NONBLOCK)	    return -EAGAIN;	interruptible_sleep_on(&chip->wq);	if (signal_pending(current))	    return -ERESTARTSYS;				goto retry;    }#endif}static int mcp251x_ioctl(struct inode *inode, struct file *file, 			 unsigned int cmd, unsigned long arg){    struct mcp251x *chip = container_of(inode->i_cdev, struct mcp251x, cdev);    struct spi_device *spi = chip->spi;    int ret = 0;    switch(cmd) {	    case CAN_IOCTRESET:		/* reset devcie */	mcp251x_hw_reset(spi);	break;    case CAN_IOCTWAKEUP:	/* wake up device */	mcp251x_hw_wakeup(spi);	break;    case CAN_IOCSRATE:		/* set bit rate */	ret = mcp251x_set_bit_rate(spi, (int)arg);	mdelay(10);	break;    case CAN_IOCGRATE:		/* get bit rate */	*((int *)arg) = mcp251x_get_bit_rate(spi);	break;    case CAN_IOCSFILTER:	/* set filter */	ret = mcp251x_set_filter(spi, (struct can_filter *)arg);	break;    case CAN_IOCGFILTER:	/* get filter */	ret = mcp251x_get_filter(spi, (struct can_filter *)arg);	break;    case CAN_IOCTNORMALMODE:	/* turn to normal mode */	mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_NORMAL);	break;    case CAN_IOCTLOOPBACKMODE:	/* turn to loopback mode */	mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_LOOPBACK);	break;    case CAN_IOCTLISTENONLYMODE: /* turn to listen only mode */	mcp251x_write_bits(spi, CANCTRL, CANCTRL_REQOP_MASK, CANCTRL_REQOP_LISTEN_ONLY);	break;    case CAN_IOCTSLEEPMODE:	/* turn to sleep mode */	mcp251x_hw_sleep(spi);	break;    default:	return -ENOTTY;    }	    return ret;}static const struct file_operations mcp251x_fops = {    .owner = THIS_MODULE,    .read = mcp251x_read,    .write = mcp251x_write,    .ioctl = mcp251x_ioctl,    .open = mcp251x_open,    .release = mcp251x_release,};/* ........................................................................ */static int mcp251x_remove(struct spi_device *spi){    struct mcp251x *chip = dev_get_drvdata(&spi->dev);    dev_dbg(&spi->dev, "%s: stop\n",  __FUNCTION__);    cdev_del(&chip->cdev);    free_irq(spi->irq, spi);    kfree(chip->spi_transfer_buf);    return 0;}static int __devinit mcp251x_probe(struct spi_device *spi){    struct mcp251x *chip;    int ret = 0;    dev_dbg(&spi->dev, "%s: start\n",  __FUNCTION__);    chip = kmalloc(sizeof(struct mcp251x), GFP_KERNEL);    if (!chip) {	ret = -ENOMEM;	goto error_alloc;    }    dev_set_drvdata(&spi->dev, chip);	    chip->txbin = chip->txbout = 0;    chip->rxbin = chip->rxbout = 0;    chip->count = 0;    chip->spi = spi;    init_MUTEX(&chip->lock);    init_MUTEX(&chip->txblock);    init_MUTEX(&chip->rxblock);    init_waitqueue_head(&chip->wq);    #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))    INIT_WORK(&chip->irq_work, mcp251x_irq_handler);#else    INIT_WORK(&chip->irq_work, mcp251x_irq_handler, spi);#endif        chip->spi_transfer_buf = kmalloc(SPI_TRANSFER_BUF_LEN, GFP_KERNEL);    if (!chip->spi_transfer_buf) {	ret = -ENOMEM;	goto error_buf;    }	    ret = request_irq(spi->irq, mcp251x_irq, SA_SAMPLE_RANDOM, DRIVER_NAME, spi);    if (ret < 0) {	dev_err(&spi->dev, "request irq %d failed (ret = %d)\n", spi->irq, ret);	goto error_irq;    }    if (can_minor > CAN_MAX_DEV)	goto error_register;		    if (can_major) {	devid = MKDEV(can_major, ++can_minor);	ret = register_chrdev_region(devid, 0, DRIVER_NAME);    } else {	ret = alloc_chrdev_region(&devid, can_minor, 0, DRIVER_NAME);	can_major = MAJOR(devid);    }	    if (ret < 0) {	dev_err(&spi->dev, "register char device region (%d:%d) failed (ret = %d)\n", MAJOR(devid), MINOR(devid), ret);	goto error_register;    }	    cdev_init(&chip->cdev, &mcp251x_fops);    chip->cdev.owner = THIS_MODULE;    ret = cdev_add(&chip->cdev, devid, 1);    if (ret < 0) {	dev_err(&spi->dev, "register char device failed (ret = %d)\n", ret);	goto error_devadd;    }	    dev_info(&spi->dev, "device register at dev(%d:%d)\n", MAJOR(devid), MINOR(devid));	    mcp251x_hw_init(spi);    mcp251x_set_bit_rate(spi, 125000); /* A reasonable default */    mcp251x_hw_sleep(spi);    return 0;	error_devadd:    unregister_chrdev_region(devid, 0);error_register:    free_irq(spi->irq, spi);error_irq:    kfree(chip->spi_transfer_buf);error_buf:    kfree(chip);error_alloc:    return ret;}#ifdef CONFIG_PMstatic int mcp251x_suspend(struct spi_device *spi, pm_message_t mesg){    struct mcp251x *chip = dev_get_drvdata(&spi->dev);    struct mcp251x_platform_data *pdata = spi->dev.platform_data;    if (chip->count)	return 0;    mcp251x_hw_sleep(spi);    if (pdata->transceiver_enable)	pdata->transceiver_enable(0);    return 0;}static int mcp251x_resume(struct spi_device *spi){    struct mcp251x *chip = dev_get_drvdata(&spi->dev);    struct mcp251x_platform_data *pdata = spi->dev.platform_data;    if (!chip->count)	return 0;		    if (pdata->transceiver_enable)	pdata->transceiver_enable(1);    mcp251x_hw_wakeup(spi);    return 0;}#endifstatic struct spi_driver mcp251x_driver = {    .driver = {	.name	= DRIVER_NAME,	.bus	= &spi_bus_type,	.owner	= THIS_MODULE,    },    .probe	= mcp251x_probe,    .remove	= __devexit_p(mcp251x_remove),#ifdef CONFIG_PM    .suspend	= mcp251x_suspend,    .resume	= mcp251x_resume,#endif};static int __init mcp251x_init(void){    return spi_register_driver(&mcp251x_driver);}module_init(mcp251x_init);static void __exit mcp251x_exit(void){    spi_unregister_driver(&mcp251x_driver);}module_exit(mcp251x_exit);MODULE_DESCRIPTION("MCP251x CAN controller driver");MODULE_LICENSE("GPL");MODULE_AUTHOR("Renzhou.Meng");

⌨️ 快捷键说明

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