📄 raw1394.c
字号:
}
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 + -