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

📄 raw1394.c

📁 1394在linux下单独的驱动程序代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/** IEEE 1394 for Linux** Raw interface to the bus** Copyright (C) 1999, 2000 Andreas E. Bombe*               2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>*                     2002 Christian Toegel <christian.toegel@gmx.at>** This code is licensed under the GPL.  See the file COPYING in the root* directory of the kernel sources for details.*** Contributions:** Manfred Weihs <weihs@ict.tuwien.ac.at>*        configuration ROM manipulation*        address range mapping*        adaptation for new (transparent) loopback mechanism*        sending of arbitrary async packets* Christian Toegel <christian.toegel@gmx.at>*        address range mapping*        lock64 request*        transmit physical packet*        busreset notification control (switch on/off)*        busreset with selection of type (short/long)*        request_reply*/#include <linux/kernel.h>#include <linux/list.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/fs.h>#include <linux/poll.h>#include <linux/module.h>#include <linux/init.h>#include <linux/version.h>#include <linux/smp_lock.h>#include <linux/vmalloc.h>#include <asm/uaccess.h>#include <asm/atomic.h>#include <linux/devfs_fs_kernel.h>#include "ieee1394.h"#include "ieee1394_types.h"#include "ieee1394_core.h"#include "nodemgr.h"#include "hosts.h"#include "highlevel.h"#include "iso.h"#include "ieee1394_transactions.h"#include "raw1394.h"#include "raw1394-private.h"#if BITS_PER_LONG == 64#define int2ptr(x) ((void *)x)#define ptr2int(x) ((u64)x)#else#define int2ptr(x) ((void *)(u32)x)#define ptr2int(x) ((u64)(u32)x)#endif#ifdef CONFIG_IEEE1394_VERBOSEDEBUG#define RAW1394_DEBUG#endif#ifdef RAW1394_DEBUG#define DBGMSG(fmt, args...) \printk(KERN_INFO "raw1394:" fmt "\n" , ## args)#else#define DBGMSG(fmt, args...)#endifstatic devfs_handle_t devfs_handle;static LIST_HEAD(host_info_list);static int host_count;static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;static atomic_t internal_generation = ATOMIC_INIT(0);static atomic_t iso_buffer_size;static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */static struct hpsb_highlevel raw1394_highlevel;static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,					 u64 addr, size_t length, u16 flags);static int arm_write (struct hpsb_host *host, int nodeid, int destid,					  quadlet_t *data, u64 addr, size_t length, u16 flags);static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,					 u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,					   u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);static struct hpsb_address_ops arm_ops = {	.read	= arm_read,		.write	= arm_write,		.lock	= arm_lock,		.lock64	= arm_lock64,};static void queue_complete_cb(struct pending_request *req);static struct pending_request *__alloc_pending_request(int flags){	struct pending_request *req;		req = (struct pending_request *)kmalloc(sizeof(struct pending_request),		flags);	if (req != NULL) {		memset(req, 0, sizeof(struct pending_request));		INIT_LIST_HEAD(&req->list);	}		return req;}static inline struct pending_request *alloc_pending_request(void){	return __alloc_pending_request(SLAB_KERNEL);}static void free_pending_request(struct pending_request *req){	if (req->ibs) {		if (atomic_dec_and_test(&req->ibs->refcount)) {			atomic_sub(req->ibs->data_size, &iso_buffer_size);			kfree(req->ibs);		}	} else if (req->free_data) {		kfree(req->data);	}	free_hpsb_packet(req->packet);	kfree(req);}/* fi->reqlists_lock must be taken */static void __queue_complete_req(struct pending_request *req){	struct file_info *fi = req->file_info;	list_del(&req->list);	list_add_tail(&req->list, &fi->req_complete);		up(&fi->complete_sem);	wake_up_interruptible(&fi->poll_wait_complete);}static void queue_complete_req(struct pending_request *req){	unsigned long flags;	struct file_info *fi = req->file_info;		spin_lock_irqsave(&fi->reqlists_lock, flags);	__queue_complete_req(req);	spin_unlock_irqrestore(&fi->reqlists_lock, flags);}static void queue_complete_cb(struct pending_request *req){	struct hpsb_packet *packet = req->packet;	int rcode = (packet->header[1] >> 12) & 0xf;		switch (packet->ack_code) {	case ACKX_NONE:	case ACKX_SEND_ERROR:		req->req.error = RAW1394_ERROR_SEND_ERROR;		break;	case ACKX_ABORTED:		req->req.error = RAW1394_ERROR_ABORTED;		break;	case ACKX_TIMEOUT:		req->req.error = RAW1394_ERROR_TIMEOUT;		break;	default:		req->req.error = (packet->ack_code << 16) | rcode;		break;	}		if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) {		req->req.length = 0;	}		if ((req->req.type == RAW1394_REQ_ASYNC_READ) ||		(req->req.type == RAW1394_REQ_ASYNC_WRITE) ||		(req->req.type == RAW1394_REQ_ASYNC_STREAM) ||		(req->req.type == RAW1394_REQ_LOCK) ||		(req->req.type == RAW1394_REQ_LOCK64))		hpsb_free_tlabel(packet);		queue_complete_req(req);}static void add_host(struct hpsb_host *host){	struct host_info *hi;	unsigned long flags;		hi = (struct host_info *)kmalloc(sizeof(struct host_info), GFP_KERNEL);		if (hi != NULL) {		INIT_LIST_HEAD(&hi->list);		hi->host = host;		INIT_LIST_HEAD(&hi->file_info_list);				spin_lock_irqsave(&host_info_lock, flags);		list_add_tail(&hi->list, &host_info_list);		host_count++;		spin_unlock_irqrestore(&host_info_lock, flags);	}		atomic_inc(&internal_generation);}static struct host_info *find_host_info(struct hpsb_host *host){	struct list_head *lh;	struct host_info *hi;		list_for_each(lh, &host_info_list) {		hi = list_entry(lh, struct host_info, list);		if (hi->host == host) {			return hi;		}	}		return NULL;}static void remove_host(struct hpsb_host *host){	struct host_info *hi;	unsigned long flags;		spin_lock_irqsave(&host_info_lock, flags);	hi = find_host_info(host);		if (hi != NULL) {		list_del(&hi->list);		host_count--;		/* 		FIXME: address ranges should be removed 		and fileinfo states should be initialized		(including setting generation to 		internal-generation ...)		*/	}	spin_unlock_irqrestore(&host_info_lock, flags);		if (hi == NULL) {		printk(KERN_ERR "raw1394: attempt to remove unknown host "			"0x%p\n", host);		return;	}		kfree(hi);		atomic_inc(&internal_generation);}static void host_reset(struct hpsb_host *host){	unsigned long flags;	struct list_head *lh;	struct host_info *hi;	struct file_info *fi;	struct pending_request *req;		spin_lock_irqsave(&host_info_lock, flags);	hi = find_host_info(host);		if (hi != NULL) {		list_for_each(lh, &hi->file_info_list) {			fi = list_entry(lh, struct file_info, list);			if (fi->notification == RAW1394_NOTIFY_ON) {				req = __alloc_pending_request(SLAB_ATOMIC);								if (req != NULL) {					req->file_info = fi;					req->req.type = RAW1394_REQ_BUS_RESET;					req->req.generation = get_hpsb_generation(host);					req->req.misc = (host->node_id << 16)						| host->node_count;					if (fi->protocol_version > 3) {						req->req.misc |= (NODEID_TO_NODE(host->irm_id)							<< 8);					}										queue_complete_req(req);				}			}		}	}	spin_unlock_irqrestore(&host_info_lock, flags);}static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data,                        size_t length){	unsigned long flags;	struct list_head *lh;	struct host_info *hi;	struct file_info *fi;	struct pending_request *req;	struct iso_block_store *ibs = NULL;	LIST_HEAD(reqs);		if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {		HPSB_INFO("dropped iso packet");		return;	}		spin_lock_irqsave(&host_info_lock, flags);	hi = find_host_info(host);		if (hi != NULL) {		list_for_each(lh, &hi->file_info_list) {			fi = list_entry(lh, struct file_info, list);						if (!(fi->listen_channels & (1ULL << channel))) {				continue;			}						req = __alloc_pending_request(SLAB_ATOMIC);			if (!req) break;						if (!ibs) {				ibs = kmalloc(sizeof(struct iso_block_store)					+ length, SLAB_ATOMIC);				if (!ibs) {					kfree(req);					break;				}								atomic_add(length, &iso_buffer_size);				atomic_set(&ibs->refcount, 0);				ibs->data_size = length;				memcpy(ibs->data, data, length);			}						atomic_inc(&ibs->refcount);						req->file_info = fi;			req->ibs = ibs;			req->data = ibs->data;			req->req.type = RAW1394_REQ_ISO_RECEIVE;			req->req.generation = get_hpsb_generation(host);			req->req.misc = 0;			req->req.recvb = ptr2int(fi->iso_buffer);			req->req.length = min(length, fi->iso_buffer_length);						list_add_tail(&req->list, &reqs);		}	}	spin_unlock_irqrestore(&host_info_lock, flags);		lh = reqs.next;	while (lh != &reqs) {		req = list_entry(lh, struct pending_request, list);		lh = lh->next;				queue_complete_req(req);	}}static void fcp_request(struct hpsb_host *host, int nodeid, int direction,						int cts, u8 *data, size_t length){	unsigned long flags;	struct list_head *lh;	struct host_info *hi;	struct file_info *fi;	struct pending_request *req;	struct iso_block_store *ibs = NULL;	LIST_HEAD(reqs);		if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) {		HPSB_INFO("dropped fcp request");		return;	}		spin_lock_irqsave(&host_info_lock, flags);	hi = find_host_info(host);		if (hi != NULL) {		list_for_each(lh, &hi->file_info_list) {			fi = list_entry(lh, struct file_info, list);						if (!fi->fcp_buffer) {				continue;			}						req = __alloc_pending_request(SLAB_ATOMIC);			if (!req) break;						if (!ibs) {				ibs = kmalloc(sizeof(struct iso_block_store)					+ length, SLAB_ATOMIC);				if (!ibs) {					kfree(req);					break;				}								atomic_add(length, &iso_buffer_size);				atomic_set(&ibs->refcount, 0);				ibs->data_size = length;				memcpy(ibs->data, data, length);			}						atomic_inc(&ibs->refcount);						req->file_info = fi;			req->ibs = ibs;			req->data = ibs->data;			req->req.type = RAW1394_REQ_FCP_REQUEST;			req->req.generation = get_hpsb_generation(host);			req->req.misc = nodeid | (direction << 16);			req->req.recvb = ptr2int(fi->fcp_buffer);			req->req.length = length;						list_add_tail(&req->list, &reqs);		}	}	spin_unlock_irqrestore(&host_info_lock, flags);		lh = reqs.next;	while (lh != &reqs) {		req = list_entry(lh, struct pending_request, list);		lh = lh->next;				queue_complete_req(req);	}}static ssize_t raw1394_read(struct file *file, char *buffer, size_t count,							loff_t *offset_is_ignored){	struct file_info *fi = (struct file_info *)file->private_data;	struct list_head *lh;	struct pending_request *req;		if (count != sizeof(struct raw1394_request)) {		return -EINVAL;	}		if (!access_ok(VERIFY_WRITE, buffer, count)) {		return -EFAULT;	}		if (file->f_flags & O_NONBLOCK) {		if (down_trylock(&fi->complete_sem)) {			return -EAGAIN;		}	} else {		if (down_interruptible(&fi->complete_sem)) {			return -ERESTARTSYS;		}

⌨️ 快捷键说明

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