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

📄 raw1394.c

📁 Ieee1394驱动实现
💻 C
📖 第 1 页 / 共 5 页
字号:
	}

	if (file->f_flags & O_NONBLOCK) {
		if (!(req = next_complete_req(fi)))
			return -EAGAIN;
	} else {
		/*
		 * NB: We call the macro wait_event_interruptible() with a
		 * condition argument with side effect.  This is only possible
		 * because the side effect does not occur until the condition
		 * became true, and wait_event_interruptible() won't evaluate
		 * the condition again after that.
		 */
		if (wait_event_interruptible(fi->wait_complete,
					     (req = next_complete_req(fi))))
			return -ERESTARTSYS;
	}

	if (req->req.length) {
		if (copy_to_user(int2ptr(req->req.recvb), req->data,
				 req->req.length)) {
			req->req.error = RAW1394_ERROR_MEMFAULT;
		}
	}

#ifdef CONFIG_COMPAT
	if (count == sizeof(struct compat_raw1394_req) &&
   	    sizeof(struct compat_raw1394_req) !=
			sizeof(struct raw1394_request)) {
		ret = raw1394_compat_read(buffer, &req->req);
	} else
#endif
	{
		if (copy_to_user(buffer, &req->req, sizeof(req->req))) {
			ret = -EFAULT;
			goto out;
		}
		ret = (ssize_t) sizeof(struct raw1394_request);
	}
      out:
	free_pending_request(req);
	return ret;
}

static int state_opened(struct file_info *fi, struct pending_request *req)
{
	if (req->req.type == RAW1394_REQ_INITIALIZE) {
		switch (req->req.misc) {
		case RAW1394_KERNELAPI_VERSION:
		case 3:
			fi->state = initialized;
			fi->protocol_version = req->req.misc;
			req->req.error = RAW1394_ERROR_NONE;
			req->req.generation = atomic_read(&internal_generation);
			break;

		default:
			req->req.error = RAW1394_ERROR_COMPAT;
			req->req.misc = RAW1394_KERNELAPI_VERSION;
		}
	} else {
		req->req.error = RAW1394_ERROR_STATE_ORDER;
	}

	req->req.length = 0;
	queue_complete_req(req);
	return 0;
}

static int state_initialized(struct file_info *fi, struct pending_request *req)
{
	unsigned long flags;
	struct host_info *hi;
	struct raw1394_khost_list *khl;

	if (req->req.generation != atomic_read(&internal_generation)) {
		req->req.error = RAW1394_ERROR_GENERATION;
		req->req.generation = atomic_read(&internal_generation);
		req->req.length = 0;
		queue_complete_req(req);
		return 0;
	}

	switch (req->req.type) {
	case RAW1394_REQ_LIST_CARDS:
		spin_lock_irqsave(&host_info_lock, flags);
		khl = kmalloc(sizeof(*khl) * host_count, GFP_ATOMIC);

		if (khl) {
			req->req.misc = host_count;
			req->data = (quadlet_t *) khl;

			list_for_each_entry(hi, &host_info_list, list) {
				khl->nodes = hi->host->node_count;
				strcpy(khl->name, hi->host->driver->name);
				khl++;
			}
		}
		spin_unlock_irqrestore(&host_info_lock, flags);

		if (khl) {
			req->req.error = RAW1394_ERROR_NONE;
			req->req.length = min(req->req.length,
					      (u32) (sizeof
						     (struct raw1394_khost_list)
						     * req->req.misc));
			req->free_data = 1;
		} else {
			return -ENOMEM;
		}
		break;

	case RAW1394_REQ_SET_CARD:
		spin_lock_irqsave(&host_info_lock, flags);
		if (req->req.misc >= host_count) {
			req->req.error = RAW1394_ERROR_INVALID_ARG;
			goto out_set_card;
		}
		list_for_each_entry(hi, &host_info_list, list)
			if (!req->req.misc--)
				break;
		get_device(&hi->host->device); /* FIXME handle failure case */
		list_add_tail(&fi->list, &hi->file_info_list);

		/* prevent unloading of the host's low-level driver */
		if (!try_module_get(hi->host->driver->owner)) {
			req->req.error = RAW1394_ERROR_ABORTED;
			goto out_set_card;
		}
		WARN_ON(fi->host);
		fi->host = hi->host;
		fi->state = connected;

		req->req.error = RAW1394_ERROR_NONE;
		req->req.generation = get_hpsb_generation(fi->host);
		req->req.misc = (fi->host->node_id << 16)
				| fi->host->node_count;
		if (fi->protocol_version > 3)
			req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
out_set_card:
		spin_unlock_irqrestore(&host_info_lock, flags);

		req->req.length = 0;
		break;

	default:
		req->req.error = RAW1394_ERROR_STATE_ORDER;
		req->req.length = 0;
		break;
	}

	queue_complete_req(req);
	return 0;
}

static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
{
	if (req->req.misc) {
		if (fi->fcp_buffer) {
			req->req.error = RAW1394_ERROR_ALREADY;
		} else {
			fi->fcp_buffer = int2ptr(req->req.recvb);
		}
	} else {
		if (!fi->fcp_buffer) {
			req->req.error = RAW1394_ERROR_ALREADY;
		} else {
			fi->fcp_buffer = NULL;
		}
	}

	req->req.length = 0;
	queue_complete_req(req);
}

static int handle_async_request(struct file_info *fi,
				struct pending_request *req, int node)
{
	unsigned long flags;
	struct hpsb_packet *packet = NULL;
	u64 addr = req->req.address & 0xffffffffffffULL;

	switch (req->req.type) {
	case RAW1394_REQ_ASYNC_READ:
		DBGMSG("read_request called");
		packet =
		    hpsb_make_readpacket(fi->host, node, addr, req->req.length);

		if (!packet)
			return -ENOMEM;

		if (req->req.length == 4)
			req->data = &packet->header[3];
		else
			req->data = packet->data;

		break;

	case RAW1394_REQ_ASYNC_WRITE:
		DBGMSG("write_request called");

		packet = hpsb_make_writepacket(fi->host, node, addr, NULL,
					       req->req.length);
		if (!packet)
			return -ENOMEM;

		if (req->req.length == 4) {
			if (copy_from_user
			    (&packet->header[3], int2ptr(req->req.sendb),
			     req->req.length))
				req->req.error = RAW1394_ERROR_MEMFAULT;
		} else {
			if (copy_from_user
			    (packet->data, int2ptr(req->req.sendb),
			     req->req.length))
				req->req.error = RAW1394_ERROR_MEMFAULT;
		}

		req->req.length = 0;
		break;

	case RAW1394_REQ_ASYNC_STREAM:
		DBGMSG("stream_request called");

		packet =
		    hpsb_make_streampacket(fi->host, NULL, req->req.length,
					   node & 0x3f /*channel */ ,
					   (req->req.misc >> 16) & 0x3,
					   req->req.misc & 0xf);
		if (!packet)
			return -ENOMEM;

		if (copy_from_user(packet->data, int2ptr(req->req.sendb),
				   req->req.length))
			req->req.error = RAW1394_ERROR_MEMFAULT;

		req->req.length = 0;
		break;

	case RAW1394_REQ_LOCK:
		DBGMSG("lock_request called");
		if ((req->req.misc == EXTCODE_FETCH_ADD)
		    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
			if (req->req.length != 4) {
				req->req.error = RAW1394_ERROR_INVALID_ARG;
				break;
			}
		} else {
			if (req->req.length != 8) {
				req->req.error = RAW1394_ERROR_INVALID_ARG;
				break;
			}
		}

		packet = hpsb_make_lockpacket(fi->host, node, addr,
					      req->req.misc, NULL, 0);
		if (!packet)
			return -ENOMEM;

		if (copy_from_user(packet->data, int2ptr(req->req.sendb),
				   req->req.length)) {
			req->req.error = RAW1394_ERROR_MEMFAULT;
			break;
		}

		req->data = packet->data;
		req->req.length = 4;
		break;

	case RAW1394_REQ_LOCK64:
		DBGMSG("lock64_request called");
		if ((req->req.misc == EXTCODE_FETCH_ADD)
		    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
			if (req->req.length != 8) {
				req->req.error = RAW1394_ERROR_INVALID_ARG;
				break;
			}
		} else {
			if (req->req.length != 16) {
				req->req.error = RAW1394_ERROR_INVALID_ARG;
				break;
			}
		}
		packet = hpsb_make_lock64packet(fi->host, node, addr,
						req->req.misc, NULL, 0);
		if (!packet)
			return -ENOMEM;

		if (copy_from_user(packet->data, int2ptr(req->req.sendb),
				   req->req.length)) {
			req->req.error = RAW1394_ERROR_MEMFAULT;
			break;
		}

		req->data = packet->data;
		req->req.length = 8;
		break;

	default:
		req->req.error = RAW1394_ERROR_STATE_ORDER;
	}

	req->packet = packet;

	if (req->req.error) {
		req->req.length = 0;
		queue_complete_req(req);
		return 0;
	}

	hpsb_set_packet_complete_task(packet,
				      (void (*)(void *))queue_complete_cb, req);

	spin_lock_irqsave(&fi->reqlists_lock, flags);
	list_add_tail(&req->list, &fi->req_pending);
	spin_unlock_irqrestore(&fi->reqlists_lock, flags);

	packet->generation = req->req.generation;

	if (hpsb_send_packet(packet) < 0) {
		req->req.error = RAW1394_ERROR_SEND_ERROR;
		req->req.length = 0;
		hpsb_free_tlabel(packet);
		queue_complete_req(req);
	}
	return 0;
}

static int handle_async_send(struct file_info *fi, struct pending_request *req)
{
	unsigned long flags;
	struct hpsb_packet *packet;
	int header_length = req->req.misc & 0xffff;
	int expect_response = req->req.misc >> 16;
	size_t data_size;

	if (header_length > req->req.length || header_length < 12 ||
	    header_length > FIELD_SIZEOF(struct hpsb_packet, header)) {
		req->req.error = RAW1394_ERROR_INVALID_ARG;
		req->req.length = 0;
		queue_complete_req(req);
		return 0;
	}

	data_size = req->req.length - header_length;
	packet = hpsb_alloc_packet(data_size);
	req->packet = packet;
	if (!packet)
		return -ENOMEM;

	if (copy_from_user(packet->header, int2ptr(req->req.sendb),
			   header_length)) {
		req->req.error = RAW1394_ERROR_MEMFAULT;
		req->req.length = 0;
		queue_complete_req(req);
		return 0;
	}

	if (copy_from_user
	    (packet->data, int2ptr(req->req.sendb) + header_length,
	     data_size)) {
		req->req.error = RAW1394_ERROR_MEMFAULT;
		req->req.length = 0;
		queue_complete_req(req);
		return 0;
	}

	packet->type = hpsb_async;
	packet->node_id = packet->header[0] >> 16;
	packet->tcode = (packet->header[0] >> 4) & 0xf;
	packet->tlabel = (packet->header[0] >> 10) & 0x3f;
	packet->host = fi->host;
	packet->expect_response = expect_response;
	packet->header_size = header_length;
	packet->data_size = data_size;

	req->req.length = 0;
	hpsb_set_packet_complete_task(packet,
				      (void (*)(void *))queue_complete_cb, req);

	spin_lock_irqsave(&fi->reqlists_lock, flags);
	list_add_tail(&req->list, &fi->req_pending);
	spin_unlock_irqrestore(&fi->reqlists_lock, flags);

	/* Update the generation of the packet just before sending. */
	packet->generation = req->req.generation;

	if (hpsb_send_packet(packet) < 0) {
		req->req.error = RAW1394_ERROR_SEND_ERROR;
		queue_complete_req(req);
	}

	return 0;
}

static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer,
		    u64 addr, size_t length, u16 flags)
{
	unsigned long irqflags;
	struct pending_request *req;
	struct host_info *hi;
	struct file_info *fi = NULL;
	struct list_head *entry;
	struct arm_addr *arm_addr = NULL;
	struct arm_request *arm_req = NULL;
	struct arm_response *arm_resp = NULL;
	int found = 0, size = 0, rcode = -1;
	struct arm_request_response *arm_req_resp = NULL;

	DBGMSG("arm_read  called by node: %X"
	       "addr: %4.4x %8.8x length: %Zu", nodeid,
	       (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
	       length);
	spin_lock_irqsave(&host_info_lock, irqflags);
	hi = find_host_info(host);	/* search address-entry */
	if (hi != NULL) {
		list_for_each_entry(fi, &hi->file_info_list, list) {
			entry = fi->addr_list.next;
			while (entry != &(fi->addr_list)) {
				arm_addr =
				    list_entry(entry, struct arm_addr,
					       addr_list);
				if (((arm_addr->start) <= (addr))
				    && ((arm_addr->end) >= (addr + length))) {
					found = 1;
					break;
				}
				entry = entry->next;
			}
			if (found) {
				break;
			}
		}
	}
	rcode = -1;
	if (!found) {
		printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
		       " -> rcode_address_error\n");
		spin_unlock_irqrestore(&host_info_lock, irqflags);
		return (RCODE_ADDRESS_ERROR);
	} else {
		DBGMSG("arm_read addr_entry FOUND");
	}
	if (arm_addr->rec_length < length) {
		DBGMSG("arm_read blocklength too big -> rcode_data_error");
		rcode = RCODE_DATA_ERROR;	/* hardware error, data is unavailable */
	}
	if (rcode == -1) {
		if (arm_addr->access_rights & ARM_READ) {
			if (!(arm_addr->client_transactions & ARM_READ)) {
				memcpy(buffer,

⌨️ 快捷键说明

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