mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
firewire updates for v7.2
This update includes the following changes. Unit drivers have been able to assign an arbitrary value in the mod_device entry, which is typed as kernel_ulong_t. While storing the pointer value is legitimate, conversion back to a pointer has been performed without preserving const qualifier. Uwe Kleine-König introduced an union to provide safer and more robust conversions, as part of the ongoing CHERI enhancement work for ARM and RISC-V architectures. This update includes changes in the sound subsystem, since the conversion pattern is widely used in ALSA firewire stack. The userspace applications can request the core function to perform isochronous resource management procedures. Dingsoul reported reference-count leak when these procedures are processed in workqueue contexts. This update refactors the relevant code paths following a divide and conquer approach. Consequently, it became clear that the issue still remain only in the path when userspace applications delegate automatic resource reallocation after bus resets to the core. In practice, the leak is rarely triggered, and a complete fix is still in progress. -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQE66IEYNDXNBPeGKSsLtaWM8LwEwUCajZH8gAKCRCsLtaWM8Lw E5zDAP4gyY1cTSdvIeKay8yYRLqZXtBQTzMeqfSsptLBQgemCAEAwAFP+KKghjU7 sDhDPgBD4bTDvYtjyh/RFb0lkTGV7wA= =3J0T -----END PGP SIGNATURE----- Merge tag 'firewire-updates-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394 Pull firewire updates from Takashi Sakamoto: - firewire drivers have been able to assign an arbitrary value in the mod_device entry, which is typed as kernel_ulong_t. While storing the pointer value is legitimate, conversion back to a pointer has been performed without preserving the const qualifier. Uwe Kleine-König introduced an union to provide safer and more robust conversions, as part of the ongoing CHERI enhancement work for ARM and RISC-V architectures. This includes changes to the sound subsystem, since the conversion pattern is widely used in ALSA firewire stack. - Userspace applications can request the core function to perform isochronous resource management procedures. Dingsoul reported a reference-count leak when these procedures are processed in workqueue contexts. This refactors the relevant code paths following a divide and conquer approach. Consequently, it became clear that the issue still remain in the path when userspace applications delegate automatic resource reallocation after bus resets to the core. In practice, the leak is rarely triggered, and a complete fix is still in progress. * tag 'firewire-updates-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394: firewire: core: Open-code topology list walk firewire: core: cancel using delayed work for iso_resource_once management firewire: core: rename member name for channel mask of isoc resource firewire: core: minor code refactoring for case-dependent parameters of iso resources management ALSA: firewire: Make use of ieee1394's .driver_data_ptr firewire: Simplify storing pointers in device id struct firewire: core: move allocation/reallocation paths into specific branch after isoc resource management in cdev firewire: core: refactor notification type determination after isoc resource management in cdev firewire: core: use switch statement for post-processing of isoc resource management in cdev firewire: core: reduce critical section duration in pre-processing of isoc resource management in cdev firewire: core: code cleanup for iso resource auto creation firewire: core: append _auto suffix for non-once iso resource operations firewire: core: code cleanup to remove old implementations for once operation firewire: core: split functions for iso_resource once operation firewire: core: code refactoring for helper function to fill iso_resource parameters firewire: core: code refactoring to queue work item for iso_resource firewire: core: code refactoring for early return at client resource allocation
This commit is contained in:
commit
aff3ca32f3
|
|
@ -128,19 +128,37 @@ struct descriptor_resource {
|
|||
u32 data[];
|
||||
};
|
||||
|
||||
struct iso_resource {
|
||||
struct iso_resource_params {
|
||||
u64 channels_mask;
|
||||
s32 bandwidth;
|
||||
};
|
||||
|
||||
struct iso_resource_auto {
|
||||
struct client_resource resource;
|
||||
struct client *client;
|
||||
/* Schedule work and access todo only with client->lock held. */
|
||||
struct delayed_work work;
|
||||
enum {ISO_RES_ALLOC, ISO_RES_REALLOC, ISO_RES_DEALLOC,
|
||||
ISO_RES_ALLOC_ONCE, ISO_RES_DEALLOC_ONCE,} todo;
|
||||
enum {
|
||||
ISO_RES_AUTO_ALLOC,
|
||||
ISO_RES_AUTO_REALLOC,
|
||||
ISO_RES_AUTO_DEALLOC,
|
||||
} todo;
|
||||
int generation;
|
||||
u64 channels;
|
||||
s32 bandwidth;
|
||||
struct iso_resource_params params;
|
||||
struct iso_resource_event *e_alloc, *e_dealloc;
|
||||
};
|
||||
|
||||
struct iso_resource_once {
|
||||
struct client *client;
|
||||
struct work_struct work;
|
||||
enum {
|
||||
ISO_RES_ONCE_ALLOC,
|
||||
ISO_RES_ONCE_DEALLOC,
|
||||
} todo;
|
||||
struct iso_resource_params params;
|
||||
struct iso_resource_event *event;
|
||||
};
|
||||
|
||||
static struct address_handler_resource *to_address_handler_resource(struct client_resource *resource)
|
||||
{
|
||||
return container_of(resource, struct address_handler_resource, resource);
|
||||
|
|
@ -156,16 +174,16 @@ static struct descriptor_resource *to_descriptor_resource(struct client_resource
|
|||
return container_of(resource, struct descriptor_resource, resource);
|
||||
}
|
||||
|
||||
static struct iso_resource *to_iso_resource(struct client_resource *resource)
|
||||
static struct iso_resource_auto *to_iso_resource_auto(struct client_resource *resource)
|
||||
{
|
||||
return container_of(resource, struct iso_resource, resource);
|
||||
return container_of(resource, struct iso_resource_auto, resource);
|
||||
}
|
||||
|
||||
static void release_iso_resource(struct client *, struct client_resource *);
|
||||
static void release_iso_resource_auto(struct client *, struct client_resource *);
|
||||
|
||||
static int is_iso_resource(const struct client_resource *resource)
|
||||
static int is_iso_resource_auto(const struct client_resource *resource)
|
||||
{
|
||||
return resource->release == release_iso_resource;
|
||||
return resource->release == release_iso_resource_auto;
|
||||
}
|
||||
|
||||
static void release_transaction(struct client *client,
|
||||
|
|
@ -176,7 +194,7 @@ static int is_outbound_transaction_resource(const struct client_resource *resour
|
|||
return resource->release == release_transaction;
|
||||
}
|
||||
|
||||
static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
|
||||
static void schedule_iso_resource_auto(struct iso_resource_auto *r, unsigned long delay)
|
||||
{
|
||||
client_get(r->client);
|
||||
if (!queue_delayed_work(fw_workqueue, &r->work, delay))
|
||||
|
|
@ -424,8 +442,8 @@ static void queue_bus_reset_event(struct client *client)
|
|||
guard(spinlock_irq)(&client->lock);
|
||||
|
||||
xa_for_each(&client->resource_xa, index, resource) {
|
||||
if (is_iso_resource(resource))
|
||||
schedule_iso_resource(to_iso_resource(resource), 0);
|
||||
if (is_iso_resource_auto(resource))
|
||||
schedule_iso_resource_auto(to_iso_resource_auto(resource), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -507,31 +525,28 @@ static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
|
|||
static int add_client_resource(struct client *client, struct client_resource *resource,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
int ret;
|
||||
|
||||
scoped_guard(spinlock_irqsave, &client->lock) {
|
||||
u32 index;
|
||||
int ret;
|
||||
|
||||
if (client->in_shutdown) {
|
||||
ret = -ECANCELED;
|
||||
if (client->in_shutdown)
|
||||
return -ECANCELED;
|
||||
|
||||
if (gfpflags_allow_blocking(gfp_mask)) {
|
||||
ret = xa_alloc(&client->resource_xa, &index, resource, xa_limit_32b,
|
||||
GFP_NOWAIT);
|
||||
} else {
|
||||
if (gfpflags_allow_blocking(gfp_mask)) {
|
||||
ret = xa_alloc(&client->resource_xa, &index, resource, xa_limit_32b,
|
||||
GFP_NOWAIT);
|
||||
} else {
|
||||
ret = xa_alloc_bh(&client->resource_xa, &index, resource,
|
||||
xa_limit_32b, GFP_NOWAIT);
|
||||
}
|
||||
}
|
||||
if (ret >= 0) {
|
||||
resource->handle = index;
|
||||
client_get(client);
|
||||
if (is_iso_resource(resource))
|
||||
schedule_iso_resource(to_iso_resource(resource), 0);
|
||||
ret = xa_alloc_bh(&client->resource_xa, &index, resource,
|
||||
xa_limit_32b, GFP_NOWAIT);
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
resource->handle = index;
|
||||
client_get(client);
|
||||
}
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int release_client_resource(struct client *client, u32 handle,
|
||||
|
|
@ -1293,83 +1308,106 @@ static int ioctl_get_cycle_timer(struct client *client, union ioctl_arg *arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void iso_resource_work(struct work_struct *work)
|
||||
static int fill_iso_resource_params(struct iso_resource_params *params,
|
||||
struct fw_cdev_allocate_iso_resource *request)
|
||||
{
|
||||
if ((request->channels == 0 && request->bandwidth == 0) ||
|
||||
request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL)
|
||||
return -EINVAL;
|
||||
|
||||
params->channels_mask = request->channels;
|
||||
params->bandwidth = request->bandwidth;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iso_resource_auto_work(struct work_struct *work)
|
||||
{
|
||||
struct iso_resource_event *e;
|
||||
struct iso_resource *r = from_work(r, work, work.work);
|
||||
struct iso_resource_auto *r = from_work(r, work, work.work);
|
||||
struct client *client = r->client;
|
||||
unsigned long index = r->resource.handle;
|
||||
int generation, channel, bandwidth, todo;
|
||||
bool skip, free, success;
|
||||
int current_generation, resource_generation, channel, bandwidth, todo;
|
||||
u64 reset_jiffies;
|
||||
bool free;
|
||||
|
||||
scoped_guard(spinlock_irq, &client->lock) {
|
||||
generation = client->device->generation;
|
||||
reset_jiffies = client->device->card->reset_jiffies;
|
||||
current_generation = client->device->generation;
|
||||
resource_generation = r->generation;
|
||||
r->generation = current_generation;
|
||||
todo = r->todo;
|
||||
}
|
||||
|
||||
switch (todo) {
|
||||
case ISO_RES_AUTO_ALLOC:
|
||||
// Allow 1000ms grace period for other reallocations.
|
||||
if (todo == ISO_RES_ALLOC &&
|
||||
time_is_after_jiffies64(client->device->card->reset_jiffies + secs_to_jiffies(1))) {
|
||||
schedule_iso_resource(r, msecs_to_jiffies(333));
|
||||
skip = true;
|
||||
} else {
|
||||
// We could be called twice within the same generation.
|
||||
skip = todo == ISO_RES_REALLOC &&
|
||||
r->generation == generation;
|
||||
if (time_is_after_jiffies64(reset_jiffies + secs_to_jiffies(1))) {
|
||||
schedule_iso_resource_auto(r, msecs_to_jiffies(333));
|
||||
goto out;
|
||||
}
|
||||
free = todo == ISO_RES_DEALLOC ||
|
||||
todo == ISO_RES_ALLOC_ONCE ||
|
||||
todo == ISO_RES_DEALLOC_ONCE;
|
||||
r->generation = generation;
|
||||
break;
|
||||
case ISO_RES_AUTO_REALLOC:
|
||||
// We could be called twice within the same generation.
|
||||
if (resource_generation == current_generation)
|
||||
goto out;
|
||||
break;
|
||||
case ISO_RES_AUTO_DEALLOC:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (skip)
|
||||
goto out;
|
||||
bandwidth = r->params.bandwidth;
|
||||
|
||||
bandwidth = r->bandwidth;
|
||||
fw_iso_resource_manage(client->device->card, current_generation, r->params.channels_mask,
|
||||
&channel, &bandwidth, todo != ISO_RES_AUTO_DEALLOC);
|
||||
|
||||
fw_iso_resource_manage(client->device->card, generation,
|
||||
r->channels, &channel, &bandwidth,
|
||||
todo == ISO_RES_ALLOC ||
|
||||
todo == ISO_RES_REALLOC ||
|
||||
todo == ISO_RES_ALLOC_ONCE);
|
||||
/*
|
||||
* Is this generation outdated already? As long as this resource sticks
|
||||
* in the xarray, it will be scheduled again for a newer generation or at
|
||||
* shutdown.
|
||||
*/
|
||||
if (channel == -EAGAIN &&
|
||||
(todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC))
|
||||
goto out;
|
||||
|
||||
success = channel >= 0 || bandwidth > 0;
|
||||
|
||||
scoped_guard(spinlock_irq, &client->lock) {
|
||||
// Transit from allocation to reallocation, except if the client
|
||||
// requested deallocation in the meantime.
|
||||
if (r->todo == ISO_RES_ALLOC)
|
||||
r->todo = ISO_RES_REALLOC;
|
||||
// Allocation or reallocation failure? Pull this resource out of the
|
||||
// xarray and prepare for deletion, unless the client is shutting down.
|
||||
if (r->todo == ISO_RES_REALLOC && !success &&
|
||||
!client->in_shutdown &&
|
||||
xa_erase(&client->resource_xa, index)) {
|
||||
client_put(client);
|
||||
free = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (todo == ISO_RES_ALLOC && channel >= 0)
|
||||
r->channels = 1ULL << channel;
|
||||
|
||||
if (todo == ISO_RES_REALLOC && success)
|
||||
goto out;
|
||||
|
||||
if (todo == ISO_RES_ALLOC || todo == ISO_RES_ALLOC_ONCE) {
|
||||
e = r->e_alloc;
|
||||
r->e_alloc = NULL;
|
||||
} else {
|
||||
if (todo == ISO_RES_AUTO_DEALLOC) {
|
||||
free = true;
|
||||
e = r->e_dealloc;
|
||||
r->e_dealloc = NULL;
|
||||
} else {
|
||||
free = false;
|
||||
|
||||
// Is this generation outdated already? As long as this resource sticks in the
|
||||
// xarray, it will be scheduled again for a newer generation or at shutdown.
|
||||
if (channel == -EAGAIN)
|
||||
goto out;
|
||||
|
||||
bool success = channel >= 0 || bandwidth > 0;
|
||||
|
||||
if (!success) {
|
||||
// Allocation or reallocation failure? Pull this resource out of the
|
||||
// xarray and prepare for deletion, unless the client is shutting down.
|
||||
scoped_guard(spinlock_irq, &client->lock) {
|
||||
if (!client->in_shutdown && xa_erase(&client->resource_xa, index)) {
|
||||
client_put(client);
|
||||
free = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (todo == ISO_RES_AUTO_REALLOC) {
|
||||
if (success)
|
||||
goto out;
|
||||
|
||||
// Notify the userspace client of the failure through a deallocation event.
|
||||
e = r->e_dealloc;
|
||||
r->e_dealloc = NULL;
|
||||
} else {
|
||||
// Transit from allocation to reallocation, except if the client requested
|
||||
// deallocation in the meantime.
|
||||
scoped_guard(spinlock_irq, &client->lock)
|
||||
r->todo = ISO_RES_AUTO_REALLOC;
|
||||
|
||||
if (channel >= 0)
|
||||
r->params.channels_mask = BIT_ULL(channel);
|
||||
|
||||
e = r->e_alloc;
|
||||
r->e_alloc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
e->iso_resource.handle = r->resource.handle;
|
||||
e->iso_resource.channel = channel;
|
||||
e->iso_resource.bandwidth = bandwidth;
|
||||
|
|
@ -1387,97 +1425,136 @@ static void iso_resource_work(struct work_struct *work)
|
|||
client_put(client);
|
||||
}
|
||||
|
||||
static void release_iso_resource(struct client *client,
|
||||
struct client_resource *resource)
|
||||
static void release_iso_resource_auto(struct client *client, struct client_resource *resource)
|
||||
{
|
||||
struct iso_resource *r = to_iso_resource(resource);
|
||||
struct iso_resource_auto *r = to_iso_resource_auto(resource);
|
||||
|
||||
guard(spinlock_irq)(&client->lock);
|
||||
|
||||
r->todo = ISO_RES_DEALLOC;
|
||||
schedule_iso_resource(r, 0);
|
||||
r->todo = ISO_RES_AUTO_DEALLOC;
|
||||
schedule_iso_resource_auto(r, 0);
|
||||
}
|
||||
|
||||
static int init_iso_resource(struct client *client,
|
||||
struct fw_cdev_allocate_iso_resource *request, int todo)
|
||||
static int ioctl_allocate_iso_resource(struct client *client, union ioctl_arg *arg)
|
||||
{
|
||||
struct iso_resource_event *e1, *e2;
|
||||
struct iso_resource *r;
|
||||
int ret;
|
||||
struct fw_cdev_allocate_iso_resource *request = &arg->allocate_iso_resource;
|
||||
struct iso_resource_event *e1 __free(kfree) = kmalloc_obj(*e1);
|
||||
struct iso_resource_event *e2 __free(kfree) = kmalloc_obj(*e2);
|
||||
struct iso_resource_auto *r __free(kfree) = kmalloc_obj(*r);
|
||||
int err;
|
||||
|
||||
if ((request->channels == 0 && request->bandwidth == 0) ||
|
||||
request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL)
|
||||
return -EINVAL;
|
||||
if (!r || !e1 || !e2)
|
||||
return -ENOMEM;
|
||||
|
||||
r = kmalloc_obj(*r);
|
||||
e1 = kmalloc_obj(*e1);
|
||||
e2 = kmalloc_obj(*e2);
|
||||
if (r == NULL || e1 == NULL || e2 == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
err = fill_iso_resource_params(&r->params, request);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
INIT_DELAYED_WORK(&r->work, iso_resource_work);
|
||||
INIT_DELAYED_WORK(&r->work, iso_resource_auto_work);
|
||||
r->client = client;
|
||||
r->todo = todo;
|
||||
r->generation = -1;
|
||||
r->channels = request->channels;
|
||||
r->bandwidth = request->bandwidth;
|
||||
r->todo = ISO_RES_AUTO_ALLOC;
|
||||
r->e_alloc = e1;
|
||||
r->e_dealloc = e2;
|
||||
|
||||
e1->iso_resource.closure = request->closure;
|
||||
e1->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
|
||||
e1->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
|
||||
e2->iso_resource.closure = request->closure;
|
||||
e2->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
|
||||
e2->iso_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, 0);
|
||||
}
|
||||
r->resource.release = release_iso_resource_auto;
|
||||
err = add_client_resource(client, &r->resource, GFP_KERNEL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
request->handle = r->resource.handle;
|
||||
|
||||
retain_and_null_ptr(e1);
|
||||
retain_and_null_ptr(e2);
|
||||
schedule_iso_resource_auto(no_free_ptr(r), 0);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
kfree(r);
|
||||
kfree(e1);
|
||||
kfree(e2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ioctl_allocate_iso_resource(struct client *client,
|
||||
union ioctl_arg *arg)
|
||||
{
|
||||
return init_iso_resource(client,
|
||||
&arg->allocate_iso_resource, ISO_RES_ALLOC);
|
||||
}
|
||||
|
||||
static int ioctl_deallocate_iso_resource(struct client *client,
|
||||
union ioctl_arg *arg)
|
||||
{
|
||||
return release_client_resource(client,
|
||||
arg->deallocate.handle, release_iso_resource, NULL);
|
||||
arg->deallocate.handle, release_iso_resource_auto, NULL);
|
||||
}
|
||||
|
||||
#define UNAVAILABLE_HANDLE -1
|
||||
|
||||
static void iso_resource_once_work(struct work_struct *work)
|
||||
{
|
||||
struct iso_resource_once *r = from_work(r, work, work);
|
||||
struct client *client = r->client;
|
||||
struct iso_resource_event *e = r->event;
|
||||
int generation, channel, bandwidth;
|
||||
|
||||
scoped_guard(spinlock_irq, &client->lock)
|
||||
generation = client->device->generation;
|
||||
|
||||
bandwidth = r->params.bandwidth;
|
||||
|
||||
fw_iso_resource_manage(client->device->card, generation, r->params.channels_mask, &channel,
|
||||
&bandwidth, r->todo == ISO_RES_ONCE_ALLOC);
|
||||
|
||||
e->iso_resource.handle = UNAVAILABLE_HANDLE;
|
||||
e->iso_resource.channel = channel;
|
||||
e->iso_resource.bandwidth = bandwidth;
|
||||
|
||||
queue_event(client, &e->event, &e->iso_resource, sizeof(e->iso_resource), NULL, 0);
|
||||
|
||||
cancel_work(&r->work);
|
||||
kfree(r);
|
||||
|
||||
client_put(client);
|
||||
}
|
||||
|
||||
static int init_iso_resource_once(struct client *client,
|
||||
struct fw_cdev_allocate_iso_resource *request, int todo)
|
||||
{
|
||||
struct iso_resource_event *e __free(kfree) = kmalloc_obj(*e);
|
||||
struct iso_resource_once *r __free(kfree) = kmalloc_obj(*r);
|
||||
int err;
|
||||
|
||||
if (!r || !e)
|
||||
return -ENOMEM;
|
||||
|
||||
err = fill_iso_resource_params(&r->params, request);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
INIT_WORK(&r->work, iso_resource_once_work);
|
||||
r->client = client;
|
||||
r->todo = todo;
|
||||
|
||||
if (todo == ISO_RES_ONCE_ALLOC)
|
||||
e->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
|
||||
else
|
||||
e->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
|
||||
e->iso_resource.closure = request->closure;
|
||||
r->event = no_free_ptr(e);
|
||||
|
||||
// Keep the client until work item finishing.
|
||||
client_get(r->client);
|
||||
|
||||
queue_work(fw_workqueue, &no_free_ptr(r)->work);
|
||||
|
||||
request->handle = UNAVAILABLE_HANDLE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioctl_allocate_iso_resource_once(struct client *client,
|
||||
union ioctl_arg *arg)
|
||||
{
|
||||
return init_iso_resource(client,
|
||||
&arg->allocate_iso_resource, ISO_RES_ALLOC_ONCE);
|
||||
return init_iso_resource_once(client, &arg->allocate_iso_resource, ISO_RES_ONCE_ALLOC);
|
||||
}
|
||||
|
||||
static int ioctl_deallocate_iso_resource_once(struct client *client,
|
||||
union ioctl_arg *arg)
|
||||
{
|
||||
return init_iso_resource(client,
|
||||
&arg->allocate_iso_resource, ISO_RES_DEALLOC_ONCE);
|
||||
return init_iso_resource_once(client, &arg->allocate_iso_resource, ISO_RES_ONCE_DEALLOC);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -272,7 +272,9 @@ static void for_each_fw_node(struct fw_card *card, struct fw_node *root,
|
|||
fw_node_get(root);
|
||||
list_add_tail(&root->link, &list);
|
||||
parent = NULL;
|
||||
list_for_each_entry(node, &list, link) {
|
||||
for (node = list_first_entry(&list, typeof(*node), link);
|
||||
!list_entry_is_head(node, &list, link);
|
||||
node = list_next_entry(node, link)) {
|
||||
node->color = card->color;
|
||||
|
||||
for (i = 0; i < node->port_count; i++) {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,10 @@ struct ieee1394_device_id {
|
|||
__u32 model_id;
|
||||
__u32 specifier_id;
|
||||
__u32 version;
|
||||
kernel_ulong_t driver_data;
|
||||
union {
|
||||
kernel_ulong_t driver_data;
|
||||
const void *driver_data_ptr;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *ent
|
|||
snd_dice_detect_formats_t detect_formats;
|
||||
int err;
|
||||
|
||||
if (!entry->driver_data && entry->vendor_id != OUI_SSL) {
|
||||
if (!entry->driver_data_ptr && entry->vendor_id != OUI_SSL) {
|
||||
err = check_dice_category(unit);
|
||||
if (err < 0)
|
||||
return -ENODEV;
|
||||
|
|
@ -164,10 +164,10 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *ent
|
|||
dev_set_drvdata(&unit->device, dice);
|
||||
dice->card = card;
|
||||
|
||||
if (!entry->driver_data)
|
||||
if (!entry->driver_data_ptr)
|
||||
detect_formats = snd_dice_stream_detect_current_formats;
|
||||
else
|
||||
detect_formats = (snd_dice_detect_formats_t)entry->driver_data;
|
||||
detect_formats = entry->driver_data_ptr;
|
||||
|
||||
// Below models are compliant to IEC 61883-1/6 and have no quirk at high sampling transfer
|
||||
// frequency.
|
||||
|
|
@ -255,7 +255,7 @@ static void dice_bus_reset(struct fw_unit *unit)
|
|||
.model_id = (model), \
|
||||
.specifier_id = (vendor), \
|
||||
.version = DICE_INTERFACE, \
|
||||
.driver_data = (kernel_ulong_t)(data), \
|
||||
.driver_data_ptr = (data), \
|
||||
}
|
||||
|
||||
static const struct ieee1394_device_id dice_id_table[] = {
|
||||
|
|
@ -267,7 +267,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_MAUDIO,
|
||||
.model_id = 0x000010,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_extension_formats,
|
||||
.driver_data_ptr = snd_dice_detect_extension_formats,
|
||||
},
|
||||
/* M-Audio Profire 610 has a different value in version field. */
|
||||
{
|
||||
|
|
@ -275,7 +275,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_MAUDIO,
|
||||
.model_id = 0x000011,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_extension_formats,
|
||||
.driver_data_ptr = snd_dice_detect_extension_formats,
|
||||
},
|
||||
/* TC Electronic Konnekt 24D. */
|
||||
{
|
||||
|
|
@ -283,7 +283,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_TCELECTRONIC,
|
||||
.model_id = 0x000020,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
|
||||
.driver_data_ptr = snd_dice_detect_tcelectronic_formats,
|
||||
},
|
||||
/* TC Electronic Konnekt 8. */
|
||||
{
|
||||
|
|
@ -291,7 +291,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_TCELECTRONIC,
|
||||
.model_id = 0x000021,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
|
||||
.driver_data_ptr = snd_dice_detect_tcelectronic_formats,
|
||||
},
|
||||
/* TC Electronic Studio Konnekt 48. */
|
||||
{
|
||||
|
|
@ -299,7 +299,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_TCELECTRONIC,
|
||||
.model_id = 0x000022,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
|
||||
.driver_data_ptr = snd_dice_detect_tcelectronic_formats,
|
||||
},
|
||||
/* TC Electronic Konnekt Live. */
|
||||
{
|
||||
|
|
@ -307,7 +307,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_TCELECTRONIC,
|
||||
.model_id = 0x000023,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
|
||||
.driver_data_ptr = snd_dice_detect_tcelectronic_formats,
|
||||
},
|
||||
/* TC Electronic Desktop Konnekt 6. */
|
||||
{
|
||||
|
|
@ -315,7 +315,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_TCELECTRONIC,
|
||||
.model_id = 0x000024,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
|
||||
.driver_data_ptr = snd_dice_detect_tcelectronic_formats,
|
||||
},
|
||||
/* TC Electronic Impact Twin. */
|
||||
{
|
||||
|
|
@ -323,7 +323,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_TCELECTRONIC,
|
||||
.model_id = 0x000027,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
|
||||
.driver_data_ptr = snd_dice_detect_tcelectronic_formats,
|
||||
},
|
||||
/* TC Electronic Digital Konnekt x32. */
|
||||
{
|
||||
|
|
@ -331,7 +331,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_TCELECTRONIC,
|
||||
.model_id = 0x000030,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
|
||||
.driver_data_ptr = snd_dice_detect_tcelectronic_formats,
|
||||
},
|
||||
/* Alesis iO14/iO26. */
|
||||
{
|
||||
|
|
@ -339,7 +339,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_ALESIS,
|
||||
.model_id = MODEL_ALESIS_IO_BOTH,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_alesis_formats,
|
||||
.driver_data_ptr = snd_dice_detect_alesis_formats,
|
||||
},
|
||||
// Alesis MasterControl.
|
||||
{
|
||||
|
|
@ -347,7 +347,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_ALESIS,
|
||||
.model_id = 0x000002,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_alesis_mastercontrol_formats,
|
||||
.driver_data_ptr = snd_dice_detect_alesis_mastercontrol_formats,
|
||||
},
|
||||
/* Mytek Stereo 192 DSD-DAC. */
|
||||
{
|
||||
|
|
@ -355,7 +355,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
IEEE1394_MATCH_MODEL_ID,
|
||||
.vendor_id = OUI_MYTEK,
|
||||
.model_id = 0x000002,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_mytek_formats,
|
||||
.driver_data_ptr = snd_dice_detect_mytek_formats,
|
||||
},
|
||||
// Solid State Logic, Duende Classic and Mini.
|
||||
// NOTE: each field of GUID in config ROM is not compliant to standard
|
||||
|
|
@ -469,7 +469,7 @@ static const struct ieee1394_device_id dice_id_table[] = {
|
|||
.model_id = OUI_TEAC,
|
||||
.specifier_id = OUI_TEAC,
|
||||
.version = 0x800006,
|
||||
.driver_data = (kernel_ulong_t)snd_dice_detect_teac_formats,
|
||||
.driver_data_ptr = snd_dice_detect_teac_formats,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ static int snd_ff_probe(struct fw_unit *unit, const struct ieee1394_device_id *e
|
|||
init_waitqueue_head(&ff->hwdep_wait);
|
||||
|
||||
ff->unit_version = entry->version;
|
||||
ff->spec = (const struct snd_ff_spec *)entry->driver_data;
|
||||
ff->spec = entry->driver_data_ptr;
|
||||
|
||||
err = snd_ff_transaction_register(ff);
|
||||
if (err < 0)
|
||||
|
|
@ -186,7 +186,7 @@ static const struct ieee1394_device_id snd_ff_id_table[] = {
|
|||
.specifier_id = OUI_RME,
|
||||
.version = SND_FF_UNIT_VERSION_FF800,
|
||||
.model_id = 0x101800,
|
||||
.driver_data = (kernel_ulong_t)&spec_ff800,
|
||||
.driver_data_ptr = &spec_ff800,
|
||||
},
|
||||
/* Fireface 400 */
|
||||
{
|
||||
|
|
@ -198,7 +198,7 @@ static const struct ieee1394_device_id snd_ff_id_table[] = {
|
|||
.specifier_id = OUI_RME,
|
||||
.version = SND_FF_UNIT_VERSION_FF400,
|
||||
.model_id = 0x101800,
|
||||
.driver_data = (kernel_ulong_t)&spec_ff400,
|
||||
.driver_data_ptr = &spec_ff400,
|
||||
},
|
||||
// Fireface UFX.
|
||||
{
|
||||
|
|
@ -210,7 +210,7 @@ static const struct ieee1394_device_id snd_ff_id_table[] = {
|
|||
.specifier_id = OUI_RME,
|
||||
.version = SND_FF_UNIT_VERSION_UFX,
|
||||
.model_id = 0x101800,
|
||||
.driver_data = (kernel_ulong_t)&spec_ufx_802,
|
||||
.driver_data_ptr = &spec_ufx_802,
|
||||
},
|
||||
// Fireface UCX.
|
||||
{
|
||||
|
|
@ -222,7 +222,7 @@ static const struct ieee1394_device_id snd_ff_id_table[] = {
|
|||
.specifier_id = OUI_RME,
|
||||
.version = SND_FF_UNIT_VERSION_UCX,
|
||||
.model_id = 0x101800,
|
||||
.driver_data = (kernel_ulong_t)&spec_ucx,
|
||||
.driver_data_ptr = &spec_ucx,
|
||||
},
|
||||
// Fireface 802.
|
||||
{
|
||||
|
|
@ -234,7 +234,7 @@ static const struct ieee1394_device_id snd_ff_id_table[] = {
|
|||
.specifier_id = OUI_RME,
|
||||
.version = SND_FF_UNIT_VERSION_802,
|
||||
.model_id = 0x101800,
|
||||
.driver_data = (kernel_ulong_t)&spec_ufx_802,
|
||||
.driver_data_ptr = &spec_ufx_802,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ static int motu_probe(struct fw_unit *unit, const struct ieee1394_device_id *ent
|
|||
dev_set_drvdata(&unit->device, motu);
|
||||
motu->card = card;
|
||||
|
||||
motu->spec = (const struct snd_motu_spec *)entry->driver_data;
|
||||
motu->spec = entry->driver_data_ptr;
|
||||
mutex_init(&motu->mutex);
|
||||
spin_lock_init(&motu->lock);
|
||||
init_waitqueue_head(&motu->hwdep_wait);
|
||||
|
|
@ -148,7 +148,7 @@ static void motu_bus_update(struct fw_unit *unit)
|
|||
snd_motu_transaction_reregister(motu);
|
||||
}
|
||||
|
||||
#define SND_MOTU_DEV_ENTRY(model, data) \
|
||||
#define SND_MOTU_DEV_ENTRY(model, data_ptr) \
|
||||
{ \
|
||||
.match_flags = IEEE1394_MATCH_VENDOR_ID | \
|
||||
IEEE1394_MATCH_SPECIFIER_ID | \
|
||||
|
|
@ -156,7 +156,7 @@ static void motu_bus_update(struct fw_unit *unit)
|
|||
.vendor_id = OUI_MOTU, \
|
||||
.specifier_id = OUI_MOTU, \
|
||||
.version = model, \
|
||||
.driver_data = (kernel_ulong_t)data, \
|
||||
.driver_data_ptr = data_ptr, \
|
||||
}
|
||||
|
||||
static const struct ieee1394_device_id motu_id_table[] = {
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ static int name_card(struct snd_oxfw *oxfw, const struct ieee1394_device_id *ent
|
|||
|
||||
/* to apply card definitions */
|
||||
if (entry->vendor_id == VENDOR_GRIFFIN || entry->vendor_id == VENDOR_LACIE) {
|
||||
info = (const struct compat_info *)entry->driver_data;
|
||||
info = entry->driver_data_ptr;
|
||||
d = info->driver_name;
|
||||
v = info->vendor_name;
|
||||
m = info->model_name;
|
||||
|
|
@ -321,7 +321,7 @@ static const struct compat_info lacie_speakers = {
|
|||
.model_id = model, \
|
||||
.specifier_id = SPECIFIER_1394TA, \
|
||||
.version = VERSION_AVC, \
|
||||
.driver_data = (kernel_ulong_t)data, \
|
||||
.driver_data_ptr = data, \
|
||||
}
|
||||
|
||||
static const struct ieee1394_device_id oxfw_id_table[] = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user