402 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Function Control Protocol (IEC 61883-1) helper functions4 *5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>6 */7 8#include <linux/device.h>9#include <linux/firewire.h>10#include <linux/firewire-constants.h>11#include <linux/list.h>12#include <linux/module.h>13#include <linux/slab.h>14#include <linux/sched.h>15#include <linux/spinlock.h>16#include <linux/wait.h>17#include <linux/delay.h>18#include "fcp.h"19#include "lib.h"20#include "amdtp-stream.h"21 22#define CTS_AVC 0x0023 24#define ERROR_RETRIES 325#define ERROR_DELAY_MS 526#define FCP_TIMEOUT_MS 12527 28int avc_general_set_sig_fmt(struct fw_unit *unit, unsigned int rate,29 enum avc_general_plug_dir dir,30 unsigned short pid)31{32 unsigned int sfc;33 u8 *buf;34 bool flag;35 int err;36 37 flag = false;38 for (sfc = 0; sfc < CIP_SFC_COUNT; sfc++) {39 if (amdtp_rate_table[sfc] == rate) {40 flag = true;41 break;42 }43 }44 if (!flag)45 return -EINVAL;46 47 buf = kzalloc(8, GFP_KERNEL);48 if (buf == NULL)49 return -ENOMEM;50 51 buf[0] = 0x00; /* AV/C CONTROL */52 buf[1] = 0xff; /* UNIT */53 if (dir == AVC_GENERAL_PLUG_DIR_IN)54 buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */55 else56 buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */57 buf[3] = 0xff & pid; /* plug id */58 buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */59 buf[5] = 0x07 & sfc; /* FDF-hi. AM824, frequency */60 buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used)*/61 buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */62 63 /* do transaction and check buf[1-5] are the same against command */64 err = fcp_avc_transaction(unit, buf, 8, buf, 8,65 BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5));66 if (err < 0)67 ;68 else if (err < 8)69 err = -EIO;70 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */71 err = -ENOSYS;72 else if (buf[0] == 0x0a) /* REJECTED */73 err = -EINVAL;74 if (err < 0)75 goto end;76 77 err = 0;78end:79 kfree(buf);80 return err;81}82EXPORT_SYMBOL(avc_general_set_sig_fmt);83 84int avc_general_get_sig_fmt(struct fw_unit *unit, unsigned int *rate,85 enum avc_general_plug_dir dir,86 unsigned short pid)87{88 unsigned int sfc;89 u8 *buf;90 int err;91 92 buf = kzalloc(8, GFP_KERNEL);93 if (buf == NULL)94 return -ENOMEM;95 96 buf[0] = 0x01; /* AV/C STATUS */97 buf[1] = 0xff; /* Unit */98 if (dir == AVC_GENERAL_PLUG_DIR_IN)99 buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */100 else101 buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */102 buf[3] = 0xff & pid; /* plug id */103 buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */104 buf[5] = 0xff; /* FDF-hi. AM824, frequency */105 buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used) */106 buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */107 108 /* do transaction and check buf[1-4] are the same against command */109 err = fcp_avc_transaction(unit, buf, 8, buf, 8,110 BIT(1) | BIT(2) | BIT(3) | BIT(4));111 if (err < 0)112 ;113 else if (err < 8)114 err = -EIO;115 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */116 err = -ENOSYS;117 else if (buf[0] == 0x0a) /* REJECTED */118 err = -EINVAL;119 else if (buf[0] == 0x0b) /* IN TRANSITION */120 err = -EAGAIN;121 if (err < 0)122 goto end;123 124 /* check sfc field and pick up rate */125 sfc = 0x07 & buf[5];126 if (sfc >= CIP_SFC_COUNT) {127 err = -EAGAIN; /* also in transition */128 goto end;129 }130 131 *rate = amdtp_rate_table[sfc];132 err = 0;133end:134 kfree(buf);135 return err;136}137EXPORT_SYMBOL(avc_general_get_sig_fmt);138 139int avc_general_get_plug_info(struct fw_unit *unit, unsigned int subunit_type,140 unsigned int subunit_id, unsigned int subfunction,141 u8 info[AVC_PLUG_INFO_BUF_BYTES])142{143 u8 *buf;144 int err;145 146 /* extended subunit in spec.4.2 is not supported */147 if ((subunit_type == 0x1E) || (subunit_id == 5))148 return -EINVAL;149 150 buf = kzalloc(8, GFP_KERNEL);151 if (buf == NULL)152 return -ENOMEM;153 154 buf[0] = 0x01; /* AV/C STATUS */155 /* UNIT or Subunit, Functionblock */156 buf[1] = ((subunit_type & 0x1f) << 3) | (subunit_id & 0x7);157 buf[2] = 0x02; /* PLUG INFO */158 buf[3] = 0xff & subfunction;159 160 err = fcp_avc_transaction(unit, buf, 8, buf, 8, BIT(1) | BIT(2));161 if (err < 0)162 ;163 else if (err < 8)164 err = -EIO;165 else if (buf[0] == 0x08) /* NOT IMPLEMENTED */166 err = -ENOSYS;167 else if (buf[0] == 0x0a) /* REJECTED */168 err = -EINVAL;169 else if (buf[0] == 0x0b) /* IN TRANSITION */170 err = -EAGAIN;171 if (err < 0)172 goto end;173 174 info[0] = buf[4];175 info[1] = buf[5];176 info[2] = buf[6];177 info[3] = buf[7];178 179 err = 0;180end:181 kfree(buf);182 return err;183}184EXPORT_SYMBOL(avc_general_get_plug_info);185 186static DEFINE_SPINLOCK(transactions_lock);187static LIST_HEAD(transactions);188 189enum fcp_state {190 STATE_PENDING,191 STATE_BUS_RESET,192 STATE_COMPLETE,193 STATE_DEFERRED,194};195 196struct fcp_transaction {197 struct list_head list;198 struct fw_unit *unit;199 void *response_buffer;200 unsigned int response_size;201 unsigned int response_match_bytes;202 enum fcp_state state;203 wait_queue_head_t wait;204 bool deferrable;205};206 207/**208 * fcp_avc_transaction - send an AV/C command and wait for its response209 * @unit: a unit on the target device210 * @command: a buffer containing the command frame; must be DMA-able211 * @command_size: the size of @command212 * @response: a buffer for the response frame213 * @response_size: the maximum size of @response214 * @response_match_bytes: a bitmap specifying the bytes used to detect the215 * correct response frame216 *217 * This function sends a FCP command frame to the target and waits for the218 * corresponding response frame to be returned.219 *220 * Because it is possible for multiple FCP transactions to be active at the221 * same time, the correct response frame is detected by the value of certain222 * bytes. These bytes must be set in @response before calling this function,223 * and the corresponding bits must be set in @response_match_bytes.224 *225 * @command and @response can point to the same buffer.226 *227 * Returns the actual size of the response frame, or a negative error code.228 */229int fcp_avc_transaction(struct fw_unit *unit,230 const void *command, unsigned int command_size,231 void *response, unsigned int response_size,232 unsigned int response_match_bytes)233{234 struct fcp_transaction t;235 int tcode, ret, tries = 0;236 237 t.unit = unit;238 t.response_buffer = response;239 t.response_size = response_size;240 t.response_match_bytes = response_match_bytes;241 t.state = STATE_PENDING;242 init_waitqueue_head(&t.wait);243 t.deferrable = (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03);244 245 spin_lock_irq(&transactions_lock);246 list_add_tail(&t.list, &transactions);247 spin_unlock_irq(&transactions_lock);248 249 for (;;) {250 tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST251 : TCODE_WRITE_BLOCK_REQUEST;252 ret = snd_fw_transaction(t.unit, tcode,253 CSR_REGISTER_BASE + CSR_FCP_COMMAND,254 (void *)command, command_size, 0);255 if (ret < 0)256 break;257deferred:258 wait_event_timeout(t.wait, t.state != STATE_PENDING,259 msecs_to_jiffies(FCP_TIMEOUT_MS));260 261 if (t.state == STATE_DEFERRED) {262 /*263 * 'AV/C General Specification' define no time limit264 * on command completion once an INTERIM response has265 * been sent. but we promise to finish this function266 * for a caller. Here we use FCP_TIMEOUT_MS for next267 * interval. This is not in the specification.268 */269 t.state = STATE_PENDING;270 goto deferred;271 } else if (t.state == STATE_COMPLETE) {272 ret = t.response_size;273 break;274 } else if (t.state == STATE_BUS_RESET) {275 msleep(ERROR_DELAY_MS);276 } else if (++tries >= ERROR_RETRIES) {277 dev_err(&t.unit->device, "FCP command timed out\n");278 ret = -EIO;279 break;280 }281 }282 283 spin_lock_irq(&transactions_lock);284 list_del(&t.list);285 spin_unlock_irq(&transactions_lock);286 287 return ret;288}289EXPORT_SYMBOL(fcp_avc_transaction);290 291/**292 * fcp_bus_reset - inform the target handler about a bus reset293 * @unit: the unit that might be used by fcp_avc_transaction()294 *295 * This function must be called from the driver's .update handler to inform296 * the FCP transaction handler that a bus reset has happened. Any pending FCP297 * transactions are retried.298 */299void fcp_bus_reset(struct fw_unit *unit)300{301 struct fcp_transaction *t;302 303 spin_lock_irq(&transactions_lock);304 list_for_each_entry(t, &transactions, list) {305 if (t->unit == unit &&306 (t->state == STATE_PENDING ||307 t->state == STATE_DEFERRED)) {308 t->state = STATE_BUS_RESET;309 wake_up(&t->wait);310 }311 }312 spin_unlock_irq(&transactions_lock);313}314EXPORT_SYMBOL(fcp_bus_reset);315 316/* checks whether the response matches the masked bytes in response_buffer */317static bool is_matching_response(struct fcp_transaction *transaction,318 const void *response, size_t length)319{320 const u8 *p1, *p2;321 unsigned int mask, i;322 323 p1 = response;324 p2 = transaction->response_buffer;325 mask = transaction->response_match_bytes;326 327 for (i = 0; ; ++i) {328 if ((mask & 1) && p1[i] != p2[i])329 return false;330 mask >>= 1;331 if (!mask)332 return true;333 if (--length == 0)334 return false;335 }336}337 338static void fcp_response(struct fw_card *card, struct fw_request *request,339 int tcode, int destination, int source,340 int generation, unsigned long long offset,341 void *data, size_t length, void *callback_data)342{343 struct fcp_transaction *t;344 unsigned long flags;345 346 if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC)347 return;348 349 spin_lock_irqsave(&transactions_lock, flags);350 list_for_each_entry(t, &transactions, list) {351 struct fw_device *device = fw_parent_device(t->unit);352 if (device->card != card ||353 device->generation != generation)354 continue;355 smp_rmb(); /* node_id vs. generation */356 if (device->node_id != source)357 continue;358 359 if (t->state == STATE_PENDING &&360 is_matching_response(t, data, length)) {361 if (t->deferrable && *(const u8 *)data == 0x0f) {362 t->state = STATE_DEFERRED;363 } else {364 t->state = STATE_COMPLETE;365 t->response_size = min_t(unsigned int, length,366 t->response_size);367 memcpy(t->response_buffer, data,368 t->response_size);369 }370 wake_up(&t->wait);371 }372 }373 spin_unlock_irqrestore(&transactions_lock, flags);374}375 376static struct fw_address_handler response_register_handler = {377 .length = 0x200,378 .address_callback = fcp_response,379};380 381static int __init fcp_module_init(void)382{383 static const struct fw_address_region response_register_region = {384 .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE,385 .end = CSR_REGISTER_BASE + CSR_FCP_END,386 };387 388 fw_core_add_address_handler(&response_register_handler,389 &response_register_region);390 391 return 0;392}393 394static void __exit fcp_module_exit(void)395{396 WARN_ON(!list_empty(&transactions));397 fw_core_remove_address_handler(&response_register_handler);398}399 400module_init(fcp_module_init);401module_exit(fcp_module_exit);402