From c58e16442b16f85d76808209c4aa7c37adc62de4 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 11 Jan 2009 22:45:02 +0100 Subject: [PATCH] Use new iso resource allocation ioctls This allows raw1394_bandwidth_modify() and raw1394_channel_modify() to work on juju without write access to the IRM's character device file. If either the build-time requirement of firewire-cdev header ABI >= v.2 or the runtime requirement of firewire-core ABI >= v.2 is not satisfied, the code falls back to transactions to the IRM as before. Signed-off-by: Stefan Richter --- src/dispatch.c | 10 ++++-- src/fw.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/fw.h | 7 ++++ 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/dispatch.c b/src/dispatch.c index 49ceca2..d202424 100644 --- a/src/dispatch.c +++ b/src/dispatch.c @@ -541,7 +541,10 @@ int raw1394_bandwidth_modify (raw1394handle_t handle, unsigned int bandwidth, errno = EINVAL; return -1; } - return ieee1394_bandwidth_modify(handle, bandwidth, mode); + if (handle->is_fw) + return fw_bandwidth_modify(handle, bandwidth, mode); + else + return ieee1394_bandwidth_modify(handle, bandwidth, mode); } int raw1394_channel_modify (raw1394handle_t handle, unsigned int channel, @@ -551,7 +554,10 @@ int raw1394_channel_modify (raw1394handle_t handle, unsigned int channel, errno = EINVAL; return -1; } - return ieee1394_channel_modify(handle, channel, mode); + if (handle->is_fw) + return fw_channel_modify(handle, channel, mode); + else + return ieee1394_channel_modify(handle, channel, mode); } int raw1394_iso_xmit_init(raw1394handle_t handle, diff --git a/src/fw.c b/src/fw.c index 9b33422..ae09fed 100644 --- a/src/fw.c +++ b/src/fw.c @@ -294,6 +294,13 @@ handle_device_event(raw1394handle_t handle, ac = u64_to_ptr(u->request.closure); return ac->callback(handle, ac, &u->request, i); +#ifdef FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED /* added in kernel 2.6.30 */ + case FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED: + case FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED: + memcpy(u64_to_ptr(u->iso_resource.closure), u, + sizeof u->iso_resource); + return 0; +#endif default: case FW_CDEV_EVENT_ISO_INTERRUPT: /* Never happens. */ @@ -631,6 +638,7 @@ int fw_set_port(fw_handle_t handle, int port) handle->local_device = &handle->devices[i]; handle->generation = reset.generation; + handle->abi_version = get_info.version; i++; } @@ -1324,3 +1332,90 @@ fw_get_config_rom(fw_handle_t handle, quadlet_t *buffer, return 0; } + +#ifdef FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE /* added in kernel 2.6.30 */ + +static int +iso_resource_modify(raw1394handle_t handle, unsigned int bandwidth, + int channel, enum raw1394_modify_mode mode) +{ + fw_handle_t fwhandle = handle->mode.fw; + struct fw_cdev_allocate_iso_resource resource; + struct fw_cdev_event_iso_resource event; + int ioctl_nr; + int err; + + if (channel > 63) { + errno = EINVAL; + return -1; + } + + event.closure = 0; + event.channel = -1; + event.bandwidth = 0; + + resource.closure = ptr_to_u64(&event); + resource.channels = channel >= 0 ? 1ULL << channel : 0; + resource.bandwidth = bandwidth; + + ioctl_nr = mode == RAW1394_MODIFY_ALLOC ? + FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE : + FW_CDEV_IOC_DEALLOCATE_ISO_RESOURCE_ONCE; + + err = ioctl(fwhandle->ioctl_fd, ioctl_nr, &resource); + + while (err >= 0 && event.closure != resource.closure) + err = fw_loop_iterate(handle); + + if (err < 0) + return err; + + if ((channel >= 0 && event.channel < 0) || + (bandwidth > 0 && event.bandwidth == 0)) { + errno = EIO; + return -1; + } + + return 0; +} + +static inline int abi_v2_available(raw1394handle_t handle) +{ + return handle->mode.fw->abi_version >= 2; +} + +#else + +static inline int +iso_resource_modify(raw1394handle_t handle, unsigned int bandwidth, + int channel, enum raw1394_modify_mode mode) +{ + return -1; +} + +static inline int abi_v2_available(raw1394handle_t handle) +{ + return 0; +} + +#endif /* defined(FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE_ONCE) */ + +int +fw_bandwidth_modify(raw1394handle_t handle, unsigned int bandwidth, + enum raw1394_modify_mode mode) +{ + if (abi_v2_available(handle)) + return iso_resource_modify(handle, bandwidth, -1, mode); + else + return ieee1394_bandwidth_modify(handle, bandwidth, mode); +} + +int +fw_channel_modify(raw1394handle_t handle, unsigned int channel, + enum raw1394_modify_mode mode) +{ + if (abi_v2_available(handle)) + return iso_resource_modify(handle, 0, channel, mode); + else + return ieee1394_channel_modify(handle, channel, mode); +} diff --git a/src/fw.h b/src/fw.h index 2d8ee38..ffd2c05 100644 --- a/src/fw.h +++ b/src/fw.h @@ -81,6 +81,7 @@ struct fw_handle { int port_count; int err; int generation; + int abi_version; void *userdata; int notify_bus_reset; @@ -202,6 +203,12 @@ int fw_update_config_rom(fw_handle_t handle, const quadlet_t *new_rom, int fw_get_config_rom(fw_handle_t handle, quadlet_t *buffer, size_t buffersize, size_t *rom_size, unsigned char *rom_version); +int fw_bandwidth_modify(raw1394handle_t handle, + unsigned int bandwidth, + enum raw1394_modify_mode mode); +int fw_channel_modify(raw1394handle_t handle, + unsigned int channel, + enum raw1394_modify_mode mode); int fw_iso_xmit_start(raw1394handle_t handle, int start_on_cycle, int prebuffer_packets);