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

📄 mcp2515.c

📁 can总线驱动 Microchip MCP2515 CAN controller driver.
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 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 __devexit mcp251x_remove(struct spi_device *spi){	struct mcp251x *chip = dev_get_drvdata(&spi->dev);	dev_dbg(&spi->dev, "%s: stop\n",  __FUNCTION__);	class_device_unregister(chip->class_dev);	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;	}		cdev_init(&chip->cdev, &mcp251x_fops);	chip->cdev.owner = THIS_MODULE;	ret = cdev_add(&chip->cdev, MKDEV(MAJOR(can_devt), can_minor), 1);	if (ret < 0) {		dev_err(&spi->dev, "register char device failed (ret = %d)\n", ret);		goto error_register;	}	chip->class_dev = class_device_create(can_class, NULL,					      MKDEV(MAJOR(can_devt), can_minor),					      &spi->dev, "can%d", can_minor);	if (IS_ERR(chip->class_dev)) {		dev_err(&spi->dev, "cannot create CAN class device\n");		ret = PTR_ERR(chip->class_dev);		goto error_class_reg;	}		dev_info(&spi->dev, "device register at dev(%d:%d)\n",		 MAJOR(can_devt), can_minor);		mcp251x_hw_init(spi);	mcp251x_set_bit_rate(spi, 125000); /* A reasonable default */	mcp251x_hw_sleep(spi);	can_minor++;		return 0;	error_class_reg:	cdev_del(&chip->cdev);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){	int ret;		can_class = class_create(THIS_MODULE, "can");	if (IS_ERR(can_class))		return PTR_ERR(can_class);	ret = alloc_chrdev_region(&can_devt, 0, CAN_DEV_MAX, DRIVER_NAME);	if (ret < 0) {		printk(KERN_ERR "%s: failed to allocate char dev region\n",		       __FILE__);		class_destroy(can_class);		return ret;	}		return spi_register_driver(&mcp251x_driver);}module_init(mcp251x_init);static void __exit mcp251x_exit(void){	class_destroy(can_class);	unregister_chrdev_region(can_devt, CAN_DEV_MAX);	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 + -