raw1394.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,567 行 · 第 1/5 页

C
1,567
字号
/* * 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/smp_lock.h>#include <linux/interrupt.h>#include <linux/vmalloc.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <asm/atomic.h>#include <linux/devfs_fs_kernel.h>#include "csr1212.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"#define int2ptr(x) ((void __user *)(unsigned long)x)#define ptr2int(x) ((u64)(unsigned long)(void __user *)x)#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 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);        }        hpsb_free_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 host_info *hi;        list_for_each_entry(hi, &host_info_list, 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 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_entry(fi, &hi->file_info_list, 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 host_info *hi;        struct file_info *fi;        struct pending_request *req, *req_next;        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_entry(fi, &hi->file_info_list, 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)

⌨️ 快捷键说明

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