ieee1394_core.c

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

C
1,324
字号
 * * Return value: 0 for success or error number otherwise. */int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt){	struct hpsb_packet *packet;	int retval = 0;	if (rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 ||	   (rootid == -1 && gapcnt == -1)) {		HPSB_DEBUG("Invalid Parameter: rootid = %d   gapcnt = %d",			   rootid, gapcnt);		return -EINVAL;	}	packet = hpsb_alloc_packet(0);	if (!packet)		return -ENOMEM;	packet->host = host;	packet->header_size = 8;	packet->data_size = 0;	packet->expect_response = 0;	packet->no_waiter = 0;	packet->type = hpsb_raw;	packet->header[0] = 0;	if (rootid != -1)		packet->header[0] |= rootid << 24 | 1 << 23;	if (gapcnt != -1)		packet->header[0] |= gapcnt << 16 | 1 << 22;	packet->header[1] = ~packet->header[0];	packet->generation = get_hpsb_generation(host);	retval = hpsb_send_packet_and_wait(packet);	hpsb_free_packet(packet);	return retval;}/** * hpsb_send_packet - transmit a packet on the bus * @packet: packet to send * * The packet is sent through the host specified in the packet->host field. * Before sending, the packet's transmit speed is automatically determined * using the local speed map when it is an async, non-broadcast packet. * * Possibilities for failure are that host is either not initialized, in bus * reset, the packet's generation number doesn't match the current generation * number or the host reports a transmit error. * * Return value: 0 on success, negative errno on failure. */int hpsb_send_packet(struct hpsb_packet *packet){	struct hpsb_host *host = packet->host;        if (host->is_shutdown)		return -EINVAL;	if (host->in_bus_reset ||	    (packet->generation != get_hpsb_generation(host)))                return -EAGAIN;        packet->state = hpsb_queued;	/* This just seems silly to me */	WARN_ON(packet->no_waiter && packet->expect_response);	if (!packet->no_waiter || packet->expect_response) {		atomic_inc(&packet->refcnt);		skb_queue_tail(&host->pending_packet_queue, packet->skb);	}        if (packet->node_id == host->node_id) {		/* it is a local request, so handle it locally */                quadlet_t *data;                size_t size = packet->data_size + packet->header_size;                data = kmalloc(size, GFP_ATOMIC);                if (!data) {                        HPSB_ERR("unable to allocate memory for concatenating header and data");                        return -ENOMEM;                }                memcpy(data, packet->header, packet->header_size);                if (packet->data_size)			memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size);                dump_packet("send packet local:", packet->header,                            packet->header_size);                hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);                hpsb_packet_received(host, data, size, 0);                kfree(data);                return 0;        }        if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {                packet->speed_code =                        host->speed_map[NODEID_TO_NODE(host->node_id) * 64                                       + NODEID_TO_NODE(packet->node_id)];        }#ifdef CONFIG_IEEE1394_VERBOSEDEBUG        switch (packet->speed_code) {        case 2:                dump_packet("send packet 400:", packet->header,                            packet->header_size);                break;        case 1:                dump_packet("send packet 200:", packet->header,                            packet->header_size);                break;        default:                dump_packet("send packet 100:", packet->header,                            packet->header_size);        }#endif        return host->driver->transmit_packet(host, packet);}/* We could just use complete() directly as the packet complete * callback, but this is more typesafe, in the sense that we get a * compiler error if the prototype for complete() changes. */static void complete_packet(void *data){	complete((struct completion *) data);}int hpsb_send_packet_and_wait(struct hpsb_packet *packet){	struct completion done;	int retval;	init_completion(&done);	hpsb_set_packet_complete_task(packet, complete_packet, &done);	retval = hpsb_send_packet(packet);	if (retval == 0)		wait_for_completion(&done);	return retval;}static void send_packet_nocare(struct hpsb_packet *packet){        if (hpsb_send_packet(packet) < 0) {                hpsb_free_packet(packet);        }}static void handle_packet_response(struct hpsb_host *host, int tcode,				   quadlet_t *data, size_t size){        struct hpsb_packet *packet = NULL;	struct sk_buff *skb;        int tcode_match = 0;        int tlabel;        unsigned long flags;        tlabel = (data[0] >> 10) & 0x3f;	spin_lock_irqsave(&host->pending_packet_queue.lock, flags);	skb_queue_walk(&host->pending_packet_queue, skb) {		packet = (struct hpsb_packet *)skb->data;                if ((packet->tlabel == tlabel)                    && (packet->node_id == (data[1] >> 16))){                        break;                }		packet = NULL;        }	if (packet == NULL) {                HPSB_DEBUG("unsolicited response packet received - no tlabel match");                dump_packet("contents:", data, 16);		spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);                return;        }        switch (packet->tcode) {        case TCODE_WRITEQ:        case TCODE_WRITEB:                if (tcode != TCODE_WRITE_RESPONSE)			break;		tcode_match = 1;		memcpy(packet->header, data, 12);                break;        case TCODE_READQ:                if (tcode != TCODE_READQ_RESPONSE)			break;		tcode_match = 1;		memcpy(packet->header, data, 16);                break;        case TCODE_READB:                if (tcode != TCODE_READB_RESPONSE)			break;		tcode_match = 1;		BUG_ON(packet->skb->len - sizeof(*packet) < size - 16);		memcpy(packet->header, data, 16);		memcpy(packet->data, data + 4, size - 16);                break;        case TCODE_LOCK_REQUEST:                if (tcode != TCODE_LOCK_RESPONSE)			break;		tcode_match = 1;		size = min((size - 16), (size_t)8);		BUG_ON(packet->skb->len - sizeof(*packet) < size);		memcpy(packet->header, data, 16);		memcpy(packet->data, data + 4, size);                break;        }        if (!tcode_match) {		spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);                HPSB_INFO("unsolicited response packet received - tcode mismatch");                dump_packet("contents:", data, 16);                return;        }	__skb_unlink(skb, skb->list);	if (packet->state == hpsb_queued) {		packet->sendtime = jiffies;		packet->ack_code = ACK_PENDING;	}	packet->state = hpsb_complete;	spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);	queue_packet_complete(packet);}static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,					       quadlet_t *data, size_t dsize){        struct hpsb_packet *p;        p = hpsb_alloc_packet(dsize);        if (unlikely(p == NULL)) {                /* FIXME - send data_error response */                return NULL;        }        p->type = hpsb_async;        p->state = hpsb_unused;        p->host = host;        p->node_id = data[1] >> 16;        p->tlabel = (data[0] >> 10) & 0x3f;        p->no_waiter = 1;	p->generation = get_hpsb_generation(host);	if (dsize % 4)		p->data[dsize / 4] = 0;        return p;}#define PREP_ASYNC_HEAD_RCODE(tc) \	packet->tcode = tc; \	packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \		| (1 << 8) | (tc << 4); \	packet->header[1] = (packet->host->node_id << 16) | (rcode << 12); \	packet->header[2] = 0static void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode,                              quadlet_t data){	PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE);	packet->header[3] = data;	packet->header_size = 16;	packet->data_size = 0;}static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,                               int length){	if (rcode != RCODE_COMPLETE)		length = 0;	PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE);	packet->header[3] = length << 16;	packet->header_size = 16;	packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);}static void fill_async_write_resp(struct hpsb_packet *packet, int rcode){	PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);	packet->header[2] = 0;	packet->header_size = 12;	packet->data_size = 0;}static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode,                          int length){	if (rcode != RCODE_COMPLETE)		length = 0;	PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE);	packet->header[3] = (length << 16) | extcode;	packet->header_size = 16;	packet->data_size = length;}#define PREP_REPLY_PACKET(length) \                packet = create_reply_packet(host, data, length); \                if (packet == NULL) breakstatic void handle_incoming_packet(struct hpsb_host *host, int tcode,				   quadlet_t *data, size_t size, int write_acked){        struct hpsb_packet *packet;        int length, rcode, extcode;        quadlet_t buffer;        nodeid_t source = data[1] >> 16;        nodeid_t dest = data[0] >> 16;        u16 flags = (u16) data[0];        u64 addr;        /* big FIXME - no error checking is done for an out of bounds length */        switch (tcode) {        case TCODE_WRITEQ:                addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];                rcode = highlevel_write(host, source, dest, data+3,					addr, 4, flags);                if (!write_acked                    && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)                    && (rcode >= 0)) {                        /* not a broadcast write, reply */                        PREP_REPLY_PACKET(0);                        fill_async_write_resp(packet, rcode);                        send_packet_nocare(packet);                }                break;        case TCODE_WRITEB:                addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];                rcode = highlevel_write(host, source, dest, data+4,					addr, data[3]>>16, flags);                if (!write_acked                    && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)                    && (rcode >= 0)) {                        /* not a broadcast write, reply */                        PREP_REPLY_PACKET(0);                        fill_async_write_resp(packet, rcode);                        send_packet_nocare(packet);                }                break;        case TCODE_READQ:                addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];                rcode = highlevel_read(host, source, &buffer, addr, 4, flags);                if (rcode >= 0) {                        PREP_REPLY_PACKET(0);                        fill_async_readquad_resp(packet, rcode, buffer);                        send_packet_nocare(packet);                }                break;        case TCODE_READB:                length = data[3] >> 16;                PREP_REPLY_PACKET(length);                addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];                rcode = highlevel_read(host, source, packet->data, addr,                                       length, flags);                if (rcode >= 0) {                        fill_async_readblock_resp(packet, rcode, length);                        send_packet_nocare(packet);                } else {                        hpsb_free_packet(packet);                }                break;        case TCODE_LOCK_REQUEST:                length = data[3] >> 16;                extcode = data[3] & 0xffff;                addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];                PREP_REPLY_PACKET(8);                if ((extcode == 0) || (extcode >= 7)) {                        /* let switch default handle error */                        length = 0;                }                switch (length) {                case 4:                        rcode = highlevel_lock(host, source, packet->data, addr,                                               data[4], 0, extcode,flags);                        fill_async_lock_resp(packet, rcode, extcode, 4);                        break;                case 8:                        if ((extcode != EXTCODE_FETCH_ADD)                            && (extcode != EXTCODE_LITTLE_ADD)) {                                rcode = highlevel_lock(host, source,                                                       packet->data, addr,                                                       data[5], data[4],                                                       extcode, flags);                                fill_async_lock_resp(packet, rcode, extcode, 4);                        } else {                                rcode = highlevel_lock64(host, source,                                             (octlet_t *)packet->data, addr,                                             *(octlet_t *)(data + 4), 0ULL,                                             extcode, flags);                                fill_async_lock_resp(packet, rcode, extcode, 8);                        }                        break;                case 16:                        rcode = highlevel_lock64(host, source,                                                 (octlet_t *)packet->data, addr,                                                 *(octlet_t *)(data + 6),                                                 *(octlet_t *)(data + 4),                                                 extcode, flags);                        fill_async_lock_resp(packet, rcode, extcode, 8);                        break;                default:                        rcode = RCODE_TYPE_ERROR;                        fill_async_lock_resp(packet, rcode,                                             extcode, 0);                }                if (rcode >= 0) {                        send_packet_nocare(packet);

⌨️ 快捷键说明

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