#include <linux/fs.h>

#include "can.h"
#include "sja1000.h"

//-----------------------------------------------------------------------------
int can_release(struct inode *inode, struct file *filp)
{
	/* Реализация функции release */
	int dev, channel;
	struct can_rx_fifo_t *rx_fifo;
	unsigned long flags;
	struct private_data_t *private_data;

	private_data = (struct private_data_t *)(filp->private_data);
	dev = private_data->num_dev;
	channel = private_data->num_channel;

	/* Захватываем спин и запрещаем локальные прерывания */
	spin_lock_irqsave(&can[dev].rx_fifo_lock[channel], flags);

	rx_fifo = can[dev].rx_fifo[channel];
	if( rx_fifo != NULL )
	{
		if( rx_fifo == private_data->rx_fifo )
		{
			can[dev].rx_fifo[channel] = rx_fifo->next;
		}
		else
		{
			while( rx_fifo->next != NULL )
			{
				if( rx_fifo->next == private_data->rx_fifo )
				{
					rx_fifo->next = rx_fifo->next->next;
					break;
				}
				rx_fifo = rx_fifo->next;
			}
		}
	}

	/* Освобождаем память */
	kfree(private_data->rx_fifo);

	private_data->rx_fifo = NULL;

	/* Освобождаем спин и разрешаем локальные прерывания */
	spin_unlock_irqrestore(&can[dev].rx_fifo_lock[channel], flags);

	/* Захватываем спин и запрещаем локальные прерывания */
	spin_lock_irqsave(&can[dev].tx_fifo_lock[channel], flags);
	if( private_data->tx_fifo != NULL )
	{
		/* Есть данные для выдачи */
		/* Удаляем ссылку на структуру private_data */
		private_data->tx_fifo->private_data = NULL;
		/* Для освобождения памяти в обработчике прерывания */
		private_data->tx_fifo->blocking = 0;
	}
	/* Освобождаем спин и разрешаем локальные прерывания */
	spin_unlock_irqrestore(&can[dev].tx_fifo_lock[channel], flags);

	kfree(private_data);

	return 0;
}
