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

📄 ieee1394_core.c

📁 IEE1394 火线接口驱动 for linux
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * IEEE 1394 for Linux * * Core support: hpsb_packet management, packet handling and forwarding to *               highlevel or lowlevel code * * Copyright (C) 1999, 2000 Andreas E. Bombe *                     2002 Manfred Weihs <weihs@ict.tuwien.ac.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> *        loopback functionality in hpsb_send_packet *        allow highlevel drivers to disable automatic response generation *              and to generate responses themselves (deferred) * */#include <linux/config.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/string.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/module.h>#include <linux/proc_fs.h>#include <linux/bitops.h>#include <asm/byteorder.h>#include <asm/semaphore.h>#include "ieee1394_types.h"#include "ieee1394.h"#include "hosts.h"#include "ieee1394_core.h"#include "highlevel.h"#include "ieee1394_transactions.h"#include "csr.h"#include "nodemgr.h"#include "dma.h"#include "iso.h"/* * Disable the nodemgr detection and config rom reading functionality. */MODULE_PARM(disable_nodemgr, "i");MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");static int disable_nodemgr = 0;/* We are GPL, so treat us special */MODULE_LICENSE("GPL");static kmem_cache_t *hpsb_packet_cache;/* Some globals used */const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };#ifdef CONFIG_IEEE1394_VERBOSEDEBUGstatic void dump_packet(const char *text, quadlet_t *data, int size){	int i;	size /= 4;	size = (size > 4 ? 4 : size);	printk(KERN_DEBUG "ieee1394: %s", text);	for (i = 0; i < size; i++)		printk(" %08x", data[i]);	printk("\n");}#else#define dump_packet(x,y,z)#endifstatic void run_packet_complete(struct hpsb_packet *packet){	if (packet->complete_routine != NULL) {		void (*complete_routine)(void*) = packet->complete_routine;		void *complete_data = packet->complete_data;		packet->complete_routine = NULL;		packet->complete_data = NULL;		complete_routine(complete_data);	}	return;}/** * hpsb_set_packet_complete_task - set the task that runs when a packet * completes. You cannot call this more than once on a single packet * before it is sent. * * @packet: the packet whose completion we want the task added to * @routine: function to call * @data: data (if any) to pass to the above function */void hpsb_set_packet_complete_task(struct hpsb_packet *packet,				   void (*routine)(void *), void *data){	BUG_ON(packet->complete_routine != NULL);	packet->complete_routine = routine;	packet->complete_data = data;	return;}/** * alloc_hpsb_packet - allocate new packet structure * @data_size: size of the data block to be allocated * * This function allocates, initializes and returns a new &struct hpsb_packet. * It can be used in interrupt context.  A header block is always included, its * size is big enough to contain all possible 1394 headers.  The data block is * only allocated when @data_size is not zero. * * For packets for which responses will be received the @data_size has to be big * enough to contain the response's data block since no further allocation * occurs at response matching time. * * The packet's generation value will be set to the current generation number * for ease of use.  Remember to overwrite it with your own recorded generation * number if you can not be sure that your code will not race with a bus reset. * * Return value: A pointer to a &struct hpsb_packet or NULL on allocation * failure. */struct hpsb_packet *alloc_hpsb_packet(size_t data_size){        struct hpsb_packet *packet = NULL;        void *data = NULL;        packet = kmem_cache_alloc(hpsb_packet_cache, GFP_ATOMIC);        if (packet == NULL)                return NULL;        memset(packet, 0, sizeof(struct hpsb_packet));        packet->header = packet->embedded_header;        if (data_size) {                data = kmalloc(data_size + 8, GFP_ATOMIC);                if (data == NULL) {			kmem_cache_free(hpsb_packet_cache, packet);                        return NULL;                }                packet->data = data;                packet->data_size = data_size;        }        INIT_LIST_HEAD(&packet->list);        sema_init(&packet->state_change, 0);	packet->complete_routine = NULL;	packet->complete_data = NULL;        packet->state = hpsb_unused;        packet->generation = -1;        packet->data_be = 1;        return packet;}/** * free_hpsb_packet - free packet and data associated with it * @packet: packet to free (is NULL safe) * * This function will free packet->data, packet->header and finally the packet * itself. */void free_hpsb_packet(struct hpsb_packet *packet){        if (!packet) return;        kfree(packet->data);        kmem_cache_free(hpsb_packet_cache, packet);}int hpsb_reset_bus(struct hpsb_host *host, int type){        if (!host->in_bus_reset) {                host->driver->devctl(host, RESET_BUS, type);                return 0;        } else {                return 1;        }}int hpsb_bus_reset(struct hpsb_host *host){        if (host->in_bus_reset) {                HPSB_NOTICE("%s called while bus reset already in progress",			    __FUNCTION__);                return 1;        }        abort_requests(host);        host->in_bus_reset = 1;        host->irm_id = -1;	host->is_irm = 0;        host->busmgr_id = -1;	host->is_busmgr = 0;	host->is_cycmst = 0;        host->node_count = 0;        host->selfid_count = 0;        return 0;}/* * Verify num_of_selfids SelfIDs and return number of nodes.  Return zero in * case verification failed. */static int check_selfids(struct hpsb_host *host){        int nodeid = -1;        int rest_of_selfids = host->selfid_count;        struct selfid *sid = (struct selfid *)host->topology_map;        struct ext_selfid *esid;        int esid_seq = 23;	host->nodes_active = 0;        while (rest_of_selfids--) {                if (!sid->extended) {                        nodeid++;                        esid_seq = 0;                                                if (sid->phy_id != nodeid) {                                HPSB_INFO("SelfIDs failed monotony check with "                                          "%d", sid->phy_id);                                return 0;                        }                        			if (sid->link_active) {				host->nodes_active++;				if (sid->contender)					host->irm_id = LOCAL_BUS | sid->phy_id;			}                } else {                        esid = (struct ext_selfid *)sid;                        if ((esid->phy_id != nodeid)                             || (esid->seq_nr != esid_seq)) {                                HPSB_INFO("SelfIDs failed monotony check with "                                          "%d/%d", esid->phy_id, esid->seq_nr);                                return 0;                        }                        esid_seq++;                }                sid++;        }                esid = (struct ext_selfid *)(sid - 1);        while (esid->extended) {                if ((esid->porta == 0x2) || (esid->portb == 0x2)                    || (esid->portc == 0x2) || (esid->portd == 0x2)                    || (esid->porte == 0x2) || (esid->portf == 0x2)                    || (esid->portg == 0x2) || (esid->porth == 0x2)) {                                HPSB_INFO("SelfIDs failed root check on "                                          "extended SelfID");                                return 0;                }                esid--;        }        sid = (struct selfid *)esid;        if ((sid->port0 == 0x2) || (sid->port1 == 0x2) || (sid->port2 == 0x2)) {                        HPSB_INFO("SelfIDs failed root check");                        return 0;        }	host->node_count = nodeid + 1;        return 1;}static void build_speed_map(struct hpsb_host *host, int nodecount){	u8 speedcap[nodecount];        u8 cldcnt[nodecount];        u8 *map = host->speed_map;        struct selfid *sid;        struct ext_selfid *esid;        int i, j, n;        for (i = 0; i < (nodecount * 64); i += 64) {                for (j = 0; j < nodecount; j++) {                        map[i+j] = IEEE1394_SPEED_MAX;                }        }        for (i = 0; i < nodecount; i++) {                cldcnt[i] = 0;        }        /* find direct children count and speed */        for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],                     n = nodecount - 1;             (void *)sid >= (void *)host->topology_map; sid--) {                if (sid->extended) {                        esid = (struct ext_selfid *)sid;                        if (esid->porta == 0x3) cldcnt[n]++;                        if (esid->portb == 0x3) cldcnt[n]++;                        if (esid->portc == 0x3) cldcnt[n]++;                        if (esid->portd == 0x3) cldcnt[n]++;                        if (esid->porte == 0x3) cldcnt[n]++;                        if (esid->portf == 0x3) cldcnt[n]++;                        if (esid->portg == 0x3) cldcnt[n]++;                        if (esid->porth == 0x3) cldcnt[n]++;                } else {                        if (sid->port0 == 0x3) cldcnt[n]++;                        if (sid->port1 == 0x3) cldcnt[n]++;                        if (sid->port2 == 0x3) cldcnt[n]++;                        speedcap[n] = sid->speed;                        n--;                }        }        /* set self mapping */        for (i = 0; i < nodecount; i++) {                map[64*i + i] = speedcap[i];        }        /* fix up direct children count to total children count;         * also fix up speedcaps for sibling and parent communication */        for (i = 1; i < nodecount; i++) {                for (j = cldcnt[i], n = i - 1; j > 0; j--) {                        cldcnt[i] += cldcnt[n];                        speedcap[n] = min(speedcap[n], speedcap[i]);                        n -= cldcnt[n] + 1;                }        }        for (n = 0; n < nodecount; n++) {                for (i = n - cldcnt[n]; i <= n; i++) {                        for (j = 0; j < (n - cldcnt[n]); j++) {                                map[j*64 + i] = map[i*64 + j] =                                        min(map[i*64 + j], speedcap[n]);                        }                        for (j = n + 1; j < nodecount; j++) {                                map[j*64 + i] = map[i*64 + j] =                                        min(map[i*64 + j], speedcap[n]);                        }                }        }}void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid){        if (host->in_bus_reset) {                HPSB_VERBOSE("Including SelfID 0x%x", sid);                host->topology_map[host->selfid_count++] = sid;        } else {                HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",			    sid, NODEID_TO_BUS(host->node_id));        }}void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot){	if (!host->in_bus_reset)		HPSB_NOTICE("SelfID completion called outside of bus reset!");        host->node_id = LOCAL_BUS | phyid;        host->is_root = isroot;        if (!check_selfids(host)) {                if (host->reset_retries++ < 20) {                        /* selfid stage did not complete without error */                        HPSB_NOTICE("Error in SelfID stage, resetting");			host->in_bus_reset = 0;			/* this should work from ohci1394 now... */                        hpsb_reset_bus(host, LONG_RESET);                        return;                } else {                        HPSB_NOTICE("Stopping out-of-control reset loop");                        HPSB_NOTICE("Warning - topology map and speed map will not be valid");			host->reset_retries = 0;                }        } else {		host->reset_retries = 0;                build_speed_map(host, host->node_count);        }	HPSB_VERBOSE("selfid_complete called with successful SelfID stage "		     "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);        /* irm_id is kept up to date by check_selfids() */        if (host->irm_id == host->node_id) {                host->is_irm = 1;        } else {                host->is_busmgr = 0;                host->is_irm = 0;        }        if (isroot) {		host->driver->devctl(host, ACT_CYCLE_MASTER, 1);		host->is_cycmst = 1;	}	atomic_inc(&host->generation);	host->in_bus_reset = 0;        highlevel_host_reset(host);}void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,                       int ackcode){        unsigned long flags;        packet->ack_code = ackcode;        if (packet->no_waiter) {                /* must not have a tlabel allocated */                free_hpsb_packet(packet);                return;        }        if (ackcode != ACK_PENDING || !packet->expect_response) {                packet->state = hpsb_complete;                up(&packet->state_change);                up(&packet->state_change);                run_packet_complete(packet);                return;        }        packet->state = hpsb_pending;        packet->sendtime = jiffies;        spin_lock_irqsave(&host->pending_pkt_lock, flags);        list_add_tail(&packet->list, &host->pending_packets);        spin_unlock_irqrestore(&host->pending_pkt_lock, flags);        up(&packet->state_change);	mod_timer(&host->timeout, jiffies + host->timeout_interval);}/** * hpsb_send_phy_config - transmit a PHY configuration packet on the bus * @host: host that PHY config packet gets sent through * @rootid: root whose force_root bit should get set (-1 = don't set force_root) * @gapcnt: gap count value to set (-1 = don't set gap count) * * This function sends a PHY config packet on the bus through the specified host. *

⌨️ 快捷键说明

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