X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fieee1394%2Fraw1394.c;h=f7de546f2ed6f34e1d874064f15c788c0e56698a;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=674dd23e55857e0558558d086ae4410bb2c9e156;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 674dd23e5..f7de546f2 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include "csr1212.h" #include "ieee1394.h" @@ -75,58 +75,57 @@ static DEFINE_SPINLOCK(host_info_lock); static atomic_t internal_generation = ATOMIC_INIT(0); static atomic_t iso_buffer_size; -static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */ +static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */ static struct hpsb_highlevel raw1394_highlevel; -static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer, - u64 addr, size_t length, u16 flags); -static int arm_write (struct hpsb_host *host, int nodeid, int destid, - quadlet_t *data, u64 addr, size_t length, u16 flags); -static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store, - u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags); -static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store, - u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags); +static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer, + u64 addr, size_t length, u16 flags); +static int arm_write(struct hpsb_host *host, int nodeid, int destid, + quadlet_t * data, u64 addr, size_t length, u16 flags); +static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, + u16 flags); +static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, + u16 flags); static struct hpsb_address_ops arm_ops = { - .read = arm_read, - .write = arm_write, - .lock = arm_lock, - .lock64 = arm_lock64, + .read = arm_read, + .write = arm_write, + .lock = arm_lock, + .lock64 = arm_lock64, }; static void queue_complete_cb(struct pending_request *req); -static struct pending_request *__alloc_pending_request(int flags) +static struct pending_request *__alloc_pending_request(gfp_t flags) { - struct pending_request *req; + struct pending_request *req; - req = (struct pending_request *)kmalloc(sizeof(struct pending_request), - flags); - if (req != NULL) { - memset(req, 0, sizeof(struct pending_request)); - INIT_LIST_HEAD(&req->list); - } + req = kzalloc(sizeof(*req), flags); + if (req) + INIT_LIST_HEAD(&req->list); - return req; + return req; } static inline struct pending_request *alloc_pending_request(void) { - return __alloc_pending_request(SLAB_KERNEL); + return __alloc_pending_request(SLAB_KERNEL); } static void free_pending_request(struct pending_request *req) { - if (req->ibs) { - if (atomic_dec_and_test(&req->ibs->refcount)) { - atomic_sub(req->ibs->data_size, &iso_buffer_size); - kfree(req->ibs); - } - } else if (req->free_data) { - kfree(req->data); - } - hpsb_free_packet(req->packet); - kfree(req); + if (req->ibs) { + if (atomic_dec_and_test(&req->ibs->refcount)) { + atomic_sub(req->ibs->data_size, &iso_buffer_size); + kfree(req->ibs); + } + } else if (req->free_data) { + kfree(req->data); + } + hpsb_free_packet(req->packet); + kfree(req); } /* fi->reqlists_lock must be taken */ @@ -134,494 +133,579 @@ static void __queue_complete_req(struct pending_request *req) { struct file_info *fi = req->file_info; list_del(&req->list); - list_add_tail(&req->list, &fi->req_complete); + list_add_tail(&req->list, &fi->req_complete); up(&fi->complete_sem); - wake_up_interruptible(&fi->poll_wait_complete); + wake_up_interruptible(&fi->poll_wait_complete); } static void queue_complete_req(struct pending_request *req) { - unsigned long flags; - struct file_info *fi = req->file_info; + unsigned long flags; + struct file_info *fi = req->file_info; - spin_lock_irqsave(&fi->reqlists_lock, flags); + spin_lock_irqsave(&fi->reqlists_lock, flags); __queue_complete_req(req); - spin_unlock_irqrestore(&fi->reqlists_lock, flags); + spin_unlock_irqrestore(&fi->reqlists_lock, flags); } static void queue_complete_cb(struct pending_request *req) { - struct hpsb_packet *packet = req->packet; - int rcode = (packet->header[1] >> 12) & 0xf; - - switch (packet->ack_code) { - case ACKX_NONE: - case ACKX_SEND_ERROR: - req->req.error = RAW1394_ERROR_SEND_ERROR; - break; - case ACKX_ABORTED: - req->req.error = RAW1394_ERROR_ABORTED; - break; - case ACKX_TIMEOUT: - req->req.error = RAW1394_ERROR_TIMEOUT; - break; - default: - req->req.error = (packet->ack_code << 16) | rcode; - break; - } - - if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) { - req->req.length = 0; - } - - if ((req->req.type == RAW1394_REQ_ASYNC_READ) || + struct hpsb_packet *packet = req->packet; + int rcode = (packet->header[1] >> 12) & 0xf; + + switch (packet->ack_code) { + case ACKX_NONE: + case ACKX_SEND_ERROR: + req->req.error = RAW1394_ERROR_SEND_ERROR; + break; + case ACKX_ABORTED: + req->req.error = RAW1394_ERROR_ABORTED; + break; + case ACKX_TIMEOUT: + req->req.error = RAW1394_ERROR_TIMEOUT; + break; + default: + req->req.error = (packet->ack_code << 16) | rcode; + break; + } + + if (!((packet->ack_code == ACK_PENDING) && (rcode == RCODE_COMPLETE))) { + req->req.length = 0; + } + + if ((req->req.type == RAW1394_REQ_ASYNC_READ) || (req->req.type == RAW1394_REQ_ASYNC_WRITE) || (req->req.type == RAW1394_REQ_ASYNC_STREAM) || (req->req.type == RAW1394_REQ_LOCK) || (req->req.type == RAW1394_REQ_LOCK64)) - hpsb_free_tlabel(packet); + hpsb_free_tlabel(packet); - queue_complete_req(req); + queue_complete_req(req); } - static void add_host(struct hpsb_host *host) { - struct host_info *hi; - unsigned long flags; + struct host_info *hi; + unsigned long flags; - hi = (struct host_info *)kmalloc(sizeof(struct host_info), GFP_KERNEL); + hi = kmalloc(sizeof(*hi), GFP_KERNEL); - if (hi != NULL) { - INIT_LIST_HEAD(&hi->list); - hi->host = host; - INIT_LIST_HEAD(&hi->file_info_list); + if (hi) { + INIT_LIST_HEAD(&hi->list); + hi->host = host; + INIT_LIST_HEAD(&hi->file_info_list); - spin_lock_irqsave(&host_info_lock, flags); - list_add_tail(&hi->list, &host_info_list); - host_count++; - spin_unlock_irqrestore(&host_info_lock, flags); - } + spin_lock_irqsave(&host_info_lock, flags); + list_add_tail(&hi->list, &host_info_list); + host_count++; + spin_unlock_irqrestore(&host_info_lock, flags); + } - atomic_inc(&internal_generation); + atomic_inc(&internal_generation); } - static struct host_info *find_host_info(struct hpsb_host *host) { - struct host_info *hi; + struct host_info *hi; - list_for_each_entry(hi, &host_info_list, list) - if (hi->host == host) - return hi; + list_for_each_entry(hi, &host_info_list, list) + if (hi->host == host) + return hi; - return NULL; + return NULL; } static void remove_host(struct hpsb_host *host) { - struct host_info *hi; - unsigned long flags; - - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(host); - - if (hi != NULL) { - list_del(&hi->list); - host_count--; - /* - FIXME: address ranges should be removed - and fileinfo states should be initialized - (including setting generation to - internal-generation ...) - */ - } - spin_unlock_irqrestore(&host_info_lock, flags); - - if (hi == NULL) { - printk(KERN_ERR "raw1394: attempt to remove unknown host " - "0x%p\n", host); - return; - } - - kfree(hi); - - atomic_inc(&internal_generation); + struct host_info *hi; + unsigned long flags; + + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(host); + + if (hi != NULL) { + list_del(&hi->list); + host_count--; + /* + FIXME: address ranges should be removed + and fileinfo states should be initialized + (including setting generation to + internal-generation ...) + */ + } + spin_unlock_irqrestore(&host_info_lock, flags); + + if (hi == NULL) { + printk(KERN_ERR "raw1394: attempt to remove unknown host " + "0x%p\n", host); + return; + } + + kfree(hi); + + atomic_inc(&internal_generation); } static void host_reset(struct hpsb_host *host) { - unsigned long flags; - struct host_info *hi; - struct file_info *fi; - struct pending_request *req; - - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(host); - - if (hi != NULL) { - list_for_each_entry(fi, &hi->file_info_list, list) { - if (fi->notification == RAW1394_NOTIFY_ON) { - req = __alloc_pending_request(SLAB_ATOMIC); - - if (req != NULL) { - req->file_info = fi; - req->req.type = RAW1394_REQ_BUS_RESET; - req->req.generation = get_hpsb_generation(host); - req->req.misc = (host->node_id << 16) - | host->node_count; - if (fi->protocol_version > 3) { - req->req.misc |= (NODEID_TO_NODE(host->irm_id) - << 8); - } - - queue_complete_req(req); - } - } - } - } - spin_unlock_irqrestore(&host_info_lock, flags); + unsigned long flags; + struct host_info *hi; + struct file_info *fi; + struct pending_request *req; + + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(host); + + if (hi != NULL) { + list_for_each_entry(fi, &hi->file_info_list, list) { + if (fi->notification == RAW1394_NOTIFY_ON) { + req = __alloc_pending_request(SLAB_ATOMIC); + + if (req != NULL) { + req->file_info = fi; + req->req.type = RAW1394_REQ_BUS_RESET; + req->req.generation = + get_hpsb_generation(host); + req->req.misc = (host->node_id << 16) + | host->node_count; + if (fi->protocol_version > 3) { + req->req.misc |= + (NODEID_TO_NODE + (host->irm_id) + << 8); + } + + queue_complete_req(req); + } + } + } + } + spin_unlock_irqrestore(&host_info_lock, flags); } -static void iso_receive(struct hpsb_host *host, int channel, quadlet_t *data, - size_t length) +static void iso_receive(struct hpsb_host *host, int channel, quadlet_t * data, + size_t length) { - unsigned long flags; - struct host_info *hi; - struct file_info *fi; - struct pending_request *req, *req_next; - struct iso_block_store *ibs = NULL; - LIST_HEAD(reqs); - - if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) { - HPSB_INFO("dropped iso packet"); - return; - } - - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(host); - - if (hi != NULL) { + unsigned long flags; + struct host_info *hi; + struct file_info *fi; + struct pending_request *req, *req_next; + struct iso_block_store *ibs = NULL; + LIST_HEAD(reqs); + + if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) { + HPSB_INFO("dropped iso packet"); + return; + } + + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(host); + + if (hi != NULL) { list_for_each_entry(fi, &hi->file_info_list, list) { - if (!(fi->listen_channels & (1ULL << channel))) - continue; - - req = __alloc_pending_request(SLAB_ATOMIC); - if (!req) break; - - if (!ibs) { - ibs = kmalloc(sizeof(struct iso_block_store) - + length, SLAB_ATOMIC); - if (!ibs) { - kfree(req); - break; - } - - atomic_add(length, &iso_buffer_size); - atomic_set(&ibs->refcount, 0); - ibs->data_size = length; - memcpy(ibs->data, data, length); - } - - atomic_inc(&ibs->refcount); - - req->file_info = fi; - req->ibs = ibs; - req->data = ibs->data; - req->req.type = RAW1394_REQ_ISO_RECEIVE; - req->req.generation = get_hpsb_generation(host); - req->req.misc = 0; - req->req.recvb = ptr2int(fi->iso_buffer); - req->req.length = min(length, fi->iso_buffer_length); - - list_add_tail(&req->list, &reqs); - } - } - spin_unlock_irqrestore(&host_info_lock, flags); + if (!(fi->listen_channels & (1ULL << channel))) + continue; + + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) + break; + + if (!ibs) { + ibs = kmalloc(sizeof(*ibs) + length, + SLAB_ATOMIC); + if (!ibs) { + kfree(req); + break; + } + + atomic_add(length, &iso_buffer_size); + atomic_set(&ibs->refcount, 0); + ibs->data_size = length; + memcpy(ibs->data, data, length); + } + + atomic_inc(&ibs->refcount); + + req->file_info = fi; + req->ibs = ibs; + req->data = ibs->data; + req->req.type = RAW1394_REQ_ISO_RECEIVE; + req->req.generation = get_hpsb_generation(host); + req->req.misc = 0; + req->req.recvb = ptr2int(fi->iso_buffer); + req->req.length = min(length, fi->iso_buffer_length); + + list_add_tail(&req->list, &reqs); + } + } + spin_unlock_irqrestore(&host_info_lock, flags); list_for_each_entry_safe(req, req_next, &reqs, list) - queue_complete_req(req); + queue_complete_req(req); } static void fcp_request(struct hpsb_host *host, int nodeid, int direction, - int cts, u8 *data, size_t length) + int cts, u8 * data, size_t length) { - unsigned long flags; - struct host_info *hi; - struct file_info *fi; - struct pending_request *req, *req_next; - struct iso_block_store *ibs = NULL; - LIST_HEAD(reqs); - - if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) { - HPSB_INFO("dropped fcp request"); - return; - } - - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(host); - - if (hi != NULL) { + unsigned long flags; + struct host_info *hi; + struct file_info *fi; + struct pending_request *req, *req_next; + struct iso_block_store *ibs = NULL; + LIST_HEAD(reqs); + + if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) { + HPSB_INFO("dropped fcp request"); + return; + } + + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(host); + + if (hi != NULL) { list_for_each_entry(fi, &hi->file_info_list, list) { - if (!fi->fcp_buffer) - continue; - - req = __alloc_pending_request(SLAB_ATOMIC); - if (!req) break; - - if (!ibs) { - ibs = kmalloc(sizeof(struct iso_block_store) - + length, SLAB_ATOMIC); - if (!ibs) { - kfree(req); - break; - } - - atomic_add(length, &iso_buffer_size); - atomic_set(&ibs->refcount, 0); - ibs->data_size = length; - memcpy(ibs->data, data, length); - } - - atomic_inc(&ibs->refcount); - - req->file_info = fi; - req->ibs = ibs; - req->data = ibs->data; - req->req.type = RAW1394_REQ_FCP_REQUEST; - req->req.generation = get_hpsb_generation(host); - req->req.misc = nodeid | (direction << 16); - req->req.recvb = ptr2int(fi->fcp_buffer); - req->req.length = length; - - list_add_tail(&req->list, &reqs); - } - } - spin_unlock_irqrestore(&host_info_lock, flags); + if (!fi->fcp_buffer) + continue; + + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) + break; + + if (!ibs) { + ibs = kmalloc(sizeof(*ibs) + length, + SLAB_ATOMIC); + if (!ibs) { + kfree(req); + break; + } + + atomic_add(length, &iso_buffer_size); + atomic_set(&ibs->refcount, 0); + ibs->data_size = length; + memcpy(ibs->data, data, length); + } + + atomic_inc(&ibs->refcount); + + req->file_info = fi; + req->ibs = ibs; + req->data = ibs->data; + req->req.type = RAW1394_REQ_FCP_REQUEST; + req->req.generation = get_hpsb_generation(host); + req->req.misc = nodeid | (direction << 16); + req->req.recvb = ptr2int(fi->fcp_buffer); + req->req.length = length; + + list_add_tail(&req->list, &reqs); + } + } + spin_unlock_irqrestore(&host_info_lock, flags); list_for_each_entry_safe(req, req_next, &reqs, list) - queue_complete_req(req); + queue_complete_req(req); } +#ifdef CONFIG_COMPAT +struct compat_raw1394_req { + __u32 type; + __s32 error; + __u32 misc; + + __u32 generation; + __u32 length; + + __u64 address; + + __u64 tag; + + __u64 sendb; + __u64 recvb; +} __attribute__((packed)); -static ssize_t raw1394_read(struct file *file, char __user *buffer, size_t count, - loff_t *offset_is_ignored) +static const char __user *raw1394_compat_write(const char __user *buf) { - struct file_info *fi = (struct file_info *)file->private_data; - struct list_head *lh; - struct pending_request *req; - - if (count != sizeof(struct raw1394_request)) { - return -EINVAL; - } - - if (!access_ok(VERIFY_WRITE, buffer, count)) { - return -EFAULT; - } - - if (file->f_flags & O_NONBLOCK) { - if (down_trylock(&fi->complete_sem)) { - return -EAGAIN; - } - } else { - if (down_interruptible(&fi->complete_sem)) { - return -ERESTARTSYS; - } - } - - spin_lock_irq(&fi->reqlists_lock); - lh = fi->req_complete.next; - list_del(lh); - spin_unlock_irq(&fi->reqlists_lock); - - req = list_entry(lh, struct pending_request, list); - - if (req->req.length) { - if (copy_to_user(int2ptr(req->req.recvb), req->data, - req->req.length)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - } - } - __copy_to_user(buffer, &req->req, sizeof(req->req)); - - free_pending_request(req); - return sizeof(struct raw1394_request); + struct compat_raw1394_req __user *cr = (typeof(cr)) buf; + struct raw1394_request __user *r; + r = compat_alloc_user_space(sizeof(struct raw1394_request)); + +#define C(x) __copy_in_user(&r->x, &cr->x, sizeof(r->x)) + + if (copy_in_user(r, cr, sizeof(struct compat_raw1394_req)) || + C(address) || + C(tag) || + C(sendb) || + C(recvb)) + return ERR_PTR(-EFAULT); + return (const char __user *)r; } +#undef C + +#define P(x) __put_user(r->x, &cr->x) + +static int +raw1394_compat_read(const char __user *buf, struct raw1394_request *r) +{ + struct compat_raw1394_req __user *cr = (typeof(cr)) r; + if (!access_ok(VERIFY_WRITE,cr,sizeof(struct compat_raw1394_req)) || + P(type) || + P(error) || + P(misc) || + P(generation) || + P(length) || + P(address) || + P(tag) || + P(sendb) || + P(recvb)) + return -EFAULT; + return sizeof(struct compat_raw1394_req); +} +#undef P + +#endif + + +static ssize_t raw1394_read(struct file *file, char __user * buffer, + size_t count, loff_t * offset_is_ignored) +{ + unsigned long flags; + struct file_info *fi = (struct file_info *)file->private_data; + struct list_head *lh; + struct pending_request *req; + ssize_t ret; + +#ifdef CONFIG_COMPAT + if (count == sizeof(struct compat_raw1394_req)) { + /* ok */ + } else +#endif + if (count != sizeof(struct raw1394_request)) { + return -EINVAL; + } + + if (!access_ok(VERIFY_WRITE, buffer, count)) { + return -EFAULT; + } + + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&fi->complete_sem)) { + return -EAGAIN; + } + } else { + if (down_interruptible(&fi->complete_sem)) { + return -ERESTARTSYS; + } + } + + spin_lock_irqsave(&fi->reqlists_lock, flags); + lh = fi->req_complete.next; + list_del(lh); + spin_unlock_irqrestore(&fi->reqlists_lock, flags); + + req = list_entry(lh, struct pending_request, list); + 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 sizeof(struct raw1394_request); + 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 sizeof(struct raw1394_request); } static int state_initialized(struct file_info *fi, struct pending_request *req) { - 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 sizeof(struct raw1394_request); - } - - switch (req->req.type) { - case RAW1394_REQ_LIST_CARDS: - spin_lock_irq(&host_info_lock); - khl = kmalloc(sizeof(struct raw1394_khost_list) * host_count, - SLAB_ATOMIC); - - if (khl != NULL) { - 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_irq(&host_info_lock); - - if (khl != NULL) { - 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_irq(&host_info_lock); - if (req->req.misc < host_count) { + 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 sizeof(struct raw1394_request); + } + + switch (req->req.type) { + case RAW1394_REQ_LIST_CARDS: + spin_lock_irqsave(&host_info_lock, flags); + khl = kmalloc(sizeof(*khl) * host_count, SLAB_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) { list_for_each_entry(hi, &host_info_list, list) { if (!req->req.misc--) break; } - get_device(&hi->host->device); // XXX Need to handle failure case - list_add_tail(&fi->list, &hi->file_info_list); - 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; - } - } else { - req->req.error = RAW1394_ERROR_INVALID_ARG; - } - spin_unlock_irq(&host_info_lock); - - req->req.length = 0; - break; - - default: - req->req.error = RAW1394_ERROR_STATE_ORDER; - req->req.length = 0; - break; - } - - queue_complete_req(req); - return sizeof(struct raw1394_request); + get_device(&hi->host->device); // XXX Need to handle failure case + list_add_tail(&fi->list, &hi->file_info_list); + 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; + } + } else { + req->req.error = RAW1394_ERROR_INVALID_ARG; + } + 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 sizeof(struct raw1394_request); } static void handle_iso_listen(struct file_info *fi, struct pending_request *req) { - int channel = req->req.misc; - - spin_lock_irq(&host_info_lock); - if ((channel > 63) || (channel < -64)) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - } else if (channel >= 0) { - /* allocate channel req.misc */ - if (fi->listen_channels & (1ULL << channel)) { - req->req.error = RAW1394_ERROR_ALREADY; - } else { - if (hpsb_listen_channel(&raw1394_highlevel, fi->host, channel)) { + int channel = req->req.misc; + + if ((channel > 63) || (channel < -64)) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + } else if (channel >= 0) { + /* allocate channel req.misc */ + if (fi->listen_channels & (1ULL << channel)) { + req->req.error = RAW1394_ERROR_ALREADY; + } else { + if (hpsb_listen_channel + (&raw1394_highlevel, fi->host, channel)) { req->req.error = RAW1394_ERROR_ALREADY; } else { fi->listen_channels |= 1ULL << channel; fi->iso_buffer = int2ptr(req->req.recvb); fi->iso_buffer_length = req->req.length; } - } - } else { - /* deallocate channel (one's complement neg) req.misc */ - channel = ~channel; - - if (fi->listen_channels & (1ULL << channel)) { - hpsb_unlisten_channel(&raw1394_highlevel, fi->host, channel); - fi->listen_channels &= ~(1ULL << channel); - } else { - req->req.error = RAW1394_ERROR_INVALID_ARG; - } - } - - req->req.length = 0; - queue_complete_req(req); - spin_unlock_irq(&host_info_lock); + } + } else { + /* deallocate channel (one's complement neg) req.misc */ + channel = ~channel; + + if (fi->listen_channels & (1ULL << channel)) { + hpsb_unlisten_channel(&raw1394_highlevel, fi->host, + channel); + fi->listen_channels &= ~(1ULL << channel); + } else { + req->req.error = RAW1394_ERROR_INVALID_ARG; + } + } + + req->req.length = 0; + queue_complete_req(req); } 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); -} + 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) + struct pending_request *req, int node) { - struct hpsb_packet *packet = NULL; - u64 addr = req->req.address & 0xffffffffffffULL; + unsigned long flags; + struct hpsb_packet *packet = NULL; + u64 addr = req->req.address & 0xffffffffffffULL; - switch (req->req.type) { - case RAW1394_REQ_ASYNC_READ: + switch (req->req.type) { + case RAW1394_REQ_ASYNC_READ: DBGMSG("read_request called"); - packet = hpsb_make_readpacket(fi->host, node, addr, req->req.length); + packet = + hpsb_make_readpacket(fi->host, node, addr, req->req.length); if (!packet) return -ENOMEM; @@ -631,7 +715,7 @@ static int handle_async_request(struct file_info *fi, else req->data = packet->data; - break; + break; case RAW1394_REQ_ASYNC_WRITE: DBGMSG("write_request called"); @@ -642,1105 +726,1213 @@ static int handle_async_request(struct file_info *fi, return -ENOMEM; if (req->req.length == 4) { - if (copy_from_user(&packet->header[3], int2ptr(req->req.sendb), - req->req.length)) + 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)) + if (copy_from_user + (packet->data, int2ptr(req->req.sendb), + req->req.length)) req->req.error = RAW1394_ERROR_MEMFAULT; } req->req.length = 0; - break; + 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); + 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.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 sizeof(struct raw1394_request); - } - - hpsb_set_packet_complete_task(packet, (void(*)(void*))queue_complete_cb, req); - - spin_lock_irq(&fi->reqlists_lock); - list_add_tail(&req->list, &fi->req_pending); - spin_unlock_irq(&fi->reqlists_lock); + 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 sizeof(struct raw1394_request); + } + + 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 sizeof(struct raw1394_request); + 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 sizeof(struct raw1394_request); } static int handle_iso_send(struct file_info *fi, struct pending_request *req, - int channel) + int channel) { - struct hpsb_packet *packet; + unsigned long flags; + struct hpsb_packet *packet; packet = hpsb_make_isopacket(fi->host, req->req.length, channel & 0x3f, - (req->req.misc >> 16) & 0x3, req->req.misc & 0xf); + (req->req.misc >> 16) & 0x3, + req->req.misc & 0xf); if (!packet) return -ENOMEM; - packet->speed_code = req->req.address & 0x3; + packet->speed_code = req->req.address & 0x3; req->packet = packet; - if (copy_from_user(packet->data, int2ptr(req->req.sendb), - req->req.length)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - req->req.length = 0; - queue_complete_req(req); - return sizeof(struct raw1394_request); - } + if (copy_from_user(packet->data, int2ptr(req->req.sendb), + req->req.length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } - req->req.length = 0; - hpsb_set_packet_complete_task(packet, (void (*)(void*))queue_complete_req, req); + req->req.length = 0; + hpsb_set_packet_complete_task(packet, + (void (*)(void *))queue_complete_req, + req); - spin_lock_irq(&fi->reqlists_lock); - list_add_tail(&req->list, &fi->req_pending); - spin_unlock_irq(&fi->reqlists_lock); + 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); - } + if (hpsb_send_packet(packet) < 0) { + req->req.error = RAW1394_ERROR_SEND_ERROR; + queue_complete_req(req); + } - return sizeof(struct raw1394_request); + return sizeof(struct raw1394_request); } static int handle_async_send(struct file_info *fi, struct pending_request *req) { - struct hpsb_packet *packet; - int header_length = req->req.misc & 0xffff; - int expect_response = req->req.misc >> 16; - - if ((header_length > req->req.length) || - (header_length < 12)) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - req->req.length = 0; - queue_complete_req(req); - return sizeof(struct raw1394_request); - } - - packet = hpsb_alloc_packet(req->req.length-header_length); - 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 sizeof(struct raw1394_request); - } - - if (copy_from_user(packet->data, int2ptr(req->req.sendb) + header_length, - packet->data_size)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - req->req.length = 0; - queue_complete_req(req); - return sizeof(struct raw1394_request); - } - - 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=req->req.length-header_length; - - req->req.length = 0; - hpsb_set_packet_complete_task(packet, (void(*)(void*))queue_complete_cb, req); - - spin_lock_irq(&fi->reqlists_lock); - list_add_tail(&req->list, &fi->req_pending); - spin_unlock_irq(&fi->reqlists_lock); - - /* 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 sizeof(struct raw1394_request); + unsigned long flags; + struct hpsb_packet *packet; + int header_length = req->req.misc & 0xffff; + int expect_response = req->req.misc >> 16; + + if ((header_length > req->req.length) || (header_length < 12)) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } + + packet = hpsb_alloc_packet(req->req.length - header_length); + 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 sizeof(struct raw1394_request); + } + + if (copy_from_user + (packet->data, int2ptr(req->req.sendb) + header_length, + packet->data_size)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } + + 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 = req->req.length - header_length; + + 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 sizeof(struct raw1394_request); } -static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer, - u64 addr, size_t length, u16 flags) +static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer, + u64 addr, size_t length, u16 flags) { - 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(&host_info_lock); - 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(&host_info_lock); - 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,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), - length); - DBGMSG("arm_read -> (rcode_complete)"); - rcode = RCODE_COMPLETE; - } - } else { - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - DBGMSG("arm_read -> rcode_type_error (access denied)"); - } - } - if (arm_addr->notification_options & ARM_READ) { - DBGMSG("arm_read -> entering notification-section"); - req = __alloc_pending_request(SLAB_ATOMIC); - if (!req) { - DBGMSG("arm_read -> rcode_conflict_error"); - spin_unlock(&host_info_lock); - return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - if (rcode == RCODE_COMPLETE) { - size = sizeof(struct arm_request)+sizeof(struct arm_response) + - length * sizeof(byte_t) + - sizeof (struct arm_request_response); - } else { - size = sizeof(struct arm_request)+sizeof(struct arm_response) + - sizeof (struct arm_request_response); - } - req->data = kmalloc(size, SLAB_ATOMIC); - if (!(req->data)) { - free_pending_request(req); - DBGMSG("arm_read -> rcode_conflict_error"); - spin_unlock(&host_info_lock); - return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - req->free_data=1; - req->file_info = fi; - req->req.type = RAW1394_REQ_ARM; - req->req.generation = get_hpsb_generation(host); - req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF)); - req->req.tag = arm_addr->arm_tag; - req->req.recvb = arm_addr->recvb; - req->req.length = size; - arm_req_resp = (struct arm_request_response *) (req->data); - arm_req = (struct arm_request *) ((byte_t *)(req->data) + - (sizeof (struct arm_request_response))); - arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + - (sizeof(struct arm_request))); - arm_req->buffer = NULL; - arm_resp->buffer = NULL; - if (rcode == RCODE_COMPLETE) { - byte_t *buf = (byte_t *)arm_resp + sizeof(struct arm_response); - memcpy (buf, - (arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), - length); - arm_resp->buffer = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response) + - sizeof (struct arm_request) + - sizeof (struct arm_response)); - } - arm_resp->buffer_length = (rcode == RCODE_COMPLETE) ? length : 0; - arm_resp->response_code = rcode; - arm_req->buffer_length = 0; - arm_req->generation = req->req.generation; - arm_req->extended_transaction_code = 0; - arm_req->destination_offset = addr; - arm_req->source_nodeid = nodeid; - arm_req->destination_nodeid = host->node_id; - arm_req->tlabel = (flags >> 10) & 0x3f; - arm_req->tcode = (flags >> 4) & 0x0f; - arm_req_resp->request = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response)); - arm_req_resp->response = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response) + - sizeof (struct arm_request)); - queue_complete_req(req); - } - spin_unlock(&host_info_lock); - return(rcode); + 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, + (arm_addr->addr_space_buffer) + (addr - + (arm_addr-> + start)), + length); + DBGMSG("arm_read -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_read -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_READ) { + DBGMSG("arm_read -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + DBGMSG("arm_read -> rcode_conflict_error"); + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + if (rcode == RCODE_COMPLETE) { + size = + sizeof(struct arm_request) + + sizeof(struct arm_response) + + length * sizeof(byte_t) + + sizeof(struct arm_request_response); + } else { + size = + sizeof(struct arm_request) + + sizeof(struct arm_response) + + sizeof(struct arm_request_response); + } + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + DBGMSG("arm_read -> rcode_conflict_error"); + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data = 1; + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = + (((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req_resp = (struct arm_request_response *)(req->data); + arm_req = (struct arm_request *)((byte_t *) (req->data) + + (sizeof + (struct + arm_request_response))); + arm_resp = + (struct arm_response *)((byte_t *) (arm_req) + + (sizeof(struct arm_request))); + arm_req->buffer = NULL; + arm_resp->buffer = NULL; + if (rcode == RCODE_COMPLETE) { + byte_t *buf = + (byte_t *) arm_resp + sizeof(struct arm_response); + memcpy(buf, + (arm_addr->addr_space_buffer) + (addr - + (arm_addr-> + start)), + length); + arm_resp->buffer = + int2ptr((arm_addr->recvb) + + sizeof(struct arm_request_response) + + sizeof(struct arm_request) + + sizeof(struct arm_response)); + } + arm_resp->buffer_length = + (rcode == RCODE_COMPLETE) ? length : 0; + arm_resp->response_code = rcode; + arm_req->buffer_length = 0; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = 0; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = host->node_id; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof(struct + arm_request_response)); + arm_req_resp->response = + int2ptr((arm_addr->recvb) + + sizeof(struct arm_request_response) + + sizeof(struct arm_request)); + queue_complete_req(req); + } + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (rcode); } -static int arm_write (struct hpsb_host *host, int nodeid, int destid, - quadlet_t *data, u64 addr, size_t length, u16 flags) +static int arm_write(struct hpsb_host *host, int nodeid, int destid, + quadlet_t * data, u64 addr, size_t length, u16 flags) { - 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, length_conflict=0; - struct arm_request_response *arm_req_resp = NULL; - - DBGMSG("arm_write called by node: %X" - "addr: %4.4x %8.8x length: %Zu", nodeid, - (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), - length); - spin_lock(&host_info_lock); - 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_write FAILED addr_entry not found" - " -> rcode_address_error\n"); - spin_unlock(&host_info_lock); - return (RCODE_ADDRESS_ERROR); - } else { - DBGMSG("arm_write addr_entry FOUND"); - } - if (arm_addr->rec_length < length) { - DBGMSG("arm_write blocklength too big -> rcode_data_error"); - length_conflict = 1; - rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */ - } - if (rcode == -1) { - if (arm_addr->access_rights & ARM_WRITE) { - if (!(arm_addr->client_transactions & ARM_WRITE)) { - memcpy((arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), - data, length); - DBGMSG("arm_write -> (rcode_complete)"); - rcode = RCODE_COMPLETE; - } - } else { - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - DBGMSG("arm_write -> rcode_type_error (access denied)"); - } - } - if (arm_addr->notification_options & ARM_WRITE) { - DBGMSG("arm_write -> entering notification-section"); - req = __alloc_pending_request(SLAB_ATOMIC); - if (!req) { - DBGMSG("arm_write -> rcode_conflict_error"); - spin_unlock(&host_info_lock); - return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request my be retried */ - } - size = sizeof(struct arm_request)+sizeof(struct arm_response) + - (length) * sizeof(byte_t) + - sizeof (struct arm_request_response); - req->data = kmalloc(size, SLAB_ATOMIC); - if (!(req->data)) { - free_pending_request(req); - DBGMSG("arm_write -> rcode_conflict_error"); - spin_unlock(&host_info_lock); - return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - req->free_data=1; - req->file_info = fi; - req->req.type = RAW1394_REQ_ARM; - req->req.generation = get_hpsb_generation(host); - req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF)); - req->req.tag = arm_addr->arm_tag; - req->req.recvb = arm_addr->recvb; - req->req.length = size; - arm_req_resp = (struct arm_request_response *) (req->data); - arm_req = (struct arm_request *) ((byte_t *)(req->data) + - (sizeof (struct arm_request_response))); - arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + - (sizeof(struct arm_request))); - arm_resp->buffer = NULL; - memcpy ((byte_t *)arm_resp + sizeof(struct arm_response), - data, length); - arm_req->buffer = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response) + - sizeof (struct arm_request) + - sizeof (struct arm_response)); - arm_req->buffer_length = length; - arm_req->generation = req->req.generation; - arm_req->extended_transaction_code = 0; - arm_req->destination_offset = addr; - arm_req->source_nodeid = nodeid; - arm_req->destination_nodeid = destid; - arm_req->tlabel = (flags >> 10) & 0x3f; - arm_req->tcode = (flags >> 4) & 0x0f; - arm_resp->buffer_length = 0; - arm_resp->response_code = rcode; - arm_req_resp->request = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response)); - arm_req_resp->response = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response) + - sizeof (struct arm_request)); - queue_complete_req(req); - } - spin_unlock(&host_info_lock); - return(rcode); + 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, length_conflict = 0; + struct arm_request_response *arm_req_resp = NULL; + + DBGMSG("arm_write 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_write FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_write addr_entry FOUND"); + } + if (arm_addr->rec_length < length) { + DBGMSG("arm_write blocklength too big -> rcode_data_error"); + length_conflict = 1; + rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */ + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_WRITE) { + if (!(arm_addr->client_transactions & ARM_WRITE)) { + memcpy((arm_addr->addr_space_buffer) + + (addr - (arm_addr->start)), data, + length); + DBGMSG("arm_write -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_write -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_WRITE) { + DBGMSG("arm_write -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + DBGMSG("arm_write -> rcode_conflict_error"); + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request my be retried */ + } + size = + sizeof(struct arm_request) + sizeof(struct arm_response) + + (length) * sizeof(byte_t) + + sizeof(struct arm_request_response); + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + DBGMSG("arm_write -> rcode_conflict_error"); + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data = 1; + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = + (((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req_resp = (struct arm_request_response *)(req->data); + arm_req = (struct arm_request *)((byte_t *) (req->data) + + (sizeof + (struct + arm_request_response))); + arm_resp = + (struct arm_response *)((byte_t *) (arm_req) + + (sizeof(struct arm_request))); + arm_resp->buffer = NULL; + memcpy((byte_t *) arm_resp + sizeof(struct arm_response), + data, length); + arm_req->buffer = int2ptr((arm_addr->recvb) + + sizeof(struct arm_request_response) + + sizeof(struct arm_request) + + sizeof(struct arm_response)); + arm_req->buffer_length = length; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = 0; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = destid; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_resp->buffer_length = 0; + arm_resp->response_code = rcode; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof(struct + arm_request_response)); + arm_req_resp->response = + int2ptr((arm_addr->recvb) + + sizeof(struct arm_request_response) + + sizeof(struct arm_request)); + queue_complete_req(req); + } + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (rcode); } -static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store, - u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags) +static int arm_lock(struct hpsb_host *host, int nodeid, quadlet_t * store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, + u16 flags) { - 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; - quadlet_t old, new; - struct arm_request_response *arm_req_resp = NULL; - - if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || - ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { - DBGMSG("arm_lock called by node: %X " - "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X", - nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), - ext_tcode & 0xFF , be32_to_cpu(data)); - } else { - DBGMSG("arm_lock called by node: %X " - "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X", - nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), - ext_tcode & 0xFF , be32_to_cpu(data), be32_to_cpu(arg)); - } - spin_lock(&host_info_lock); - 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+sizeof(*store)))) { - found = 1; - break; - } - entry = entry->next; - } - if (found) { - break; - } - } - } - rcode = -1; - if (!found) { - printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found" - " -> rcode_address_error\n"); - spin_unlock(&host_info_lock); - return (RCODE_ADDRESS_ERROR); - } else { - DBGMSG("arm_lock addr_entry FOUND"); - } - if (rcode == -1) { - if (arm_addr->access_rights & ARM_LOCK) { - if (!(arm_addr->client_transactions & ARM_LOCK)) { - memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), - sizeof(old)); - switch (ext_tcode) { - case (EXTCODE_MASK_SWAP): - new = data | (old & ~arg); - break; - case (EXTCODE_COMPARE_SWAP): - if (old == arg) { - new = data; - } else { - new = old; - } - break; - case (EXTCODE_FETCH_ADD): - new = cpu_to_be32(be32_to_cpu(data) + be32_to_cpu(old)); - break; - case (EXTCODE_LITTLE_ADD): - new = cpu_to_le32(le32_to_cpu(data) + le32_to_cpu(old)); - break; - case (EXTCODE_BOUNDED_ADD): - if (old != arg) { - new = cpu_to_be32(be32_to_cpu(data) + - be32_to_cpu(old)); - } else { - new = old; - } - break; - case (EXTCODE_WRAP_ADD): - if (old != arg) { - new = cpu_to_be32(be32_to_cpu(data) + - be32_to_cpu(old)); - } else { - new = data; - } - break; - default: - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - printk(KERN_ERR "raw1394: arm_lock FAILED " - "ext_tcode not allowed -> rcode_type_error\n"); - break; - } /*switch*/ - if (rcode == -1) { - DBGMSG("arm_lock -> (rcode_complete)"); - rcode = RCODE_COMPLETE; - memcpy (store, &old, sizeof(*store)); - memcpy ((arm_addr->addr_space_buffer)+ - (addr-(arm_addr->start)), - &new, sizeof(*store)); - } - } - } else { - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - DBGMSG("arm_lock -> rcode_type_error (access denied)"); - } - } - if (arm_addr->notification_options & ARM_LOCK) { + 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; + quadlet_t old, new; + struct arm_request_response *arm_req_resp = NULL; + + if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || + ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { + DBGMSG("arm_lock called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X", + nodeid, (u16) ((addr >> 32) & 0xFFFF), + (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF, + be32_to_cpu(data)); + } else { + DBGMSG("arm_lock called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X", + nodeid, (u16) ((addr >> 32) & 0xFFFF), + (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF, + be32_to_cpu(data), be32_to_cpu(arg)); + } + 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 + sizeof(*store)))) { + found = 1; + break; + } + entry = entry->next; + } + if (found) { + break; + } + } + } + rcode = -1; + if (!found) { + printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_lock addr_entry FOUND"); + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_LOCK) { + if (!(arm_addr->client_transactions & ARM_LOCK)) { + memcpy(&old, + (arm_addr->addr_space_buffer) + (addr - + (arm_addr-> + start)), + sizeof(old)); + switch (ext_tcode) { + case (EXTCODE_MASK_SWAP): + new = data | (old & ~arg); + break; + case (EXTCODE_COMPARE_SWAP): + if (old == arg) { + new = data; + } else { + new = old; + } + break; + case (EXTCODE_FETCH_ADD): + new = + cpu_to_be32(be32_to_cpu(data) + + be32_to_cpu(old)); + break; + case (EXTCODE_LITTLE_ADD): + new = + cpu_to_le32(le32_to_cpu(data) + + le32_to_cpu(old)); + break; + case (EXTCODE_BOUNDED_ADD): + if (old != arg) { + new = + cpu_to_be32(be32_to_cpu + (data) + + be32_to_cpu + (old)); + } else { + new = old; + } + break; + case (EXTCODE_WRAP_ADD): + if (old != arg) { + new = + cpu_to_be32(be32_to_cpu + (data) + + be32_to_cpu + (old)); + } else { + new = data; + } + break; + default: + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + printk(KERN_ERR + "raw1394: arm_lock FAILED " + "ext_tcode not allowed -> rcode_type_error\n"); + break; + } /*switch */ + if (rcode == -1) { + DBGMSG("arm_lock -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + memcpy(store, &old, sizeof(*store)); + memcpy((arm_addr->addr_space_buffer) + + (addr - (arm_addr->start)), + &new, sizeof(*store)); + } + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_lock -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_LOCK) { byte_t *buf1, *buf2; - DBGMSG("arm_lock -> entering notification-section"); - req = __alloc_pending_request(SLAB_ATOMIC); - if (!req) { - DBGMSG("arm_lock -> rcode_conflict_error"); - spin_unlock(&host_info_lock); - return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - size = sizeof(struct arm_request)+sizeof(struct arm_response) + - 3 * sizeof(*store) + - sizeof (struct arm_request_response); /* maximum */ - req->data = kmalloc(size, SLAB_ATOMIC); - if (!(req->data)) { - free_pending_request(req); - DBGMSG("arm_lock -> rcode_conflict_error"); - spin_unlock(&host_info_lock); - return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - req->free_data=1; - arm_req_resp = (struct arm_request_response *) (req->data); - arm_req = (struct arm_request *) ((byte_t *)(req->data) + - (sizeof (struct arm_request_response))); - arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + - (sizeof(struct arm_request))); - buf1 = (byte_t *)arm_resp + sizeof(struct arm_response); + DBGMSG("arm_lock -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + DBGMSG("arm_lock -> rcode_conflict_error"); + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response); /* maximum */ + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + DBGMSG("arm_lock -> rcode_conflict_error"); + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data = 1; + arm_req_resp = (struct arm_request_response *)(req->data); + arm_req = (struct arm_request *)((byte_t *) (req->data) + + (sizeof + (struct + arm_request_response))); + arm_resp = + (struct arm_response *)((byte_t *) (arm_req) + + (sizeof(struct arm_request))); + buf1 = (byte_t *) arm_resp + sizeof(struct arm_response); buf2 = buf1 + 2 * sizeof(*store); - if ((ext_tcode == EXTCODE_FETCH_ADD) || - (ext_tcode == EXTCODE_LITTLE_ADD)) { - arm_req->buffer_length = sizeof(*store); - memcpy (buf1, &data, sizeof(*store)); - - } else { - arm_req->buffer_length = 2 * sizeof(*store); - memcpy (buf1, &arg, sizeof(*store)); - memcpy (buf1 + sizeof(*store), &data, sizeof(*store)); - } - if (rcode == RCODE_COMPLETE) { - arm_resp->buffer_length = sizeof(*store); - memcpy (buf2, &old, sizeof(*store)); - } else { - arm_resp->buffer_length = 0; - } - req->file_info = fi; - req->req.type = RAW1394_REQ_ARM; - req->req.generation = get_hpsb_generation(host); - req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | - (ARM_LOCK & 0xFF)); - req->req.tag = arm_addr->arm_tag; - req->req.recvb = arm_addr->recvb; - req->req.length = size; - arm_req->generation = req->req.generation; - arm_req->extended_transaction_code = ext_tcode; - arm_req->destination_offset = addr; - arm_req->source_nodeid = nodeid; - arm_req->destination_nodeid = host->node_id; - arm_req->tlabel = (flags >> 10) & 0x3f; - arm_req->tcode = (flags >> 4) & 0x0f; - arm_resp->response_code = rcode; - arm_req_resp->request = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response)); - arm_req_resp->response = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response) + - sizeof (struct arm_request)); - arm_req->buffer = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response) + - sizeof (struct arm_request) + - sizeof (struct arm_response)); - arm_resp->buffer = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response) + - sizeof (struct arm_request) + - sizeof (struct arm_response) + - 2* sizeof (*store)); - queue_complete_req(req); - } - spin_unlock(&host_info_lock); - return(rcode); + if ((ext_tcode == EXTCODE_FETCH_ADD) || + (ext_tcode == EXTCODE_LITTLE_ADD)) { + arm_req->buffer_length = sizeof(*store); + memcpy(buf1, &data, sizeof(*store)); + + } else { + arm_req->buffer_length = 2 * sizeof(*store); + memcpy(buf1, &arg, sizeof(*store)); + memcpy(buf1 + sizeof(*store), &data, sizeof(*store)); + } + if (rcode == RCODE_COMPLETE) { + arm_resp->buffer_length = sizeof(*store); + memcpy(buf2, &old, sizeof(*store)); + } else { + arm_resp->buffer_length = 0; + } + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) | + (ARM_LOCK & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = ext_tcode; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = host->node_id; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_resp->response_code = rcode; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof(struct + arm_request_response)); + arm_req_resp->response = + int2ptr((arm_addr->recvb) + + sizeof(struct arm_request_response) + + sizeof(struct arm_request)); + arm_req->buffer = + int2ptr((arm_addr->recvb) + + sizeof(struct arm_request_response) + + sizeof(struct arm_request) + + sizeof(struct arm_response)); + arm_resp->buffer = + int2ptr((arm_addr->recvb) + + sizeof(struct arm_request_response) + + sizeof(struct arm_request) + + sizeof(struct arm_response) + 2 * sizeof(*store)); + queue_complete_req(req); + } + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (rcode); } -static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store, - u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags) +static int arm_lock64(struct hpsb_host *host, int nodeid, octlet_t * store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, + u16 flags) { - 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; - octlet_t old, new; - struct arm_request_response *arm_req_resp = NULL; - - if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || - ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { - DBGMSG("arm_lock64 called by node: %X " - "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ", - nodeid, (u16) ((addr >>32) & 0xFFFF), - (u32) (addr & 0xFFFFFFFF), - ext_tcode & 0xFF , - (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), - (u32) (be64_to_cpu(data) & 0xFFFFFFFF)); - } else { - DBGMSG("arm_lock64 called by node: %X " - "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: " - "%8.8X %8.8X ", - nodeid, (u16) ((addr >>32) & 0xFFFF), - (u32) (addr & 0xFFFFFFFF), - ext_tcode & 0xFF , - (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), - (u32) (be64_to_cpu(data) & 0xFFFFFFFF), - (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF), - (u32) (be64_to_cpu(arg) & 0xFFFFFFFF)); - } - spin_lock(&host_info_lock); - hi = find_host_info(host); /* search addressentry in file_info's for host */ - 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+sizeof(*store)))) { - found = 1; - break; - } - entry = entry->next; - } - if (found) { - break; - } - } - } - rcode = -1; - if (!found) { - printk(KERN_ERR "raw1394: arm_lock64 FAILED addr_entry not found" - " -> rcode_address_error\n"); - spin_unlock(&host_info_lock); - return (RCODE_ADDRESS_ERROR); - } else { - DBGMSG("arm_lock64 addr_entry FOUND"); - } - if (rcode == -1) { - if (arm_addr->access_rights & ARM_LOCK) { - if (!(arm_addr->client_transactions & ARM_LOCK)) { - memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), - sizeof(old)); - switch (ext_tcode) { - case (EXTCODE_MASK_SWAP): - new = data | (old & ~arg); - break; - case (EXTCODE_COMPARE_SWAP): - if (old == arg) { - new = data; - } else { - new = old; - } - break; - case (EXTCODE_FETCH_ADD): - new = cpu_to_be64(be64_to_cpu(data) + be64_to_cpu(old)); - break; - case (EXTCODE_LITTLE_ADD): - new = cpu_to_le64(le64_to_cpu(data) + le64_to_cpu(old)); - break; - case (EXTCODE_BOUNDED_ADD): - if (old != arg) { - new = cpu_to_be64(be64_to_cpu(data) + - be64_to_cpu(old)); - } else { - new = old; - } - break; - case (EXTCODE_WRAP_ADD): - if (old != arg) { - new = cpu_to_be64(be64_to_cpu(data) + - be64_to_cpu(old)); - } else { - new = data; - } - break; - default: - printk(KERN_ERR "raw1394: arm_lock64 FAILED " - "ext_tcode not allowed -> rcode_type_error\n"); - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - break; - } /*switch*/ - if (rcode == -1) { - DBGMSG("arm_lock64 -> (rcode_complete)"); - rcode = RCODE_COMPLETE; - memcpy (store, &old, sizeof(*store)); - memcpy ((arm_addr->addr_space_buffer)+ - (addr-(arm_addr->start)), - &new, sizeof(*store)); - } - } - } else { - rcode = RCODE_TYPE_ERROR; /* function not allowed */ - DBGMSG("arm_lock64 -> rcode_type_error (access denied)"); - } - } - if (arm_addr->notification_options & ARM_LOCK) { + 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; + octlet_t old, new; + struct arm_request_response *arm_req_resp = NULL; + + if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || + ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { + DBGMSG("arm_lock64 called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ", + nodeid, (u16) ((addr >> 32) & 0xFFFF), + (u32) (addr & 0xFFFFFFFF), + ext_tcode & 0xFF, + (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), + (u32) (be64_to_cpu(data) & 0xFFFFFFFF)); + } else { + DBGMSG("arm_lock64 called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: " + "%8.8X %8.8X ", + nodeid, (u16) ((addr >> 32) & 0xFFFF), + (u32) (addr & 0xFFFFFFFF), + ext_tcode & 0xFF, + (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), + (u32) (be64_to_cpu(data) & 0xFFFFFFFF), + (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF), + (u32) (be64_to_cpu(arg) & 0xFFFFFFFF)); + } + spin_lock_irqsave(&host_info_lock, irqflags); + hi = find_host_info(host); /* search addressentry in file_info's for host */ + 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 + sizeof(*store)))) { + found = 1; + break; + } + entry = entry->next; + } + if (found) { + break; + } + } + } + rcode = -1; + if (!found) { + printk(KERN_ERR + "raw1394: arm_lock64 FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_lock64 addr_entry FOUND"); + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_LOCK) { + if (!(arm_addr->client_transactions & ARM_LOCK)) { + memcpy(&old, + (arm_addr->addr_space_buffer) + (addr - + (arm_addr-> + start)), + sizeof(old)); + switch (ext_tcode) { + case (EXTCODE_MASK_SWAP): + new = data | (old & ~arg); + break; + case (EXTCODE_COMPARE_SWAP): + if (old == arg) { + new = data; + } else { + new = old; + } + break; + case (EXTCODE_FETCH_ADD): + new = + cpu_to_be64(be64_to_cpu(data) + + be64_to_cpu(old)); + break; + case (EXTCODE_LITTLE_ADD): + new = + cpu_to_le64(le64_to_cpu(data) + + le64_to_cpu(old)); + break; + case (EXTCODE_BOUNDED_ADD): + if (old != arg) { + new = + cpu_to_be64(be64_to_cpu + (data) + + be64_to_cpu + (old)); + } else { + new = old; + } + break; + case (EXTCODE_WRAP_ADD): + if (old != arg) { + new = + cpu_to_be64(be64_to_cpu + (data) + + be64_to_cpu + (old)); + } else { + new = data; + } + break; + default: + printk(KERN_ERR + "raw1394: arm_lock64 FAILED " + "ext_tcode not allowed -> rcode_type_error\n"); + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + break; + } /*switch */ + if (rcode == -1) { + DBGMSG + ("arm_lock64 -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + memcpy(store, &old, sizeof(*store)); + memcpy((arm_addr->addr_space_buffer) + + (addr - (arm_addr->start)), + &new, sizeof(*store)); + } + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG + ("arm_lock64 -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_LOCK) { byte_t *buf1, *buf2; - DBGMSG("arm_lock64 -> entering notification-section"); - req = __alloc_pending_request(SLAB_ATOMIC); - if (!req) { - spin_unlock(&host_info_lock); - DBGMSG("arm_lock64 -> rcode_conflict_error"); - return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - size = sizeof(struct arm_request)+sizeof(struct arm_response) + - 3 * sizeof(*store) + - sizeof (struct arm_request_response); /* maximum */ - req->data = kmalloc(size, SLAB_ATOMIC); - if (!(req->data)) { - free_pending_request(req); - spin_unlock(&host_info_lock); - DBGMSG("arm_lock64 -> rcode_conflict_error"); - return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. - The request may be retried */ - } - req->free_data=1; - arm_req_resp = (struct arm_request_response *) (req->data); - arm_req = (struct arm_request *) ((byte_t *)(req->data) + - (sizeof (struct arm_request_response))); - arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + - (sizeof(struct arm_request))); - buf1 = (byte_t *)arm_resp + sizeof(struct arm_response); - buf2 = buf1 + 2 * sizeof(*store); - if ((ext_tcode == EXTCODE_FETCH_ADD) || - (ext_tcode == EXTCODE_LITTLE_ADD)) { - arm_req->buffer_length = sizeof(*store); - memcpy (buf1, &data, sizeof(*store)); - - } else { - arm_req->buffer_length = 2 * sizeof(*store); - memcpy (buf1, &arg, sizeof(*store)); - memcpy (buf1 + sizeof(*store), &data, sizeof(*store)); - } - if (rcode == RCODE_COMPLETE) { - arm_resp->buffer_length = sizeof(*store); - memcpy (buf2, &old, sizeof(*store)); - } else { - arm_resp->buffer_length = 0; - } - req->file_info = fi; - req->req.type = RAW1394_REQ_ARM; - req->req.generation = get_hpsb_generation(host); - req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | - (ARM_LOCK & 0xFF)); - req->req.tag = arm_addr->arm_tag; - req->req.recvb = arm_addr->recvb; - req->req.length = size; - arm_req->generation = req->req.generation; - arm_req->extended_transaction_code = ext_tcode; - arm_req->destination_offset = addr; - arm_req->source_nodeid = nodeid; - arm_req->destination_nodeid = host->node_id; - arm_req->tlabel = (flags >> 10) & 0x3f; - arm_req->tcode = (flags >> 4) & 0x0f; - arm_resp->response_code = rcode; - arm_req_resp->request = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response)); - arm_req_resp->response = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response) + - sizeof (struct arm_request)); - arm_req->buffer = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response) + - sizeof (struct arm_request) + - sizeof (struct arm_response)); - arm_resp->buffer = int2ptr((arm_addr->recvb) + - sizeof (struct arm_request_response) + - sizeof (struct arm_request) + - sizeof (struct arm_response) + - 2* sizeof (*store)); - queue_complete_req(req); - } - spin_unlock(&host_info_lock); - return(rcode); + DBGMSG("arm_lock64 -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + spin_unlock_irqrestore(&host_info_lock, irqflags); + DBGMSG("arm_lock64 -> rcode_conflict_error"); + return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + size = sizeof(struct arm_request) + sizeof(struct arm_response) + 3 * sizeof(*store) + sizeof(struct arm_request_response); /* maximum */ + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + spin_unlock_irqrestore(&host_info_lock, irqflags); + DBGMSG("arm_lock64 -> rcode_conflict_error"); + return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data = 1; + arm_req_resp = (struct arm_request_response *)(req->data); + arm_req = (struct arm_request *)((byte_t *) (req->data) + + (sizeof + (struct + arm_request_response))); + arm_resp = + (struct arm_response *)((byte_t *) (arm_req) + + (sizeof(struct arm_request))); + buf1 = (byte_t *) arm_resp + sizeof(struct arm_response); + buf2 = buf1 + 2 * sizeof(*store); + if ((ext_tcode == EXTCODE_FETCH_ADD) || + (ext_tcode == EXTCODE_LITTLE_ADD)) { + arm_req->buffer_length = sizeof(*store); + memcpy(buf1, &data, sizeof(*store)); + + } else { + arm_req->buffer_length = 2 * sizeof(*store); + memcpy(buf1, &arg, sizeof(*store)); + memcpy(buf1 + sizeof(*store), &data, sizeof(*store)); + } + if (rcode == RCODE_COMPLETE) { + arm_resp->buffer_length = sizeof(*store); + memcpy(buf2, &old, sizeof(*store)); + } else { + arm_resp->buffer_length = 0; + } + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = ((((sizeof(*store)) << 16) & (0xFFFF0000)) | + (ARM_LOCK & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = ext_tcode; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = host->node_id; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_resp->response_code = rcode; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof(struct + arm_request_response)); + arm_req_resp->response = + int2ptr((arm_addr->recvb) + + sizeof(struct arm_request_response) + + sizeof(struct arm_request)); + arm_req->buffer = + int2ptr((arm_addr->recvb) + + sizeof(struct arm_request_response) + + sizeof(struct arm_request) + + sizeof(struct arm_response)); + arm_resp->buffer = + int2ptr((arm_addr->recvb) + + sizeof(struct arm_request_response) + + sizeof(struct arm_request) + + sizeof(struct arm_response) + 2 * sizeof(*store)); + queue_complete_req(req); + } + spin_unlock_irqrestore(&host_info_lock, irqflags); + return (rcode); } static int arm_register(struct file_info *fi, struct pending_request *req) { - int retval; - struct arm_addr *addr; - struct host_info *hi; - struct file_info *fi_hlp = NULL; - struct list_head *entry; - struct arm_addr *arm_addr = NULL; - int same_host, another_host; - unsigned long flags; - - DBGMSG("arm_register called " - "addr(Offset): %8.8x %8.8x length: %u " - "rights: %2.2X notify: %2.2X " - "max_blk_len: %4.4X", - (u32) ((req->req.address >>32) & 0xFFFF), - (u32) (req->req.address & 0xFFFFFFFF), - req->req.length, ((req->req.misc >> 8) & 0xFF), - (req->req.misc & 0xFF),((req->req.misc >> 16) & 0xFFFF)); - /* check addressrange */ - if ((((req->req.address) & ~(0xFFFFFFFFFFFFULL)) != 0) || - (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFFULL)) != 0)) { - req->req.length = 0; - return (-EINVAL); - } - /* addr-list-entry for fileinfo */ - addr = (struct arm_addr *)kmalloc(sizeof(struct arm_addr), SLAB_KERNEL); - if (!addr) { - req->req.length = 0; - return (-ENOMEM); - } - /* allocation of addr_space_buffer */ - addr->addr_space_buffer = (u8 *)vmalloc(req->req.length); - if (!(addr->addr_space_buffer)) { - kfree(addr); - req->req.length = 0; - return (-ENOMEM); - } - /* initialization of addr_space_buffer */ - if ((req->req.sendb)== (unsigned long)NULL) { - /* init: set 0 */ - memset(addr->addr_space_buffer, 0,req->req.length); - } else { - /* init: user -> kernel */ - if (copy_from_user(addr->addr_space_buffer,int2ptr(req->req.sendb), - req->req.length)) { - vfree(addr->addr_space_buffer); - kfree(addr); - return (-EFAULT); - } - } - INIT_LIST_HEAD(&addr->addr_list); - addr->arm_tag = req->req.tag; - addr->start = req->req.address; - addr->end = req->req.address + req->req.length; - addr->access_rights = (u8) (req->req.misc & 0x0F); - addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F); - addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F); - addr->access_rights |= addr->client_transactions; - addr->notification_options |= addr->client_transactions; - addr->recvb = req->req.recvb; - addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF); - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(fi->host); - same_host = 0; - another_host = 0; - /* same host with address-entry containing same addressrange ? */ - list_for_each_entry(fi_hlp, &hi->file_info_list, list) { - entry = fi_hlp->addr_list.next; - while (entry != &(fi_hlp->addr_list)) { - arm_addr = list_entry(entry, struct arm_addr, addr_list); - if ( (arm_addr->start == addr->start) && - (arm_addr->end == addr->end)) { - DBGMSG("same host ownes same " - "addressrange -> EALREADY"); - same_host = 1; - break; - } - entry = entry->next; - } - if (same_host) { - break; - } - } - if (same_host) { - /* addressrange occupied by same host */ - vfree(addr->addr_space_buffer); - kfree(addr); - spin_unlock_irqrestore(&host_info_lock, flags); - return (-EALREADY); - } - /* another host with valid address-entry containing same addressrange */ - list_for_each_entry(hi, &host_info_list, list) { - if (hi->host != fi->host) { - list_for_each_entry(fi_hlp, &hi->file_info_list, list) { - entry = fi_hlp->addr_list.next; - while (entry != &(fi_hlp->addr_list)) { - arm_addr = list_entry(entry, struct arm_addr, addr_list); - if ( (arm_addr->start == addr->start) && - (arm_addr->end == addr->end)) { - DBGMSG("another host ownes same " - "addressrange"); - another_host = 1; - break; - } - entry = entry->next; - } - if (another_host) { - break; - } - } - } - } - if (another_host) { - DBGMSG("another hosts entry is valid -> SUCCESS"); - if (copy_to_user(int2ptr(req->req.recvb), - &addr->start,sizeof(u64))) { - printk(KERN_ERR "raw1394: arm_register failed " - " address-range-entry is invalid -> EFAULT !!!\n"); - vfree(addr->addr_space_buffer); - kfree(addr); - spin_unlock_irqrestore(&host_info_lock, flags); - return (-EFAULT); - } - free_pending_request(req); /* immediate success or fail */ - /* INSERT ENTRY */ - list_add_tail(&addr->addr_list, &fi->addr_list); - spin_unlock_irqrestore(&host_info_lock, flags); - return sizeof(struct raw1394_request); - } - retval = hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops, req->req.address, - req->req.address + req->req.length); - if (retval) { - /* INSERT ENTRY */ - list_add_tail(&addr->addr_list, &fi->addr_list); - } else { - DBGMSG("arm_register failed errno: %d \n",retval); - vfree(addr->addr_space_buffer); - kfree(addr); - spin_unlock_irqrestore(&host_info_lock, flags); - return (-EALREADY); - } - spin_unlock_irqrestore(&host_info_lock, flags); - free_pending_request(req); /* immediate success or fail */ - return sizeof(struct raw1394_request); + int retval; + struct arm_addr *addr; + struct host_info *hi; + struct file_info *fi_hlp = NULL; + struct list_head *entry; + struct arm_addr *arm_addr = NULL; + int same_host, another_host; + unsigned long flags; + + DBGMSG("arm_register called " + "addr(Offset): %8.8x %8.8x length: %u " + "rights: %2.2X notify: %2.2X " + "max_blk_len: %4.4X", + (u32) ((req->req.address >> 32) & 0xFFFF), + (u32) (req->req.address & 0xFFFFFFFF), + req->req.length, ((req->req.misc >> 8) & 0xFF), + (req->req.misc & 0xFF), ((req->req.misc >> 16) & 0xFFFF)); + /* check addressrange */ + if ((((req->req.address) & ~(0xFFFFFFFFFFFFULL)) != 0) || + (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFFULL)) != + 0)) { + req->req.length = 0; + return (-EINVAL); + } + /* addr-list-entry for fileinfo */ + addr = kmalloc(sizeof(*addr), SLAB_KERNEL); + if (!addr) { + req->req.length = 0; + return (-ENOMEM); + } + /* allocation of addr_space_buffer */ + addr->addr_space_buffer = vmalloc(req->req.length); + if (!(addr->addr_space_buffer)) { + kfree(addr); + req->req.length = 0; + return (-ENOMEM); + } + /* initialization of addr_space_buffer */ + if ((req->req.sendb) == (unsigned long)NULL) { + /* init: set 0 */ + memset(addr->addr_space_buffer, 0, req->req.length); + } else { + /* init: user -> kernel */ + if (copy_from_user + (addr->addr_space_buffer, int2ptr(req->req.sendb), + req->req.length)) { + vfree(addr->addr_space_buffer); + kfree(addr); + return (-EFAULT); + } + } + INIT_LIST_HEAD(&addr->addr_list); + addr->arm_tag = req->req.tag; + addr->start = req->req.address; + addr->end = req->req.address + req->req.length; + addr->access_rights = (u8) (req->req.misc & 0x0F); + addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F); + addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F); + addr->access_rights |= addr->client_transactions; + addr->notification_options |= addr->client_transactions; + addr->recvb = req->req.recvb; + addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF); + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(fi->host); + same_host = 0; + another_host = 0; + /* same host with address-entry containing same addressrange ? */ + list_for_each_entry(fi_hlp, &hi->file_info_list, list) { + entry = fi_hlp->addr_list.next; + while (entry != &(fi_hlp->addr_list)) { + arm_addr = + list_entry(entry, struct arm_addr, addr_list); + if ((arm_addr->start == addr->start) + && (arm_addr->end == addr->end)) { + DBGMSG("same host ownes same " + "addressrange -> EALREADY"); + same_host = 1; + break; + } + entry = entry->next; + } + if (same_host) { + break; + } + } + if (same_host) { + /* addressrange occupied by same host */ + vfree(addr->addr_space_buffer); + kfree(addr); + spin_unlock_irqrestore(&host_info_lock, flags); + return (-EALREADY); + } + /* another host with valid address-entry containing same addressrange */ + list_for_each_entry(hi, &host_info_list, list) { + if (hi->host != fi->host) { + list_for_each_entry(fi_hlp, &hi->file_info_list, list) { + entry = fi_hlp->addr_list.next; + while (entry != &(fi_hlp->addr_list)) { + arm_addr = + list_entry(entry, struct arm_addr, + addr_list); + if ((arm_addr->start == addr->start) + && (arm_addr->end == addr->end)) { + DBGMSG + ("another host ownes same " + "addressrange"); + another_host = 1; + break; + } + entry = entry->next; + } + if (another_host) { + break; + } + } + } + } + if (another_host) { + DBGMSG("another hosts entry is valid -> SUCCESS"); + if (copy_to_user(int2ptr(req->req.recvb), + &addr->start, sizeof(u64))) { + printk(KERN_ERR "raw1394: arm_register failed " + " address-range-entry is invalid -> EFAULT !!!\n"); + vfree(addr->addr_space_buffer); + kfree(addr); + spin_unlock_irqrestore(&host_info_lock, flags); + return (-EFAULT); + } + free_pending_request(req); /* immediate success or fail */ + /* INSERT ENTRY */ + list_add_tail(&addr->addr_list, &fi->addr_list); + spin_unlock_irqrestore(&host_info_lock, flags); + return sizeof(struct raw1394_request); + } + retval = + hpsb_register_addrspace(&raw1394_highlevel, fi->host, &arm_ops, + req->req.address, + req->req.address + req->req.length); + if (retval) { + /* INSERT ENTRY */ + list_add_tail(&addr->addr_list, &fi->addr_list); + } else { + DBGMSG("arm_register failed errno: %d \n", retval); + vfree(addr->addr_space_buffer); + kfree(addr); + spin_unlock_irqrestore(&host_info_lock, flags); + return (-EALREADY); + } + spin_unlock_irqrestore(&host_info_lock, flags); + free_pending_request(req); /* immediate success or fail */ + return sizeof(struct raw1394_request); } static int arm_unregister(struct file_info *fi, struct pending_request *req) { - int found = 0; - int retval = 0; - struct list_head *entry; - struct arm_addr *addr = NULL; - struct host_info *hi; - struct file_info *fi_hlp = NULL; - struct arm_addr *arm_addr = NULL; - int another_host; - unsigned long flags; - - DBGMSG("arm_Unregister called addr(Offset): " - "%8.8x %8.8x", - (u32) ((req->req.address >>32) & 0xFFFF), - (u32) (req->req.address & 0xFFFFFFFF)); - spin_lock_irqsave(&host_info_lock, flags); - /* get addr */ - entry = fi->addr_list.next; - while (entry != &(fi->addr_list)) { - addr = list_entry(entry, struct arm_addr, addr_list); - if (addr->start == req->req.address) { - found = 1; - break; - } - entry = entry->next; - } - if (!found) { - DBGMSG("arm_Unregister addr not found"); - spin_unlock_irqrestore(&host_info_lock, flags); - return (-EINVAL); - } - DBGMSG("arm_Unregister addr found"); - another_host = 0; - /* another host with valid address-entry containing - same addressrange */ - list_for_each_entry(hi, &host_info_list, list) { - if (hi->host != fi->host) { - list_for_each_entry(fi_hlp, &hi->file_info_list, list) { - entry = fi_hlp->addr_list.next; - while (entry != &(fi_hlp->addr_list)) { - arm_addr = list_entry(entry, - struct arm_addr, addr_list); - if (arm_addr->start == - addr->start) { - DBGMSG("another host ownes " - "same addressrange"); - another_host = 1; - break; - } - entry = entry->next; - } - if (another_host) { - break; - } - } - } - } - if (another_host) { - DBGMSG("delete entry from list -> success"); - list_del(&addr->addr_list); - vfree(addr->addr_space_buffer); - kfree(addr); - free_pending_request(req); /* immediate success or fail */ - spin_unlock_irqrestore(&host_info_lock, flags); - return sizeof(struct raw1394_request); - } - 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 sizeof(struct raw1394_request); + int found = 0; + int retval = 0; + struct list_head *entry; + struct arm_addr *addr = NULL; + struct host_info *hi; + struct file_info *fi_hlp = NULL; + struct arm_addr *arm_addr = NULL; + int another_host; + unsigned long flags; + + DBGMSG("arm_Unregister called addr(Offset): " + "%8.8x %8.8x", + (u32) ((req->req.address >> 32) & 0xFFFF), + (u32) (req->req.address & 0xFFFFFFFF)); + spin_lock_irqsave(&host_info_lock, flags); + /* get addr */ + entry = fi->addr_list.next; + while (entry != &(fi->addr_list)) { + addr = list_entry(entry, struct arm_addr, addr_list); + if (addr->start == req->req.address) { + found = 1; + break; + } + entry = entry->next; + } + if (!found) { + DBGMSG("arm_Unregister addr not found"); + spin_unlock_irqrestore(&host_info_lock, flags); + return (-EINVAL); + } + DBGMSG("arm_Unregister addr found"); + another_host = 0; + /* another host with valid address-entry containing + same addressrange */ + list_for_each_entry(hi, &host_info_list, list) { + if (hi->host != fi->host) { + list_for_each_entry(fi_hlp, &hi->file_info_list, list) { + entry = fi_hlp->addr_list.next; + while (entry != &(fi_hlp->addr_list)) { + arm_addr = list_entry(entry, + struct arm_addr, + addr_list); + if (arm_addr->start == addr->start) { + DBGMSG("another host ownes " + "same addressrange"); + another_host = 1; + break; + } + entry = entry->next; + } + if (another_host) { + break; + } + } + } + } + if (another_host) { + DBGMSG("delete entry from list -> success"); + list_del(&addr->addr_list); + vfree(addr->addr_space_buffer); + kfree(addr); + free_pending_request(req); /* immediate success or fail */ + spin_unlock_irqrestore(&host_info_lock, flags); + return sizeof(struct raw1394_request); + } + 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 sizeof(struct raw1394_request); } /* 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; + struct arm_addr *arm_addr = NULL; unsigned long flags; unsigned long offset; @@ -1749,8 +1941,7 @@ static int arm_get_buf(struct file_info *fi, struct pending_request *req) 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); + (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length); spin_lock_irqsave(&host_info_lock, flags); entry = fi->addr_list.next; @@ -1761,13 +1952,18 @@ static int arm_get_buf(struct file_info *fi, struct pending_request *req) if (req->req.address + req->req.length <= arm_addr->end) { offset = req->req.address - arm_addr->start; - 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)) { - 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)) { + spin_unlock_irqrestore(&host_info_lock, + flags); return (-EFAULT); } @@ -1789,11 +1985,10 @@ static int arm_get_buf(struct file_info *fi, struct pending_request *req) 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; + struct arm_addr *arm_addr = NULL; unsigned long flags; unsigned long offset; @@ -1802,9 +1997,7 @@ static int arm_set_buf(struct file_info *fi, struct pending_request *req) 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); - + (u32) (req->req.address & 0xFFFFFFFF), (u32) req->req.length); spin_lock_irqsave(&host_info_lock, flags); entry = fi->addr_list.next; @@ -1815,18 +2008,23 @@ static int arm_set_buf(struct file_info *fi, struct pending_request *req) if (req->req.address + req->req.length <= arm_addr->end) { offset = req->req.address - arm_addr->start; - 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)) { - 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)) { + spin_unlock_irqrestore(&host_info_lock, + flags); return (-EFAULT); } spin_unlock_irqrestore(&host_info_lock, flags); - free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ + free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ return sizeof(struct raw1394_request); } else { DBGMSG("arm_set_buf request exceeded mapping"); @@ -1842,96 +2040,101 @@ static int arm_set_buf(struct file_info *fi, struct pending_request *req) 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 sizeof(struct raw1394_request); - } - /* error EINVAL (22) invalid argument */ - return (-EINVAL); + 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 sizeof(struct raw1394_request); + } + /* 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; - - 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_irq(&fi->reqlists_lock); - list_add_tail(&req->list, &fi->req_pending); - spin_unlock_irq(&fi->reqlists_lock); - 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 sizeof(struct raw1394_request); + 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 sizeof(struct raw1394_request); } static int get_config_rom(struct file_info *fi, struct pending_request *req) { - int ret=sizeof(struct raw1394_request); - quadlet_t *data = kmalloc(req->req.length, SLAB_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; + int ret = sizeof(struct raw1394_request); + quadlet_t *data = kmalloc(req->req.length, SLAB_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; + 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=sizeof(struct raw1394_request); - quadlet_t *data = kmalloc(req->req.length, SLAB_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 */ + int ret = sizeof(struct raw1394_request); + quadlet_t *data = kmalloc(req->req.length, SLAB_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; + } + return ret; } static int modify_config_rom(struct file_info *fi, struct pending_request *req) @@ -1943,23 +2146,32 @@ static int modify_config_rom(struct file_info *fi, struct pending_request *req) int ret = 0; if (req->req.misc == ~0) { - if (req->req.length == 0) return -EINVAL; + 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++); + for (dr = 0; + dr < RAW1394_MAX_USER_CSR_DIRS && fi->csr1212_dirs[dr]; + dr++) ; - if (dr == RAW1394_MAX_USER_CSR_DIRS) return -ENOMEM; + 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; + 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; + if (!fi->csr1212_dirs[dr]) + return -EINVAL; /* Delete old stuff */ - for (dentry = fi->csr1212_dirs[dr]->value.directory.dentries_head; + 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, + csr1212_detach_keyval_from_directory(fi->host->csr.rom-> + root_kv, dentry->kv); } @@ -1980,7 +2192,7 @@ static int modify_config_rom(struct file_info *fi, struct pending_request *req) return -ENOMEM; } - cache->filled_head = kmalloc(sizeof(struct csr1212_cache_region), GFP_KERNEL); + 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; @@ -1993,12 +2205,11 @@ static int modify_config_rom(struct file_info *fi, struct pending_request *req) req->req.length)) { csr1212_release_keyval(fi->csr1212_dirs[dr]); fi->csr1212_dirs[dr] = NULL; - CSR1212_FREE(cache); - ret= -EFAULT; + ret = -EFAULT; } else { cache->len = req->req.length; cache->filled_head->offset_start = 0; - cache->filled_head->offset_end = cache->size -1; + cache->filled_head->offset_end = cache->size - 1; cache->layout_head = cache->layout_tail = fi->csr1212_dirs[dr]; @@ -2010,23 +2221,26 @@ static int modify_config_rom(struct file_info *fi, struct pending_request *req) } /* attach top level items to the root directory */ - for (dentry = fi->csr1212_dirs[dr]->value.directory.dentries_head; + 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); + 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))) { + &dr, sizeof(dr))) { ret = -ENOMEM; } } } kfree(cache->filled_head); - kfree(cache); + CSR1212_FREE(cache); if (ret >= 0) { /* we have to free the request, because we queue no response, @@ -2034,9 +2248,11 @@ static int modify_config_rom(struct file_info *fi, struct pending_request *req) free_pending_request(req); return sizeof(struct raw1394_request); } else { - for (dentry = fi->csr1212_dirs[dr]->value.directory.dentries_head; + 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, + csr1212_detach_keyval_from_directory(fi->host->csr.rom-> + root_kv, dentry->kv); } csr1212_release_keyval(fi->csr1212_dirs[dr]); @@ -2047,133 +2263,142 @@ static int modify_config_rom(struct file_info *fi, struct pending_request *req) static int state_connected(struct file_info *fi, struct pending_request *req) { - int node = req->req.address >> 48; + int node = req->req.address >> 48; - req->req.error = RAW1394_ERROR_NONE; + req->req.error = RAW1394_ERROR_NONE; - switch (req->req.type) { + switch (req->req.type) { - case RAW1394_REQ_ECHO: - queue_complete_req(req); - return sizeof(struct raw1394_request); + case RAW1394_REQ_ECHO: + queue_complete_req(req); + return sizeof(struct raw1394_request); - case RAW1394_REQ_ISO_SEND: - return handle_iso_send(fi, req, node); + case RAW1394_REQ_ISO_SEND: + return handle_iso_send(fi, req, node); - case RAW1394_REQ_ARM_REGISTER: - return arm_register(fi, req); + case RAW1394_REQ_ARM_REGISTER: + return arm_register(fi, req); - case RAW1394_REQ_ARM_UNREGISTER: - return arm_unregister(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_SET_BUF: + return arm_set_buf(fi, req); - case RAW1394_REQ_ARM_GET_BUF: - return arm_get_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_RESET_NOTIFY: + return reset_notification(fi, req); - case RAW1394_REQ_ISO_LISTEN: - handle_iso_listen(fi, req); - return sizeof(struct raw1394_request); + case RAW1394_REQ_ISO_LISTEN: + handle_iso_listen(fi, req); + return sizeof(struct raw1394_request); - case RAW1394_REQ_FCP_LISTEN: - handle_fcp_listen(fi, req); - return sizeof(struct raw1394_request); + case RAW1394_REQ_FCP_LISTEN: + handle_fcp_listen(fi, req); + return sizeof(struct raw1394_request); - 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 sizeof(struct raw1394_request); - } - 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 sizeof(struct raw1394_request); - } - /* error EINVAL (22) invalid argument */ - return (-EINVAL); - case RAW1394_REQ_GET_ROM: - return get_config_rom(fi, req); + 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 sizeof(struct raw1394_request); + } + 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 sizeof(struct raw1394_request); + } + /* 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_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 sizeof(struct raw1394_request); - } - - 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 sizeof(struct raw1394_request); - } - - return handle_async_request(fi, req, node); + } + + 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 sizeof(struct raw1394_request); + } + + 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 sizeof(struct raw1394_request); + } + + 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) +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 = 0; - - if (count != sizeof(struct raw1394_request)) { - return -EINVAL; - } - - req = alloc_pending_request(); - if (req == NULL) { - return -ENOMEM; - } - req->file_info = fi; - - if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) { - free_pending_request(req); - return -EFAULT; - } - - switch (fi->state) { - case opened: - retval = state_opened(fi, req); - break; - - case initialized: - retval = state_initialized(fi, req); - break; - - case connected: - retval = state_connected(fi, req); - break; - } - - if (retval < 0) { - free_pending_request(req); - } - - return retval; + struct file_info *fi = (struct file_info *)file->private_data; + struct pending_request *req; + ssize_t retval = 0; + +#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 PTR_ERR(buffer); + } else +#endif + if (count != sizeof(struct raw1394_request)) { + return -EINVAL; + } + + req = alloc_pending_request(); + if (req == NULL) { + return -ENOMEM; + } + req->file_info = fi; + + if (copy_from_user(&req->req, buffer, sizeof(struct raw1394_request))) { + free_pending_request(req); + return -EFAULT; + } + + switch (fi->state) { + case opened: + retval = state_opened(fi, req); + break; + + case initialized: + retval = state_initialized(fi, req); + break; + + case connected: + retval = state_connected(fi, req); + break; + } + + if (retval < 0) { + free_pending_request(req); + } + + return retval; } /* rawiso operations */ @@ -2185,8 +2410,8 @@ static inline int __rawiso_event_in_queue(struct file_info *fi) struct pending_request *req; list_for_each_entry(req, &fi->req_complete, list) - if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY) - return 1; + if (req->req.type == RAW1394_REQ_RAWISO_ACTIVITY) + return 1; return 0; } @@ -2200,7 +2425,8 @@ static void queue_rawiso_event(struct file_info *fi) /* only one ISO activity event may be in the queue */ if (!__rawiso_event_in_queue(fi)) { - struct pending_request *req = __alloc_pending_request(SLAB_ATOMIC); + struct pending_request *req = + __alloc_pending_request(SLAB_ATOMIC); if (req) { req->file_info = fi; @@ -2220,11 +2446,11 @@ static void queue_rawiso_event(struct file_info *fi) static void rawiso_activity_cb(struct hpsb_iso *iso) { unsigned long flags; - struct host_info *hi; + struct host_info *hi; struct file_info *fi; - spin_lock_irqsave(&host_info_lock, flags); - hi = find_host_info(iso->host); + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(iso->host); if (hi != NULL) { list_for_each_entry(fi, &hi->file_info_list, list) { @@ -2237,7 +2463,8 @@ static void rawiso_activity_cb(struct hpsb_iso *iso) } /* helper function - gather all the kernel iso status bits for returning to user-space */ -static void raw1394_iso_fill_status(struct hpsb_iso *iso, struct raw1394_iso_status *stat) +static void raw1394_iso_fill_status(struct hpsb_iso *iso, + struct raw1394_iso_status *stat) { stat->config.data_buf_size = iso->buf_size; stat->config.buf_packets = iso->buf_packets; @@ -2249,7 +2476,7 @@ static void raw1394_iso_fill_status(struct hpsb_iso *iso, struct raw1394_iso_sta stat->xmit_cycle = iso->xmit_cycle; } -static int raw1394_iso_xmit_init(struct file_info *fi, void __user *uaddr) +static int raw1394_iso_xmit_init(struct file_info *fi, void __user * uaddr) { struct raw1394_iso_status stat; @@ -2281,7 +2508,7 @@ static int raw1394_iso_xmit_init(struct file_info *fi, void __user *uaddr) return 0; } -static int raw1394_iso_recv_init(struct file_info *fi, void __user *uaddr) +static int raw1394_iso_recv_init(struct file_info *fi, void __user * uaddr) { struct raw1394_iso_status stat; @@ -2295,7 +2522,7 @@ static int raw1394_iso_recv_init(struct file_info *fi, void __user *uaddr) stat.config.data_buf_size, stat.config.buf_packets, stat.config.channel, - stat.config.dma_mode, + stat.config.dma_mode, stat.config.irq_interval, rawiso_activity_cb); if (!fi->iso_handle) @@ -2309,7 +2536,7 @@ static int raw1394_iso_recv_init(struct file_info *fi, void __user *uaddr) return 0; } -static int raw1394_iso_get_status(struct file_info *fi, void __user *uaddr) +static int raw1394_iso_get_status(struct file_info *fi, void __user * uaddr) { struct raw1394_iso_status stat; struct hpsb_iso *iso = fi->iso_handle; @@ -2325,7 +2552,7 @@ static int raw1394_iso_get_status(struct file_info *fi, void __user *uaddr) } /* copy N packet_infos out of the ringbuffer into user-supplied array */ -static int raw1394_iso_recv_packets(struct file_info *fi, void __user *uaddr) +static int raw1394_iso_recv_packets(struct file_info *fi, void __user * uaddr) { struct raw1394_iso_packets upackets; unsigned int packet = fi->iso_handle->first_packet; @@ -2338,15 +2565,16 @@ static int raw1394_iso_recv_packets(struct file_info *fi, void __user *uaddr) return -EINVAL; /* ensure user-supplied buffer is accessible and big enough */ - if (verify_area(VERIFY_WRITE, upackets.infos, - upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) + if (!access_ok(VERIFY_WRITE, upackets.infos, + upackets.n_packets * + sizeof(struct raw1394_iso_packet_info))) return -EFAULT; /* copy the packet_infos out */ for (i = 0; i < upackets.n_packets; i++) { if (__copy_to_user(&upackets.infos[i], - &fi->iso_handle->infos[packet], - sizeof(struct raw1394_iso_packet_info))) + &fi->iso_handle->infos[packet], + sizeof(struct raw1394_iso_packet_info))) return -EFAULT; packet = (packet + 1) % fi->iso_handle->buf_packets; @@ -2356,7 +2584,7 @@ static int raw1394_iso_recv_packets(struct file_info *fi, void __user *uaddr) } /* copy N packet_infos from user to ringbuffer, and queue them for transmission */ -static int raw1394_iso_send_packets(struct file_info *fi, void __user *uaddr) +static int raw1394_iso_send_packets(struct file_info *fi, void __user * uaddr) { struct raw1394_iso_packets upackets; int i, rv; @@ -2364,12 +2592,16 @@ static int raw1394_iso_send_packets(struct file_info *fi, void __user *uaddr) if (copy_from_user(&upackets, uaddr, sizeof(upackets))) return -EFAULT; - if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) + if (upackets.n_packets >= fi->iso_handle->buf_packets) return -EINVAL; + if (upackets.n_packets >= hpsb_iso_n_ready(fi->iso_handle)) + return -EAGAIN; + /* ensure user-supplied buffer is accessible and big enough */ - if (verify_area(VERIFY_READ, upackets.infos, - upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) + if (!access_ok(VERIFY_READ, upackets.infos, + upackets.n_packets * + sizeof(struct raw1394_iso_packet_info))) return -EFAULT; /* copy the infos structs in and queue the packets */ @@ -2377,7 +2609,7 @@ static int raw1394_iso_send_packets(struct file_info *fi, void __user *uaddr) struct raw1394_iso_packet_info info; if (__copy_from_user(&info, &upackets.infos[i], - sizeof(struct raw1394_iso_packet_info))) + sizeof(struct raw1394_iso_packet_info))) return -EFAULT; rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset, @@ -2410,14 +2642,15 @@ static int raw1394_mmap(struct file *file, struct vm_area_struct *vma) } /* ioctl is only used for rawiso operations */ -static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int raw1394_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct file_info *fi = file->private_data; void __user *argp = (void __user *)arg; - switch(fi->iso_state) { + switch (fi->iso_state) { case RAW1394_ISO_INACTIVE: - switch(cmd) { + switch (cmd) { case RAW1394_IOC_ISO_XMIT_INIT: return raw1394_iso_xmit_init(fi, argp); case RAW1394_IOC_ISO_RECV_INIT: @@ -2427,34 +2660,42 @@ static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cm } break; case RAW1394_ISO_RECV: - switch(cmd) { - case RAW1394_IOC_ISO_RECV_START: { - /* copy args from user-space */ - int args[3]; - if (copy_from_user(&args[0], argp, sizeof(args))) - return -EFAULT; - return hpsb_iso_recv_start(fi->iso_handle, args[0], args[1], args[2]); - } + switch (cmd) { + case RAW1394_IOC_ISO_RECV_START:{ + /* copy args from user-space */ + int args[3]; + if (copy_from_user + (&args[0], argp, sizeof(args))) + return -EFAULT; + return hpsb_iso_recv_start(fi->iso_handle, + args[0], args[1], + args[2]); + } case RAW1394_IOC_ISO_XMIT_RECV_STOP: hpsb_iso_stop(fi->iso_handle); return 0; case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL: - return hpsb_iso_recv_listen_channel(fi->iso_handle, arg); + return hpsb_iso_recv_listen_channel(fi->iso_handle, + arg); case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL: - return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg); - case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK: { - /* copy the u64 from user-space */ - u64 mask; - if (copy_from_user(&mask, argp, sizeof(mask))) - return -EFAULT; - return hpsb_iso_recv_set_channel_mask(fi->iso_handle, mask); - } + return hpsb_iso_recv_unlisten_channel(fi->iso_handle, + arg); + case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK:{ + /* copy the u64 from user-space */ + u64 mask; + if (copy_from_user(&mask, argp, sizeof(mask))) + return -EFAULT; + return hpsb_iso_recv_set_channel_mask(fi-> + iso_handle, + mask); + } case RAW1394_IOC_ISO_GET_STATUS: return raw1394_iso_get_status(fi, argp); case RAW1394_IOC_ISO_RECV_PACKETS: return raw1394_iso_recv_packets(fi, argp); case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS: - return hpsb_iso_recv_release_packets(fi->iso_handle, arg); + return hpsb_iso_recv_release_packets(fi->iso_handle, + arg); case RAW1394_IOC_ISO_RECV_FLUSH: return hpsb_iso_recv_flush(fi->iso_handle); case RAW1394_IOC_ISO_SHUTDOWN: @@ -2466,14 +2707,16 @@ static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cm } break; case RAW1394_ISO_XMIT: - switch(cmd) { - case RAW1394_IOC_ISO_XMIT_START: { - /* copy two ints from user-space */ - int args[2]; - if (copy_from_user(&args[0], argp, sizeof(args))) - return -EFAULT; - return hpsb_iso_xmit_start(fi->iso_handle, args[0], args[1]); - } + switch (cmd) { + case RAW1394_IOC_ISO_XMIT_START:{ + /* copy two ints from user-space */ + int args[2]; + if (copy_from_user + (&args[0], argp, sizeof(args))) + return -EFAULT; + return hpsb_iso_xmit_start(fi->iso_handle, + args[0], args[1]); + } case RAW1394_IOC_ISO_XMIT_SYNC: return hpsb_iso_xmit_sync(fi->iso_handle); case RAW1394_IOC_ISO_XMIT_RECV_STOP: @@ -2498,273 +2741,303 @@ static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cm return -EINVAL; } -static unsigned int raw1394_poll(struct file *file, poll_table *pt) +static unsigned int raw1394_poll(struct file *file, poll_table * pt) { - struct file_info *fi = file->private_data; - unsigned int mask = POLLOUT | POLLWRNORM; + struct file_info *fi = file->private_data; + unsigned int mask = POLLOUT | POLLWRNORM; + unsigned long flags; - poll_wait(file, &fi->poll_wait_complete, pt); + poll_wait(file, &fi->poll_wait_complete, pt); - spin_lock_irq(&fi->reqlists_lock); - if (!list_empty(&fi->req_complete)) { - mask |= POLLIN | POLLRDNORM; - } - spin_unlock_irq(&fi->reqlists_lock); + spin_lock_irqsave(&fi->reqlists_lock, flags); + if (!list_empty(&fi->req_complete)) { + mask |= POLLIN | POLLRDNORM; + } + spin_unlock_irqrestore(&fi->reqlists_lock, flags); - return mask; + return mask; } static int raw1394_open(struct inode *inode, struct file *file) { - struct file_info *fi; + struct file_info *fi; - fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL); - if (fi == NULL) - return -ENOMEM; + fi = kzalloc(sizeof(*fi), SLAB_KERNEL); + if (!fi) + return -ENOMEM; - memset(fi, 0, sizeof(struct file_info)); - fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */ + fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */ - INIT_LIST_HEAD(&fi->list); - fi->state = opened; - INIT_LIST_HEAD(&fi->req_pending); - INIT_LIST_HEAD(&fi->req_complete); - sema_init(&fi->complete_sem, 0); - spin_lock_init(&fi->reqlists_lock); - init_waitqueue_head(&fi->poll_wait_complete); - INIT_LIST_HEAD(&fi->addr_list); + INIT_LIST_HEAD(&fi->list); + fi->state = opened; + INIT_LIST_HEAD(&fi->req_pending); + INIT_LIST_HEAD(&fi->req_complete); + sema_init(&fi->complete_sem, 0); + spin_lock_init(&fi->reqlists_lock); + init_waitqueue_head(&fi->poll_wait_complete); + INIT_LIST_HEAD(&fi->addr_list); - file->private_data = fi; + file->private_data = fi; - return 0; + return 0; } static int raw1394_release(struct inode *inode, struct file *file) { - struct file_info *fi = file->private_data; - struct list_head *lh; - struct pending_request *req; - int done = 0, i, fail = 0; - int retval = 0; - struct list_head *entry; - struct arm_addr *addr = NULL; - struct host_info *hi; - struct file_info *fi_hlp = NULL; - struct arm_addr *arm_addr = NULL; - int another_host; + struct file_info *fi = file->private_data; + struct list_head *lh; + struct pending_request *req; + int done = 0, i, fail = 0; + int retval = 0; + struct list_head *entry; + struct arm_addr *addr = NULL; + struct host_info *hi; + struct file_info *fi_hlp = NULL; + struct arm_addr *arm_addr = NULL; + int another_host; int csr_mod = 0; + unsigned long flags; if (fi->iso_state != RAW1394_ISO_INACTIVE) raw1394_iso_shutdown(fi); - for (i = 0; i < 64; i++) { - if (fi->listen_channels & (1ULL << i)) { - hpsb_unlisten_channel(&raw1394_highlevel, fi->host, i); - } - } - - spin_lock_irq(&host_info_lock); - fi->listen_channels = 0; - spin_unlock_irq(&host_info_lock); - - fail = 0; - /* set address-entries invalid */ - spin_lock_irq(&host_info_lock); - - while (!list_empty(&fi->addr_list)) { - another_host = 0; - lh = fi->addr_list.next; - addr = list_entry(lh, struct arm_addr, addr_list); - /* another host with valid address-entry containing - same addressrange? */ - list_for_each_entry(hi, &host_info_list, list) { - if (hi->host != fi->host) { - list_for_each_entry(fi_hlp, &hi->file_info_list, list) { - entry = fi_hlp->addr_list.next; - while (entry != &(fi_hlp->addr_list)) { - arm_addr = list_entry(entry, - struct arm_addr, addr_list); - if (arm_addr->start == - addr->start) { - DBGMSG("raw1394_release: " - "another host ownes " - "same addressrange"); - another_host = 1; - break; - } - entry = entry->next; - } - if (another_host) { - break; - } - } - } - } - if (!another_host) { - DBGMSG("raw1394_release: call hpsb_arm_unregister"); - retval = hpsb_unregister_addrspace(&raw1394_highlevel, fi->host, addr->start); - if (!retval) { - ++fail; - printk(KERN_ERR "raw1394_release arm_Unregister failed\n"); - } - } - DBGMSG("raw1394_release: delete addr_entry from list"); - list_del(&addr->addr_list); - vfree(addr->addr_space_buffer); - kfree(addr); - } /* while */ - spin_unlock_irq(&host_info_lock); - if (fail > 0) { - printk(KERN_ERR "raw1394: during addr_list-release " - "error(s) occurred \n"); - } - - while (!done) { - spin_lock_irq(&fi->reqlists_lock); - - while (!list_empty(&fi->req_complete)) { - lh = fi->req_complete.next; - list_del(lh); - - req = list_entry(lh, struct pending_request, list); - - free_pending_request(req); - } - - if (list_empty(&fi->req_pending)) done = 1; - - spin_unlock_irq(&fi->reqlists_lock); - - if (!done) down_interruptible(&fi->complete_sem); - } + for (i = 0; i < 64; i++) { + if (fi->listen_channels & (1ULL << i)) { + hpsb_unlisten_channel(&raw1394_highlevel, fi->host, i); + } + } + + spin_lock_irqsave(&host_info_lock, flags); + fi->listen_channels = 0; + + fail = 0; + /* set address-entries invalid */ + + while (!list_empty(&fi->addr_list)) { + another_host = 0; + lh = fi->addr_list.next; + addr = list_entry(lh, struct arm_addr, addr_list); + /* another host with valid address-entry containing + same addressrange? */ + list_for_each_entry(hi, &host_info_list, list) { + if (hi->host != fi->host) { + list_for_each_entry(fi_hlp, &hi->file_info_list, + list) { + entry = fi_hlp->addr_list.next; + while (entry != &(fi_hlp->addr_list)) { + arm_addr = list_entry(entry, struct + arm_addr, + addr_list); + if (arm_addr->start == + addr->start) { + DBGMSG + ("raw1394_release: " + "another host ownes " + "same addressrange"); + another_host = 1; + break; + } + entry = entry->next; + } + if (another_host) { + break; + } + } + } + } + if (!another_host) { + DBGMSG("raw1394_release: call hpsb_arm_unregister"); + retval = + hpsb_unregister_addrspace(&raw1394_highlevel, + fi->host, addr->start); + if (!retval) { + ++fail; + printk(KERN_ERR + "raw1394_release arm_Unregister failed\n"); + } + } + DBGMSG("raw1394_release: delete addr_entry from list"); + list_del(&addr->addr_list); + vfree(addr->addr_space_buffer); + kfree(addr); + } /* while */ + spin_unlock_irqrestore(&host_info_lock, flags); + if (fail > 0) { + printk(KERN_ERR "raw1394: during addr_list-release " + "error(s) occurred \n"); + } + + while (!done) { + spin_lock_irqsave(&fi->reqlists_lock, flags); + + while (!list_empty(&fi->req_complete)) { + lh = fi->req_complete.next; + list_del(lh); + + req = list_entry(lh, struct pending_request, list); + + free_pending_request(req); + } + + if (list_empty(&fi->req_pending)) + done = 1; + + spin_unlock_irqrestore(&fi->reqlists_lock, flags); + + if (!done) + down_interruptible(&fi->complete_sem); + } /* Remove any sub-trees left by user space programs */ for (i = 0; i < RAW1394_MAX_USER_CSR_DIRS; i++) { struct csr1212_dentry *dentry; - if (!fi->csr1212_dirs[i]) continue; - for (dentry = fi->csr1212_dirs[i]->value.directory.dentries_head; - dentry; dentry = dentry->next) { - csr1212_detach_keyval_from_directory(fi->host->csr.rom->root_kv, dentry->kv); + if (!fi->csr1212_dirs[i]) + continue; + for (dentry = + fi->csr1212_dirs[i]->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[i]); fi->csr1212_dirs[i] = NULL; csr_mod = 1; } - if ((csr_mod || fi->cfgrom_upd) && hpsb_update_config_rom_image(fi->host) < 0) - HPSB_ERR("Failed to generate Configuration ROM image for host %d", fi->host->id); + if ((csr_mod || fi->cfgrom_upd) + && hpsb_update_config_rom_image(fi->host) < 0) + HPSB_ERR + ("Failed to generate Configuration ROM image for host %d", + fi->host->id); - if (fi->state == connected) { - spin_lock_irq(&host_info_lock); - list_del(&fi->list); - spin_unlock_irq(&host_info_lock); + if (fi->state == connected) { + spin_lock_irqsave(&host_info_lock, flags); + list_del(&fi->list); + spin_unlock_irqrestore(&host_info_lock, flags); put_device(&fi->host->device); - } + } - kfree(fi); + kfree(fi); - return 0; + return 0; } - /*** HOTPLUG STUFF **********************************************************/ /* * Export information about protocols/devices supported by this driver. */ static struct ieee1394_device_id raw1394_id_table[] = { { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = AVC_SW_VERSION_ENTRY & 0xffffff - }, + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + .version = AVC_SW_VERSION_ENTRY & 0xffffff}, + { + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, + .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, + .version = CAMERA_SW_VERSION_ENTRY & 0xffffff}, { - .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, - .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, - .version = CAMERA_SW_VERSION_ENTRY & 0xffffff - }, - { } + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, + .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, + .version = (CAMERA_SW_VERSION_ENTRY + 1) & 0xffffff}, + { + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, + .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, + .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff}, + {} }; MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table); static struct hpsb_protocol_driver raw1394_driver = { - .name = "raw1394 Driver", - .id_table = raw1394_id_table, - .driver = { - .name = "raw1394", - .bus = &ieee1394_bus_type, - }, + .name = "raw1394 Driver", + .id_table = raw1394_id_table, + .driver = { + .name = "raw1394", + .bus = &ieee1394_bus_type, + }, }; - /******************************************************************************/ - static struct hpsb_highlevel raw1394_highlevel = { - .name = RAW1394_DEVICE_NAME, - .add_host = add_host, - .remove_host = remove_host, - .host_reset = host_reset, - .iso_receive = iso_receive, - .fcp_request = fcp_request, + .name = RAW1394_DEVICE_NAME, + .add_host = add_host, + .remove_host = remove_host, + .host_reset = host_reset, + .iso_receive = iso_receive, + .fcp_request = fcp_request, }; static struct cdev raw1394_cdev; static struct file_operations raw1394_fops = { - .owner = THIS_MODULE, - .read = raw1394_read, - .write = raw1394_write, - .mmap = raw1394_mmap, - .ioctl = raw1394_ioctl, - .poll = raw1394_poll, - .open = raw1394_open, - .release = raw1394_release, + .owner = THIS_MODULE, + .read = raw1394_read, + .write = raw1394_write, + .mmap = raw1394_mmap, + .ioctl = raw1394_ioctl, + // .compat_ioctl = ... someone needs to do this + .poll = raw1394_poll, + .open = raw1394_open, + .release = raw1394_release, }; static int __init init_raw1394(void) { - int ret; + int ret = 0; hpsb_register_highlevel(&raw1394_highlevel); - devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16), - S_IFCHR | S_IRUSR | S_IWUSR, RAW1394_DEVICE_NAME); + if (IS_ERR + (class_device_create + (hpsb_protocol_class, NULL, + MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16), NULL, + RAW1394_DEVICE_NAME))) { + ret = -EFAULT; + goto out_unreg; + } cdev_init(&raw1394_cdev, &raw1394_fops); raw1394_cdev.owner = THIS_MODULE; kobject_set_name(&raw1394_cdev.kobj, RAW1394_DEVICE_NAME); ret = cdev_add(&raw1394_cdev, IEEE1394_RAW1394_DEV, 1); if (ret) { - HPSB_ERR("raw1394 failed to register minor device block"); - devfs_remove(RAW1394_DEVICE_NAME); - hpsb_unregister_highlevel(&raw1394_highlevel); - return ret; - } + HPSB_ERR("raw1394 failed to register minor device block"); + goto out_dev; + } - HPSB_INFO("raw1394: /dev/%s device initialized", RAW1394_DEVICE_NAME); + HPSB_INFO("raw1394: /dev/%s device initialized", RAW1394_DEVICE_NAME); ret = hpsb_register_protocol(&raw1394_driver); if (ret) { HPSB_ERR("raw1394: failed to register protocol"); cdev_del(&raw1394_cdev); - devfs_remove(RAW1394_DEVICE_NAME); - hpsb_unregister_highlevel(&raw1394_highlevel); - return ret; + goto out_dev; } - return 0; + goto out; + + out_dev: + class_device_destroy(hpsb_protocol_class, + MKDEV(IEEE1394_MAJOR, + IEEE1394_MINOR_BLOCK_RAW1394 * 16)); + out_unreg: + hpsb_unregister_highlevel(&raw1394_highlevel); + out: + return ret; } static void __exit cleanup_raw1394(void) { - hpsb_unregister_protocol(&raw1394_driver); + class_device_destroy(hpsb_protocol_class, + MKDEV(IEEE1394_MAJOR, + IEEE1394_MINOR_BLOCK_RAW1394 * 16)); cdev_del(&raw1394_cdev); - devfs_remove(RAW1394_DEVICE_NAME); - hpsb_unregister_highlevel(&raw1394_highlevel); + hpsb_unregister_highlevel(&raw1394_highlevel); + hpsb_unregister_protocol(&raw1394_driver); } module_init(init_raw1394); module_exit(cleanup_raw1394); MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16);