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

📄 fw-transaction.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
 * deallocated region, payload is set to NULL. */void fw_core_remove_address_handler(struct fw_address_handler *handler){	unsigned long flags;	spin_lock_irqsave(&address_handler_lock, flags);	list_del(&handler->link);	spin_unlock_irqrestore(&address_handler_lock, flags);}EXPORT_SYMBOL(fw_core_remove_address_handler);struct fw_request {	struct fw_packet response;	u32 request_header[4];	int ack;	u32 length;	u32 data[0];};static voidfree_response_callback(struct fw_packet *packet,		       struct fw_card *card, int status){	struct fw_request *request;	request = container_of(packet, struct fw_request, response);	kfree(request);}voidfw_fill_response(struct fw_packet *response, u32 *request_header,		 int rcode, void *payload, size_t length){	int tcode, tlabel, extended_tcode, source, destination;	tcode          = HEADER_GET_TCODE(request_header[0]);	tlabel         = HEADER_GET_TLABEL(request_header[0]);	source         = HEADER_GET_DESTINATION(request_header[0]);	destination    = HEADER_GET_SOURCE(request_header[1]);	extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]);	response->header[0] =		HEADER_RETRY(RETRY_1) |		HEADER_TLABEL(tlabel) |		HEADER_DESTINATION(destination);	response->header[1] =		HEADER_SOURCE(source) |		HEADER_RCODE(rcode);	response->header[2] = 0;	switch (tcode) {	case TCODE_WRITE_QUADLET_REQUEST:	case TCODE_WRITE_BLOCK_REQUEST:		response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE);		response->header_length = 12;		response->payload_length = 0;		break;	case TCODE_READ_QUADLET_REQUEST:		response->header[0] |=			HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE);		if (payload != NULL)			response->header[3] = *(u32 *)payload;		else			response->header[3] = 0;		response->header_length = 16;		response->payload_length = 0;		break;	case TCODE_READ_BLOCK_REQUEST:	case TCODE_LOCK_REQUEST:		response->header[0] |= HEADER_TCODE(tcode + 2);		response->header[3] =			HEADER_DATA_LENGTH(length) |			HEADER_EXTENDED_TCODE(extended_tcode);		response->header_length = 16;		response->payload = payload;		response->payload_length = length;		break;	default:		BUG();		return;	}}EXPORT_SYMBOL(fw_fill_response);static struct fw_request *allocate_request(struct fw_packet *p){	struct fw_request *request;	u32 *data, length;	int request_tcode, t;	request_tcode = HEADER_GET_TCODE(p->header[0]);	switch (request_tcode) {	case TCODE_WRITE_QUADLET_REQUEST:		data = &p->header[3];		length = 4;		break;	case TCODE_WRITE_BLOCK_REQUEST:	case TCODE_LOCK_REQUEST:		data = p->payload;		length = HEADER_GET_DATA_LENGTH(p->header[3]);		break;	case TCODE_READ_QUADLET_REQUEST:		data = NULL;		length = 4;		break;	case TCODE_READ_BLOCK_REQUEST:		data = NULL;		length = HEADER_GET_DATA_LENGTH(p->header[3]);		break;	default:		BUG();		return NULL;	}	request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);	if (request == NULL)		return NULL;	t = (p->timestamp & 0x1fff) + 4000;	if (t >= 8000)		t = (p->timestamp & ~0x1fff) + 0x2000 + t - 8000;	else		t = (p->timestamp & ~0x1fff) + t;	request->response.speed = p->speed;	request->response.timestamp = t;	request->response.generation = p->generation;	request->response.ack = 0;	request->response.callback = free_response_callback;	request->ack = p->ack;	request->length = length;	if (data)		memcpy(request->data, data, length);	memcpy(request->request_header, p->header, sizeof(p->header));	return request;}voidfw_send_response(struct fw_card *card, struct fw_request *request, int rcode){	/*	 * Broadcast packets are reported as ACK_COMPLETE, so this	 * check is sufficient to ensure we don't send response to	 * broadcast packets or posted writes.	 */	if (request->ack != ACK_PENDING) {		kfree(request);		return;	}	if (rcode == RCODE_COMPLETE)		fw_fill_response(&request->response, request->request_header,				 rcode, request->data, request->length);	else		fw_fill_response(&request->response, request->request_header,				 rcode, NULL, 0);	card->driver->send_response(card, &request->response);}EXPORT_SYMBOL(fw_send_response);voidfw_core_handle_request(struct fw_card *card, struct fw_packet *p){	struct fw_address_handler *handler;	struct fw_request *request;	unsigned long long offset;	unsigned long flags;	int tcode, destination, source;	if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)		return;	request = allocate_request(p);	if (request == NULL) {		/* FIXME: send statically allocated busy packet. */		return;	}	offset      =		((unsigned long long)		 HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | p->header[2];	tcode       = HEADER_GET_TCODE(p->header[0]);	destination = HEADER_GET_DESTINATION(p->header[0]);	source      = HEADER_GET_SOURCE(p->header[0]);	spin_lock_irqsave(&address_handler_lock, flags);	handler = lookup_enclosing_address_handler(&address_handler_list,						   offset, request->length);	spin_unlock_irqrestore(&address_handler_lock, flags);	/*	 * FIXME: lookup the fw_node corresponding to the sender of	 * this request and pass that to the address handler instead	 * of the node ID.  We may also want to move the address	 * allocations to fw_node so we only do this callback if the	 * upper layers registered it for this node.	 */	if (handler == NULL)		fw_send_response(card, request, RCODE_ADDRESS_ERROR);	else		handler->address_callback(card, request,					  tcode, destination, source,					  p->generation, p->speed, offset,					  request->data, request->length,					  handler->callback_data);}EXPORT_SYMBOL(fw_core_handle_request);voidfw_core_handle_response(struct fw_card *card, struct fw_packet *p){	struct fw_transaction *t;	unsigned long flags;	u32 *data;	size_t data_length;	int tcode, tlabel, destination, source, rcode;	tcode       = HEADER_GET_TCODE(p->header[0]);	tlabel      = HEADER_GET_TLABEL(p->header[0]);	destination = HEADER_GET_DESTINATION(p->header[0]);	source      = HEADER_GET_SOURCE(p->header[1]);	rcode       = HEADER_GET_RCODE(p->header[1]);	spin_lock_irqsave(&card->lock, flags);	list_for_each_entry(t, &card->transaction_list, link) {		if (t->node_id == source && t->tlabel == tlabel) {			list_del(&t->link);			card->tlabel_mask &= ~(1 << t->tlabel);			break;		}	}	spin_unlock_irqrestore(&card->lock, flags);	if (&t->link == &card->transaction_list) {		fw_notify("Unsolicited response (source %x, tlabel %x)\n",			  source, tlabel);		return;	}	/*	 * FIXME: sanity check packet, is length correct, does tcodes	 * and addresses match.	 */	switch (tcode) {	case TCODE_READ_QUADLET_RESPONSE:		data = (u32 *) &p->header[3];		data_length = 4;		break;	case TCODE_WRITE_RESPONSE:		data = NULL;		data_length = 0;		break;	case TCODE_READ_BLOCK_RESPONSE:	case TCODE_LOCK_RESPONSE:		data = p->payload;		data_length = HEADER_GET_DATA_LENGTH(p->header[3]);		break;	default:		/* Should never happen, this is just to shut up gcc. */		data = NULL;		data_length = 0;		break;	}	t->callback(card, rcode, data, data_length, t->callback_data);}EXPORT_SYMBOL(fw_core_handle_response);static const struct fw_address_region topology_map_region =	{ .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, };static voidhandle_topology_map(struct fw_card *card, struct fw_request *request,		    int tcode, int destination, int source,		    int generation, int speed,		    unsigned long long offset,		    void *payload, size_t length, void *callback_data){	int i, start, end;	u32 *map;	if (!TCODE_IS_READ_REQUEST(tcode)) {		fw_send_response(card, request, RCODE_TYPE_ERROR);		return;	}	if ((offset & 3) > 0 || (length & 3) > 0) {		fw_send_response(card, request, RCODE_ADDRESS_ERROR);		return;	}	start = (offset - topology_map_region.start) / 4;	end = start + length / 4;	map = payload;	for (i = 0; i < length / 4; i++)		map[i] = cpu_to_be32(card->topology_map[start + i]);	fw_send_response(card, request, RCODE_COMPLETE);}static struct fw_address_handler topology_map = {	.length			= 0x200,	.address_callback	= handle_topology_map,};static const struct fw_address_region registers_region =	{ .start = 0xfffff0000000ull, .end = 0xfffff0000400ull, };static voidhandle_registers(struct fw_card *card, struct fw_request *request,		 int tcode, int destination, int source,		 int generation, int speed,		 unsigned long long offset,		 void *payload, size_t length, void *callback_data){	int reg = offset - CSR_REGISTER_BASE;	unsigned long long bus_time;	__be32 *data = payload;	switch (reg) {	case CSR_CYCLE_TIME:	case CSR_BUS_TIME:		if (!TCODE_IS_READ_REQUEST(tcode) || length != 4) {			fw_send_response(card, request, RCODE_TYPE_ERROR);			break;		}		bus_time = card->driver->get_bus_time(card);		if (reg == CSR_CYCLE_TIME)			*data = cpu_to_be32(bus_time);		else			*data = cpu_to_be32(bus_time >> 25);		fw_send_response(card, request, RCODE_COMPLETE);		break;	case CSR_BUS_MANAGER_ID:	case CSR_BANDWIDTH_AVAILABLE:	case CSR_CHANNELS_AVAILABLE_HI:	case CSR_CHANNELS_AVAILABLE_LO:		/*		 * FIXME: these are handled by the OHCI hardware and		 * the stack never sees these request. If we add		 * support for a new type of controller that doesn't		 * handle this in hardware we need to deal with these		 * transactions.		 */		BUG();		break;	case CSR_BUSY_TIMEOUT:		/* FIXME: Implement this. */	default:		fw_send_response(card, request, RCODE_ADDRESS_ERROR);		break;	}}static struct fw_address_handler registers = {	.length			= 0x400,	.address_callback	= handle_registers,};MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");MODULE_DESCRIPTION("Core IEEE1394 transaction logic");MODULE_LICENSE("GPL");static const u32 vendor_textual_descriptor[] = {	/* textual descriptor leaf () */	0x00060000,	0x00000000,	0x00000000,	0x4c696e75,		/* L i n u */	0x78204669,		/* x   F i */	0x72657769,		/* r e w i */	0x72650000,		/* r e     */};static const u32 model_textual_descriptor[] = {	/* model descriptor leaf () */	0x00030000,	0x00000000,	0x00000000,	0x4a756a75,		/* J u j u */};static struct fw_descriptor vendor_id_descriptor = {	.length = ARRAY_SIZE(vendor_textual_descriptor),	.immediate = 0x03d00d1e,	.key = 0x81000000,	.data = vendor_textual_descriptor,};static struct fw_descriptor model_id_descriptor = {	.length = ARRAY_SIZE(model_textual_descriptor),	.immediate = 0x17000001,	.key = 0x81000000,	.data = model_textual_descriptor,};static int __init fw_core_init(void){	int retval;	retval = bus_register(&fw_bus_type);	if (retval < 0)		return retval;	fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);	if (fw_cdev_major < 0) {		bus_unregister(&fw_bus_type);		return fw_cdev_major;	}	retval = fw_core_add_address_handler(&topology_map,					     &topology_map_region);	BUG_ON(retval < 0);	retval = fw_core_add_address_handler(&registers,					     &registers_region);	BUG_ON(retval < 0);	/* Add the vendor textual descriptor. */	retval = fw_core_add_descriptor(&vendor_id_descriptor);	BUG_ON(retval < 0);	retval = fw_core_add_descriptor(&model_id_descriptor);	BUG_ON(retval < 0);	return 0;}static void __exit fw_core_cleanup(void){	unregister_chrdev(fw_cdev_major, "firewire");	bus_unregister(&fw_bus_type);}module_init(fw_core_init);module_exit(fw_core_cleanup);

⌨️ 快捷键说明

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