aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/fw-cdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/fw-cdev.c')
-rw-r--r--drivers/firewire/fw-cdev.c67
1 files changed, 54 insertions, 13 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index a227853aa1e2..08fe68d34f32 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -121,14 +121,15 @@ struct iso_resource {
121 struct client *client; 121 struct client *client;
122 /* Schedule work and access todo only with client->lock held. */ 122 /* Schedule work and access todo only with client->lock held. */
123 struct delayed_work work; 123 struct delayed_work work;
124 enum {ISO_RES_ALLOC, ISO_RES_REALLOC, ISO_RES_DEALLOC,} todo; 124 enum {ISO_RES_ALLOC, ISO_RES_REALLOC, ISO_RES_DEALLOC,
125 ISO_RES_ALLOC_ONCE, ISO_RES_DEALLOC_ONCE,} todo;
125 int generation; 126 int generation;
126 u64 channels; 127 u64 channels;
127 s32 bandwidth; 128 s32 bandwidth;
128 struct iso_resource_event *e_alloc, *e_dealloc; 129 struct iso_resource_event *e_alloc, *e_dealloc;
129}; 130};
130 131
131static void schedule_iso_resource(struct iso_resource *); 132static int schedule_iso_resource(struct iso_resource *);
132static void release_iso_resource(struct client *, struct client_resource *); 133static void release_iso_resource(struct client *, struct client_resource *);
133 134
134/* 135/*
@@ -1033,7 +1034,9 @@ static void iso_resource_work(struct work_struct *work)
1033 skip = todo == ISO_RES_REALLOC && 1034 skip = todo == ISO_RES_REALLOC &&
1034 r->generation == generation; 1035 r->generation == generation;
1035 } 1036 }
1036 free = todo == ISO_RES_DEALLOC; 1037 free = todo == ISO_RES_DEALLOC ||
1038 todo == ISO_RES_ALLOC_ONCE ||
1039 todo == ISO_RES_DEALLOC_ONCE;
1037 r->generation = generation; 1040 r->generation = generation;
1038 spin_unlock_irq(&client->lock); 1041 spin_unlock_irq(&client->lock);
1039 1042
@@ -1044,7 +1047,9 @@ static void iso_resource_work(struct work_struct *work)
1044 1047
1045 fw_iso_resource_manage(client->device->card, generation, 1048 fw_iso_resource_manage(client->device->card, generation,
1046 r->channels, &channel, &bandwidth, 1049 r->channels, &channel, &bandwidth,
1047 todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC); 1050 todo == ISO_RES_ALLOC ||
1051 todo == ISO_RES_REALLOC ||
1052 todo == ISO_RES_ALLOC_ONCE);
1048 /* 1053 /*
1049 * Is this generation outdated already? As long as this resource sticks 1054 * Is this generation outdated already? As long as this resource sticks
1050 * in the idr, it will be scheduled again for a newer generation or at 1055 * in the idr, it will be scheduled again for a newer generation or at
@@ -1082,7 +1087,7 @@ static void iso_resource_work(struct work_struct *work)
1082 if (todo == ISO_RES_REALLOC && success) 1087 if (todo == ISO_RES_REALLOC && success)
1083 goto out; 1088 goto out;
1084 1089
1085 if (todo == ISO_RES_ALLOC) { 1090 if (todo == ISO_RES_ALLOC || todo == ISO_RES_ALLOC_ONCE) {
1086 e = r->e_alloc; 1091 e = r->e_alloc;
1087 r->e_alloc = NULL; 1092 r->e_alloc = NULL;
1088 } else { 1093 } else {
@@ -1106,10 +1111,17 @@ static void iso_resource_work(struct work_struct *work)
1106 client_put(client); 1111 client_put(client);
1107} 1112}
1108 1113
1109static void schedule_iso_resource(struct iso_resource *r) 1114static int schedule_iso_resource(struct iso_resource *r)
1110{ 1115{
1111 if (schedule_delayed_work(&r->work, 0)) 1116 int scheduled;
1112 client_get(r->client); 1117
1118 client_get(r->client);
1119
1120 scheduled = schedule_delayed_work(&r->work, 0);
1121 if (!scheduled)
1122 client_put(r->client);
1123
1124 return scheduled;
1113} 1125}
1114 1126
1115static void release_iso_resource(struct client *client, 1127static void release_iso_resource(struct client *client,
@@ -1124,9 +1136,9 @@ static void release_iso_resource(struct client *client,
1124 spin_unlock_irq(&client->lock); 1136 spin_unlock_irq(&client->lock);
1125} 1137}
1126 1138
1127static int ioctl_allocate_iso_resource(struct client *client, void *buffer) 1139static int init_iso_resource(struct client *client,
1140 struct fw_cdev_allocate_iso_resource *request, int todo)
1128{ 1141{
1129 struct fw_cdev_allocate_iso_resource *request = buffer;
1130 struct iso_resource_event *e1, *e2; 1142 struct iso_resource_event *e1, *e2;
1131 struct iso_resource *r; 1143 struct iso_resource *r;
1132 int ret; 1144 int ret;
@@ -1146,7 +1158,7 @@ static int ioctl_allocate_iso_resource(struct client *client, void *buffer)
1146 1158
1147 INIT_DELAYED_WORK(&r->work, iso_resource_work); 1159 INIT_DELAYED_WORK(&r->work, iso_resource_work);
1148 r->client = client; 1160 r->client = client;
1149 r->todo = ISO_RES_ALLOC; 1161 r->todo = todo;
1150 r->generation = -1; 1162 r->generation = -1;
1151 r->channels = request->channels; 1163 r->channels = request->channels;
1152 r->bandwidth = request->bandwidth; 1164 r->bandwidth = request->bandwidth;
@@ -1158,8 +1170,14 @@ static int ioctl_allocate_iso_resource(struct client *client, void *buffer)
1158 e2->resource.closure = request->closure; 1170 e2->resource.closure = request->closure;
1159 e2->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED; 1171 e2->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
1160 1172
1161 r->resource.release = release_iso_resource; 1173 if (todo == ISO_RES_ALLOC) {
1162 ret = add_client_resource(client, &r->resource, GFP_KERNEL); 1174 r->resource.release = release_iso_resource;
1175 ret = add_client_resource(client, &r->resource, GFP_KERNEL);
1176 } else {
1177 r->resource.release = NULL;
1178 r->resource.handle = -1;
1179 ret = schedule_iso_resource(r) ? 0 : -ENOMEM;
1180 }
1163 if (ret < 0) 1181 if (ret < 0)
1164 goto fail; 1182 goto fail;
1165 request->handle = r->resource.handle; 1183 request->handle = r->resource.handle;
@@ -1173,6 +1191,13 @@ static int ioctl_allocate_iso_resource(struct client *client, void *buffer)
1173 return ret; 1191 return ret;
1174} 1192}
1175 1193
1194static int ioctl_allocate_iso_resource(struct client *client, void *buffer)
1195{
1196 struct fw_cdev_allocate_iso_resource *request = buffer;
1197
1198 return init_iso_resource(client, request, ISO_RES_ALLOC);
1199}
1200
1176static int ioctl_deallocate_iso_resource(struct client *client, void *buffer) 1201static int ioctl_deallocate_iso_resource(struct client *client, void *buffer)
1177{ 1202{
1178 struct fw_cdev_deallocate *request = buffer; 1203 struct fw_cdev_deallocate *request = buffer;
@@ -1181,6 +1206,20 @@ static int ioctl_deallocate_iso_resource(struct client *client, void *buffer)
1181 release_iso_resource, NULL); 1206 release_iso_resource, NULL);
1182} 1207}
1183 1208
1209static int ioctl_allocate_iso_resource_once(struct client *client, void *buffer)
1210{
1211 struct fw_cdev_allocate_iso_resource *request = buffer;
1212
1213 return init_iso_resource(client, request, ISO_RES_ALLOC_ONCE);
1214}
1215
1216static int ioctl_deallocate_iso_resource_once(struct client *client, void *buffer)
1217{
1218 struct fw_cdev_allocate_iso_resource *request = buffer;
1219
1220 return init_iso_resource(client, request, ISO_RES_DEALLOC_ONCE);
1221}
1222
1184static int (* const ioctl_handlers[])(struct client *client, void *buffer) = { 1223static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
1185 ioctl_get_info, 1224 ioctl_get_info,
1186 ioctl_send_request, 1225 ioctl_send_request,
@@ -1197,6 +1236,8 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
1197 ioctl_get_cycle_timer, 1236 ioctl_get_cycle_timer,
1198 ioctl_allocate_iso_resource, 1237 ioctl_allocate_iso_resource,
1199 ioctl_deallocate_iso_resource, 1238 ioctl_deallocate_iso_resource,
1239 ioctl_allocate_iso_resource_once,
1240 ioctl_deallocate_iso_resource_once,
1200}; 1241};
1201 1242
1202static int dispatch_ioctl(struct client *client, 1243static int dispatch_ioctl(struct client *client,