static int ioctl_allocate(struct client *client, void *buffer) { struct fw_cdev_allocate *request = buffer; struct address_handler_resource *r; struct fw_address_region region; int ret; r = kmalloc(sizeof(*r), GFP_KERNEL); if (r == NULL) return -ENOMEM; region.start = request->offset; region.end = request->offset + request->length; r->handler.length = request->length; r->handler.address_callback = handle_request; r->handler.callback_data = r; r->closure = request->closure; r->client = client; ret = fw_core_add_address_handler(&r->handler, ®ion); if (ret < 0) { kfree(r); return ret; } r->resource.release = release_address_handler; ret = add_client_resource(client, &r->resource, GFP_KERNEL); if (ret < 0) { release_address_handler(client, &r->resource); return ret; } request->handle = r->resource.handle; return 0; }
static int init_iso_resource(struct client *client, struct fw_cdev_allocate_iso_resource *request, int todo) { struct iso_resource_event *e1, *e2; struct iso_resource *r; int ret; if ((request->channels == 0 && request->bandwidth == 0) || request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL || request->bandwidth < 0) return -EINVAL; r = kmalloc(sizeof(*r), GFP_KERNEL); e1 = kmalloc(sizeof(*e1), GFP_KERNEL); e2 = kmalloc(sizeof(*e2), GFP_KERNEL); if (r == NULL || e1 == NULL || e2 == NULL) { ret = -ENOMEM; goto fail; } INIT_DELAYED_WORK(&r->work, iso_resource_work); r->client = client; r->todo = todo; r->generation = -1; r->channels = request->channels; r->bandwidth = request->bandwidth; r->e_alloc = e1; r->e_dealloc = e2; e1->resource.closure = request->closure; e1->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED; e2->resource.closure = request->closure; e2->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED; if (todo == ISO_RES_ALLOC) { r->resource.release = release_iso_resource; ret = add_client_resource(client, &r->resource, GFP_KERNEL); if (ret < 0) goto fail; } else { r->resource.release = NULL; r->resource.handle = -1; schedule_iso_resource(r); } request->handle = r->resource.handle; return 0; fail: kfree(r); kfree(e1); kfree(e2); return ret; }
static int ioctl_add_descriptor(struct client *client, void *buffer) { struct fw_cdev_add_descriptor *request = buffer; struct descriptor_resource *r; int ret; /* Access policy: Allow this ioctl only on local nodes' device files. */ if (!client->device->is_local) return -ENOSYS; if (request->length > 256) return -EINVAL; r = kmalloc(sizeof(*r) + request->length * 4, GFP_KERNEL); if (r == NULL) return -ENOMEM; if (copy_from_user(r->data, u64_to_uptr(request->data), request->length * 4)) { ret = -EFAULT; goto failed; } r->descriptor.length = request->length; r->descriptor.immediate = request->immediate; r->descriptor.key = request->key; r->descriptor.data = r->data; ret = fw_core_add_descriptor(&r->descriptor); if (ret < 0) goto failed; r->resource.release = release_descriptor; ret = add_client_resource(client, &r->resource, GFP_KERNEL); if (ret < 0) { fw_core_remove_descriptor(&r->descriptor); goto failed; } request->handle = r->resource.handle; return 0; failed: kfree(r); return ret; }
static int init_request(struct client *client, struct fw_cdev_send_request *request, int destination_id, int speed) { struct outbound_transaction_event *e; int ret; if (request->tcode != TCODE_STREAM_DATA && (request->length > 4096 || request->length > 512 << speed)) return -EIO; e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL); if (e == NULL) return -ENOMEM; e->client = client; e->response.length = request->length; e->response.closure = request->closure; if (request->data && copy_from_user(e->response.data, u64_to_uptr(request->data), request->length)) { ret = -EFAULT; goto failed; } e->r.resource.release = release_transaction; ret = add_client_resource(client, &e->r.resource, GFP_KERNEL); if (ret < 0) goto failed; /* Get a reference for the transaction callback */ client_get(client); fw_send_request(client->device->card, &e->r.transaction, request->tcode, destination_id, request->generation, speed, request->offset, e->response.data, request->length, complete_transaction, e); return 0; failed: kfree(e); return ret; }
static void handle_request(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, int generation, int speed, unsigned long long offset, void *payload, size_t length, void *callback_data) { struct address_handler_resource *handler = callback_data; struct inbound_transaction_resource *r; struct inbound_transaction_event *e; int ret; r = kmalloc(sizeof(*r), GFP_ATOMIC); e = kmalloc(sizeof(*e), GFP_ATOMIC); if (r == NULL || e == NULL) goto failed; r->request = request; r->data = payload; r->length = length; r->resource.release = release_request; ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC); if (ret < 0) goto failed; e->request.type = FW_CDEV_EVENT_REQUEST; e->request.tcode = tcode; e->request.offset = offset; e->request.length = length; e->request.handle = r->resource.handle; e->request.closure = handler->closure; queue_event(handler->client, &e->event, &e->request, sizeof(e->request), payload, length); return; failed: kfree(r); kfree(e); fw_send_response(card, request, RCODE_CONFLICT_ERROR); }