?? raw1394.c
字號:
/* * IEEE 1394 for Linux * * Raw interface to the bus * * Copyright (C) 1999, 2000 Andreas E. Bombe * * This code is licensed under the GPL. See the file COPYING in the root * directory of the kernel sources for details. */#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 <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 "hosts.h"#include "highlevel.h"#include "ieee1394_transactions.h"#include "raw1394.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)#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 struct hpsb_highlevel *hl_handle;static atomic_t iso_buffer_size;static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */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); INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL); } 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);}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); list_del(&req->list); list_add_tail(&req->list, &fi->req_complete); spin_unlock_irqrestore(&fi->reqlists_lock, flags); up(&fi->complete_sem); wake_up_interruptible(&fi->poll_wait_complete);}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; } free_tlabel(packet->host, packet->node_id, packet->tlabel); queue_complete_req(req);}static void add_host(struct hpsb_host *host){ struct host_info *hi; hi = (struct host_info *)kmalloc(sizeof(struct host_info), SLAB_KERNEL); if (hi != NULL) { INIT_LIST_HEAD(&hi->list); hi->host = host; INIT_LIST_HEAD(&hi->file_info_list); spin_lock_irq(&host_info_lock); list_add_tail(&hi->list, &host_info_list); host_count++; spin_unlock_irq(&host_info_lock); } 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; spin_lock_irq(&host_info_lock); hi = find_host_info(host); if (hi != NULL) { list_del(&hi->list); host_count--; } spin_unlock_irq(&host_info_lock); 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); 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 |= ((host->irm_id & NODE_MASK) << 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, unsigned int 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, unsigned int 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;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -