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

📄 raw1394.c

📁 Ieee1394驱动实现
💻 C
📖 第 1 页 / 共 5 页
字号:
		return 0;
	}
	retval =
	    hpsb_unregister_addrspace(&raw1394_highlevel, fi->host,
				      addr->start);
	if (!retval) {
		printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
		spin_unlock_irqrestore(&host_info_lock, flags);
		return (-EINVAL);
	}
	DBGMSG("delete entry from list -> success");
	list_del(&addr->addr_list);
	spin_unlock_irqrestore(&host_info_lock, flags);
	vfree(addr->addr_space_buffer);
	kfree(addr);
	free_pending_request(req);	/* immediate success or fail */
	return 0;
}

/* Copy data from ARM buffer(s) to user buffer. */
static int arm_get_buf(struct file_info *fi, struct pending_request *req)
{
	struct arm_addr *arm_addr = NULL;
	unsigned long flags;
	unsigned long offset;

	struct list_head *entry;

	DBGMSG("arm_get_buf "
	       "addr(Offset): %04X %08X length: %u",
	       (u32) ((req->req.address >> 32) & 0xFFFF),
	       (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);

	spin_lock_irqsave(&host_info_lock, flags);
	entry = fi->addr_list.next;
	while (entry != &(fi->addr_list)) {
		arm_addr = list_entry(entry, struct arm_addr, addr_list);
		if ((arm_addr->start <= req->req.address) &&
		    (arm_addr->end > req->req.address)) {
			if (req->req.address + req->req.length <= arm_addr->end) {
				offset = req->req.address - arm_addr->start;
				spin_unlock_irqrestore(&host_info_lock, flags);

				DBGMSG
				    ("arm_get_buf copy_to_user( %08X, %p, %u )",
				     (u32) req->req.recvb,
				     arm_addr->addr_space_buffer + offset,
				     (u32) req->req.length);
				if (copy_to_user
				    (int2ptr(req->req.recvb),
				     arm_addr->addr_space_buffer + offset,
				     req->req.length))
					return (-EFAULT);

				/* We have to free the request, because we
				 * queue no response, and therefore nobody
				 * will free it. */
				free_pending_request(req);
				return 0;
			} else {
				DBGMSG("arm_get_buf request exceeded mapping");
				spin_unlock_irqrestore(&host_info_lock, flags);
				return (-EINVAL);
			}
		}
		entry = entry->next;
	}
	spin_unlock_irqrestore(&host_info_lock, flags);
	return (-EINVAL);
}

/* Copy data from user buffer to ARM buffer(s). */
static int arm_set_buf(struct file_info *fi, struct pending_request *req)
{
	struct arm_addr *arm_addr = NULL;
	unsigned long flags;
	unsigned long offset;

	struct list_head *entry;

	DBGMSG("arm_set_buf "
	       "addr(Offset): %04X %08X length: %u",
	       (u32) ((req->req.address >> 32) & 0xFFFF),
	       (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length);

	spin_lock_irqsave(&host_info_lock, flags);
	entry = fi->addr_list.next;
	while (entry != &(fi->addr_list)) {
		arm_addr = list_entry(entry, struct arm_addr, addr_list);
		if ((arm_addr->start <= req->req.address) &&
		    (arm_addr->end > req->req.address)) {
			if (req->req.address + req->req.length <= arm_addr->end) {
				offset = req->req.address - arm_addr->start;
				spin_unlock_irqrestore(&host_info_lock, flags);

				DBGMSG
				    ("arm_set_buf copy_from_user( %p, %08X, %u )",
				     arm_addr->addr_space_buffer + offset,
				     (u32) req->req.sendb,
				     (u32) req->req.length);
				if (copy_from_user
				    (arm_addr->addr_space_buffer + offset,
				     int2ptr(req->req.sendb),
				     req->req.length))
					return (-EFAULT);

				/* We have to free the request, because we
				 * queue no response, and therefore nobody
				 * will free it. */
				free_pending_request(req);
				return 0;
			} else {
				DBGMSG("arm_set_buf request exceeded mapping");
				spin_unlock_irqrestore(&host_info_lock, flags);
				return (-EINVAL);
			}
		}
		entry = entry->next;
	}
	spin_unlock_irqrestore(&host_info_lock, flags);
	return (-EINVAL);
}

static int reset_notification(struct file_info *fi, struct pending_request *req)
{
	DBGMSG("reset_notification called - switch %s ",
	       (req->req.misc == RAW1394_NOTIFY_OFF) ? "OFF" : "ON");
	if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
	    (req->req.misc == RAW1394_NOTIFY_ON)) {
		fi->notification = (u8) req->req.misc;
		free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
		return 0;
	}
	/* error EINVAL (22) invalid argument */
	return (-EINVAL);
}

static int write_phypacket(struct file_info *fi, struct pending_request *req)
{
	struct hpsb_packet *packet = NULL;
	int retval = 0;
	quadlet_t data;
	unsigned long flags;

	data = be32_to_cpu((u32) req->req.sendb);
	DBGMSG("write_phypacket called - quadlet 0x%8.8x ", data);
	packet = hpsb_make_phypacket(fi->host, data);
	if (!packet)
		return -ENOMEM;
	req->req.length = 0;
	req->packet = packet;
	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;
	retval = hpsb_send_packet(packet);
	DBGMSG("write_phypacket send_packet called => retval: %d ", retval);
	if (retval < 0) {
		req->req.error = RAW1394_ERROR_SEND_ERROR;
		req->req.length = 0;
		queue_complete_req(req);
	}
	return 0;
}

static int get_config_rom(struct file_info *fi, struct pending_request *req)
{
	int ret = 0;
	quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
	int status;

	if (!data)
		return -ENOMEM;

	status =
	    csr1212_read(fi->host->csr.rom, CSR1212_CONFIG_ROM_SPACE_OFFSET,
			 data, req->req.length);
	if (copy_to_user(int2ptr(req->req.recvb), data, req->req.length))
		ret = -EFAULT;
	if (copy_to_user
	    (int2ptr(req->req.tag), &fi->host->csr.rom->cache_head->len,
	     sizeof(fi->host->csr.rom->cache_head->len)))
		ret = -EFAULT;
	if (copy_to_user(int2ptr(req->req.address), &fi->host->csr.generation,
			 sizeof(fi->host->csr.generation)))
		ret = -EFAULT;
	if (copy_to_user(int2ptr(req->req.sendb), &status, sizeof(status)))
		ret = -EFAULT;
	kfree(data);
	if (ret >= 0) {
		free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
	}
	return ret;
}

static int update_config_rom(struct file_info *fi, struct pending_request *req)
{
	int ret = 0;
	quadlet_t *data = kmalloc(req->req.length, GFP_KERNEL);
	if (!data)
		return -ENOMEM;
	if (copy_from_user(data, int2ptr(req->req.sendb), req->req.length)) {
		ret = -EFAULT;
	} else {
		int status = hpsb_update_config_rom(fi->host,
						    data, req->req.length,
						    (unsigned char)req->req.
						    misc);
		if (copy_to_user
		    (int2ptr(req->req.recvb), &status, sizeof(status)))
			ret = -ENOMEM;
	}
	kfree(data);
	if (ret >= 0) {
		free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
		fi->cfgrom_upd = 1;
	}
	return ret;
}

static int modify_config_rom(struct file_info *fi, struct pending_request *req)
{
	struct csr1212_keyval *kv;
	struct csr1212_csr_rom_cache *cache;
	struct csr1212_dentry *dentry;
	u32 dr;
	int ret = 0;

	if (req->req.misc == ~0) {
		if (req->req.length == 0)
			return -EINVAL;

		/* Find an unused slot */
		for (dr = 0;
		     dr < RAW1394_MAX_USER_CSR_DIRS && fi->csr1212_dirs[dr];
		     dr++) ;

		if (dr == RAW1394_MAX_USER_CSR_DIRS)
			return -ENOMEM;

		fi->csr1212_dirs[dr] =
		    csr1212_new_directory(CSR1212_KV_ID_VENDOR);
		if (!fi->csr1212_dirs[dr])
			return -ENOMEM;
	} else {
		dr = req->req.misc;
		if (!fi->csr1212_dirs[dr])
			return -EINVAL;

		/* Delete old stuff */
		for (dentry =
		     fi->csr1212_dirs[dr]->value.directory.dentries_head;
		     dentry; dentry = dentry->next) {
			csr1212_detach_keyval_from_directory(fi->host->csr.rom->
							     root_kv,
							     dentry->kv);
		}

		if (req->req.length == 0) {
			csr1212_release_keyval(fi->csr1212_dirs[dr]);
			fi->csr1212_dirs[dr] = NULL;

			hpsb_update_config_rom_image(fi->host);
			free_pending_request(req);
			return 0;
		}
	}

	cache = csr1212_rom_cache_malloc(0, req->req.length);
	if (!cache) {
		csr1212_release_keyval(fi->csr1212_dirs[dr]);
		fi->csr1212_dirs[dr] = NULL;
		return -ENOMEM;
	}

	cache->filled_head = kmalloc(sizeof(*cache->filled_head), GFP_KERNEL);
	if (!cache->filled_head) {
		csr1212_release_keyval(fi->csr1212_dirs[dr]);
		fi->csr1212_dirs[dr] = NULL;
		CSR1212_FREE(cache);
		return -ENOMEM;
	}
	cache->filled_tail = cache->filled_head;

	if (copy_from_user(cache->data, int2ptr(req->req.sendb),
			   req->req.length)) {
		csr1212_release_keyval(fi->csr1212_dirs[dr]);
		fi->csr1212_dirs[dr] = NULL;
		ret = -EFAULT;
	} else {
		cache->len = req->req.length;
		cache->filled_head->offset_start = 0;
		cache->filled_head->offset_end = cache->size - 1;

		cache->layout_head = cache->layout_tail = fi->csr1212_dirs[dr];

		ret = CSR1212_SUCCESS;
		/* parse all the items */
		for (kv = cache->layout_head; ret == CSR1212_SUCCESS && kv;
		     kv = kv->next) {
			ret = csr1212_parse_keyval(kv, cache);
		}

		/* attach top level items to the root directory */
		for (dentry =
		     fi->csr1212_dirs[dr]->value.directory.dentries_head;
		     ret == CSR1212_SUCCESS && dentry; dentry = dentry->next) {
			ret =
			    csr1212_attach_keyval_to_directory(fi->host->csr.
							       rom->root_kv,
							       dentry->kv);
		}

		if (ret == CSR1212_SUCCESS) {
			ret = hpsb_update_config_rom_image(fi->host);

			if (ret >= 0 && copy_to_user(int2ptr(req->req.recvb),
						     &dr, sizeof(dr))) {
				ret = -ENOMEM;
			}
		}
	}
	kfree(cache->filled_head);
	CSR1212_FREE(cache);

	if (ret >= 0) {
		/* we have to free the request, because we queue no response,
		 * and therefore nobody will free it */
		free_pending_request(req);
		return 0;
	} else {
		for (dentry =
		     fi->csr1212_dirs[dr]->value.directory.dentries_head;
		     dentry; dentry = dentry->next) {
			csr1212_detach_keyval_from_directory(fi->host->csr.rom->
							     root_kv,
							     dentry->kv);
		}
		csr1212_release_keyval(fi->csr1212_dirs[dr]);
		fi->csr1212_dirs[dr] = NULL;
		return ret;
	}
}

static int state_connected(struct file_info *fi, struct pending_request *req)
{
	int node = req->req.address >> 48;

	req->req.error = RAW1394_ERROR_NONE;

	switch (req->req.type) {

	case RAW1394_REQ_ECHO:
		queue_complete_req(req);
		return 0;

	case RAW1394_REQ_ARM_REGISTER:
		return arm_register(fi, req);

	case RAW1394_REQ_ARM_UNREGISTER:
		return arm_unregister(fi, req);

	case RAW1394_REQ_ARM_SET_BUF:
		return arm_set_buf(fi, req);

	case RAW1394_REQ_ARM_GET_BUF:
		return arm_get_buf(fi, req);

	case RAW1394_REQ_RESET_NOTIFY:
		return reset_notification(fi, req);

	case RAW1394_REQ_ISO_SEND:
	case RAW1394_REQ_ISO_LISTEN:
		printk(KERN_DEBUG "raw1394: old iso ABI has been removed\n");
		req->req.error = RAW1394_ERROR_COMPAT;
		req->req.misc = RAW1394_KERNELAPI_VERSION;
		queue_complete_req(req);
		return 0;

	case RAW1394_REQ_FCP_LISTEN:
		handle_fcp_listen(fi, req);
		return 0;

	case RAW1394_REQ_RESET_BUS:
		if (req->req.misc == RAW1394_LONG_RESET) {
			DBGMSG("busreset called (type: LONG)");
			hpsb_reset_bus(fi->host, LONG_RESET);
			free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
			return 0;
		}
		if (req->req.misc == RAW1394_SHORT_RESET) {
			DBGMSG("busreset called (type: SHORT)");
			hpsb_reset_bus(fi->host, SHORT_RESET);
			free_pending_request(req);	/* we have to free the request, because we queue no response, and therefore nobody will free it */
			return 0;
		}
		/* error EINVAL (22) invalid argument */
		return (-EINVAL);
	case RAW1394_REQ_GET_ROM:
		return get_config_rom(fi, req);

	case RAW1394_REQ_UPDATE_ROM:
		return update_config_rom(fi, req);

	case RAW1394_REQ_MODIFY_ROM:
		return modify_config_rom(fi, req);
	}

	if (req->req.generation != get_hpsb_generation(fi->host)) {
		req->req.error = RAW1394_ERROR_GENERATION;
		req->req.generation = get_hpsb_generation(fi->host);
		req->req.length = 0;
		queue_complete_req(req);
		return 0;
	}

	switch (req->req.type) {
	case RAW1394_REQ_PHYPACKET:
		return write_phypacket(fi, req);
	case RAW1394_REQ_ASYNC_SEND:
		return handle_async_send(fi, req);
	}

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

	return handle_async_request(fi, req, node);
}

static ssize_t raw1394_write(struct file *file, const char __user * buffer,
			     size_t count, loff_t * offset_is_ignored)
{
	struct file_info *fi = (struct file_info *)file->private_data;
	struct pending_request *req;
	ssize_t retval = -EBADFD;

#ifdef CONFIG_COMPAT
	if (count == sizeof(struct compat_raw1394_req) &&
   	    sizeof(struct compat_raw1394_req) !=
			sizeof(struct raw1394_request)) {
		buffer = raw1394_compat_write(buffer);
		if (IS_ERR(buffer))
			return P

⌨️ 快捷键说明

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