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