1*da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 231ef9134SClemens Ladisch /* 331ef9134SClemens Ladisch * Function Control Protocol (IEC 61883-1) helper functions 431ef9134SClemens Ladisch * 531ef9134SClemens Ladisch * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 631ef9134SClemens Ladisch */ 731ef9134SClemens Ladisch 831ef9134SClemens Ladisch #include <linux/device.h> 931ef9134SClemens Ladisch #include <linux/firewire.h> 1031ef9134SClemens Ladisch #include <linux/firewire-constants.h> 1131ef9134SClemens Ladisch #include <linux/list.h> 1231ef9134SClemens Ladisch #include <linux/module.h> 131017abedSTakashi Sakamoto #include <linux/slab.h> 1431ef9134SClemens Ladisch #include <linux/sched.h> 1531ef9134SClemens Ladisch #include <linux/spinlock.h> 1631ef9134SClemens Ladisch #include <linux/wait.h> 175de0ee57SStephen Rothwell #include <linux/delay.h> 1831ef9134SClemens Ladisch #include "fcp.h" 1931ef9134SClemens Ladisch #include "lib.h" 20d67c46b9STakashi Sakamoto #include "amdtp-stream.h" 2131ef9134SClemens Ladisch 2231ef9134SClemens Ladisch #define CTS_AVC 0x00 2331ef9134SClemens Ladisch 2431ef9134SClemens Ladisch #define ERROR_RETRIES 3 2531ef9134SClemens Ladisch #define ERROR_DELAY_MS 5 2631ef9134SClemens Ladisch #define FCP_TIMEOUT_MS 125 2731ef9134SClemens Ladisch 281017abedSTakashi Sakamoto int avc_general_set_sig_fmt(struct fw_unit *unit, unsigned int rate, 291017abedSTakashi Sakamoto enum avc_general_plug_dir dir, 301017abedSTakashi Sakamoto unsigned short pid) 311017abedSTakashi Sakamoto { 321017abedSTakashi Sakamoto unsigned int sfc; 331017abedSTakashi Sakamoto u8 *buf; 341017abedSTakashi Sakamoto bool flag; 351017abedSTakashi Sakamoto int err; 361017abedSTakashi Sakamoto 371017abedSTakashi Sakamoto flag = false; 381017abedSTakashi Sakamoto for (sfc = 0; sfc < CIP_SFC_COUNT; sfc++) { 391017abedSTakashi Sakamoto if (amdtp_rate_table[sfc] == rate) { 401017abedSTakashi Sakamoto flag = true; 411017abedSTakashi Sakamoto break; 421017abedSTakashi Sakamoto } 431017abedSTakashi Sakamoto } 441017abedSTakashi Sakamoto if (!flag) 451017abedSTakashi Sakamoto return -EINVAL; 461017abedSTakashi Sakamoto 471017abedSTakashi Sakamoto buf = kzalloc(8, GFP_KERNEL); 481017abedSTakashi Sakamoto if (buf == NULL) 491017abedSTakashi Sakamoto return -ENOMEM; 501017abedSTakashi Sakamoto 511017abedSTakashi Sakamoto buf[0] = 0x00; /* AV/C CONTROL */ 521017abedSTakashi Sakamoto buf[1] = 0xff; /* UNIT */ 531017abedSTakashi Sakamoto if (dir == AVC_GENERAL_PLUG_DIR_IN) 541017abedSTakashi Sakamoto buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */ 551017abedSTakashi Sakamoto else 561017abedSTakashi Sakamoto buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */ 571017abedSTakashi Sakamoto buf[3] = 0xff & pid; /* plug id */ 581017abedSTakashi Sakamoto buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */ 591017abedSTakashi Sakamoto buf[5] = 0x07 & sfc; /* FDF-hi. AM824, frequency */ 601017abedSTakashi Sakamoto buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used)*/ 611017abedSTakashi Sakamoto buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */ 621017abedSTakashi Sakamoto 631017abedSTakashi Sakamoto /* do transaction and check buf[1-5] are the same against command */ 641017abedSTakashi Sakamoto err = fcp_avc_transaction(unit, buf, 8, buf, 8, 651017abedSTakashi Sakamoto BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5)); 667e1621deSTakashi Sakamoto if (err < 0) 677e1621deSTakashi Sakamoto ; 687e1621deSTakashi Sakamoto else if (err < 8) 691017abedSTakashi Sakamoto err = -EIO; 701017abedSTakashi Sakamoto else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 711017abedSTakashi Sakamoto err = -ENOSYS; 721017abedSTakashi Sakamoto else if (buf[0] == 0x0a) /* REJECTED */ 731017abedSTakashi Sakamoto err = -EINVAL; 741017abedSTakashi Sakamoto if (err < 0) 751017abedSTakashi Sakamoto goto end; 761017abedSTakashi Sakamoto 771017abedSTakashi Sakamoto err = 0; 781017abedSTakashi Sakamoto end: 791017abedSTakashi Sakamoto kfree(buf); 801017abedSTakashi Sakamoto return err; 811017abedSTakashi Sakamoto } 821017abedSTakashi Sakamoto EXPORT_SYMBOL(avc_general_set_sig_fmt); 831017abedSTakashi Sakamoto 841017abedSTakashi Sakamoto int avc_general_get_sig_fmt(struct fw_unit *unit, unsigned int *rate, 851017abedSTakashi Sakamoto enum avc_general_plug_dir dir, 861017abedSTakashi Sakamoto unsigned short pid) 871017abedSTakashi Sakamoto { 881017abedSTakashi Sakamoto unsigned int sfc; 891017abedSTakashi Sakamoto u8 *buf; 901017abedSTakashi Sakamoto int err; 911017abedSTakashi Sakamoto 921017abedSTakashi Sakamoto buf = kzalloc(8, GFP_KERNEL); 931017abedSTakashi Sakamoto if (buf == NULL) 941017abedSTakashi Sakamoto return -ENOMEM; 951017abedSTakashi Sakamoto 961017abedSTakashi Sakamoto buf[0] = 0x01; /* AV/C STATUS */ 971017abedSTakashi Sakamoto buf[1] = 0xff; /* Unit */ 981017abedSTakashi Sakamoto if (dir == AVC_GENERAL_PLUG_DIR_IN) 991017abedSTakashi Sakamoto buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */ 1001017abedSTakashi Sakamoto else 1011017abedSTakashi Sakamoto buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */ 1021017abedSTakashi Sakamoto buf[3] = 0xff & pid; /* plug id */ 1031017abedSTakashi Sakamoto buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */ 1041017abedSTakashi Sakamoto buf[5] = 0xff; /* FDF-hi. AM824, frequency */ 1051017abedSTakashi Sakamoto buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used) */ 1061017abedSTakashi Sakamoto buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */ 1071017abedSTakashi Sakamoto 1081017abedSTakashi Sakamoto /* do transaction and check buf[1-4] are the same against command */ 1091017abedSTakashi Sakamoto err = fcp_avc_transaction(unit, buf, 8, buf, 8, 1101017abedSTakashi Sakamoto BIT(1) | BIT(2) | BIT(3) | BIT(4)); 1117e1621deSTakashi Sakamoto if (err < 0) 1127e1621deSTakashi Sakamoto ; 1137e1621deSTakashi Sakamoto else if (err < 8) 1141017abedSTakashi Sakamoto err = -EIO; 1151017abedSTakashi Sakamoto else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 1161017abedSTakashi Sakamoto err = -ENOSYS; 1171017abedSTakashi Sakamoto else if (buf[0] == 0x0a) /* REJECTED */ 1181017abedSTakashi Sakamoto err = -EINVAL; 1191017abedSTakashi Sakamoto else if (buf[0] == 0x0b) /* IN TRANSITION */ 1201017abedSTakashi Sakamoto err = -EAGAIN; 1211017abedSTakashi Sakamoto if (err < 0) 1221017abedSTakashi Sakamoto goto end; 1231017abedSTakashi Sakamoto 1241017abedSTakashi Sakamoto /* check sfc field and pick up rate */ 1251017abedSTakashi Sakamoto sfc = 0x07 & buf[5]; 1261017abedSTakashi Sakamoto if (sfc >= CIP_SFC_COUNT) { 1271017abedSTakashi Sakamoto err = -EAGAIN; /* also in transition */ 1281017abedSTakashi Sakamoto goto end; 1291017abedSTakashi Sakamoto } 1301017abedSTakashi Sakamoto 1311017abedSTakashi Sakamoto *rate = amdtp_rate_table[sfc]; 1321017abedSTakashi Sakamoto err = 0; 1331017abedSTakashi Sakamoto end: 1341017abedSTakashi Sakamoto kfree(buf); 1351017abedSTakashi Sakamoto return err; 1361017abedSTakashi Sakamoto } 1371017abedSTakashi Sakamoto EXPORT_SYMBOL(avc_general_get_sig_fmt); 1381017abedSTakashi Sakamoto 1391017abedSTakashi Sakamoto int avc_general_get_plug_info(struct fw_unit *unit, unsigned int subunit_type, 1401017abedSTakashi Sakamoto unsigned int subunit_id, unsigned int subfunction, 1411017abedSTakashi Sakamoto u8 info[AVC_PLUG_INFO_BUF_BYTES]) 1421017abedSTakashi Sakamoto { 1431017abedSTakashi Sakamoto u8 *buf; 1441017abedSTakashi Sakamoto int err; 1451017abedSTakashi Sakamoto 1461017abedSTakashi Sakamoto /* extended subunit in spec.4.2 is not supported */ 1471017abedSTakashi Sakamoto if ((subunit_type == 0x1E) || (subunit_id == 5)) 1481017abedSTakashi Sakamoto return -EINVAL; 1491017abedSTakashi Sakamoto 1501017abedSTakashi Sakamoto buf = kzalloc(8, GFP_KERNEL); 1511017abedSTakashi Sakamoto if (buf == NULL) 1521017abedSTakashi Sakamoto return -ENOMEM; 1531017abedSTakashi Sakamoto 1541017abedSTakashi Sakamoto buf[0] = 0x01; /* AV/C STATUS */ 1551017abedSTakashi Sakamoto /* UNIT or Subunit, Functionblock */ 1561017abedSTakashi Sakamoto buf[1] = ((subunit_type & 0x1f) << 3) | (subunit_id & 0x7); 1571017abedSTakashi Sakamoto buf[2] = 0x02; /* PLUG INFO */ 1581017abedSTakashi Sakamoto buf[3] = 0xff & subfunction; 1591017abedSTakashi Sakamoto 1601017abedSTakashi Sakamoto err = fcp_avc_transaction(unit, buf, 8, buf, 8, BIT(1) | BIT(2)); 1617e1621deSTakashi Sakamoto if (err < 0) 1627e1621deSTakashi Sakamoto ; 1637e1621deSTakashi Sakamoto else if (err < 8) 1641017abedSTakashi Sakamoto err = -EIO; 1651017abedSTakashi Sakamoto else if (buf[0] == 0x08) /* NOT IMPLEMENTED */ 1661017abedSTakashi Sakamoto err = -ENOSYS; 1671017abedSTakashi Sakamoto else if (buf[0] == 0x0a) /* REJECTED */ 1681017abedSTakashi Sakamoto err = -EINVAL; 1691017abedSTakashi Sakamoto else if (buf[0] == 0x0b) /* IN TRANSITION */ 1701017abedSTakashi Sakamoto err = -EAGAIN; 1711017abedSTakashi Sakamoto if (err < 0) 1721017abedSTakashi Sakamoto goto end; 1731017abedSTakashi Sakamoto 1741017abedSTakashi Sakamoto info[0] = buf[4]; 1751017abedSTakashi Sakamoto info[1] = buf[5]; 1761017abedSTakashi Sakamoto info[2] = buf[6]; 1771017abedSTakashi Sakamoto info[3] = buf[7]; 1781017abedSTakashi Sakamoto 1791017abedSTakashi Sakamoto err = 0; 1801017abedSTakashi Sakamoto end: 1811017abedSTakashi Sakamoto kfree(buf); 1821017abedSTakashi Sakamoto return err; 1831017abedSTakashi Sakamoto } 1841017abedSTakashi Sakamoto EXPORT_SYMBOL(avc_general_get_plug_info); 1851017abedSTakashi Sakamoto 18631ef9134SClemens Ladisch static DEFINE_SPINLOCK(transactions_lock); 18731ef9134SClemens Ladisch static LIST_HEAD(transactions); 18831ef9134SClemens Ladisch 18931ef9134SClemens Ladisch enum fcp_state { 19031ef9134SClemens Ladisch STATE_PENDING, 19131ef9134SClemens Ladisch STATE_BUS_RESET, 19231ef9134SClemens Ladisch STATE_COMPLETE, 19300a7bb81STakashi Sakamoto STATE_DEFERRED, 19431ef9134SClemens Ladisch }; 19531ef9134SClemens Ladisch 19631ef9134SClemens Ladisch struct fcp_transaction { 19731ef9134SClemens Ladisch struct list_head list; 19831ef9134SClemens Ladisch struct fw_unit *unit; 19931ef9134SClemens Ladisch void *response_buffer; 20031ef9134SClemens Ladisch unsigned int response_size; 20131ef9134SClemens Ladisch unsigned int response_match_bytes; 20231ef9134SClemens Ladisch enum fcp_state state; 20331ef9134SClemens Ladisch wait_queue_head_t wait; 20400a7bb81STakashi Sakamoto bool deferrable; 20531ef9134SClemens Ladisch }; 20631ef9134SClemens Ladisch 20731ef9134SClemens Ladisch /** 20831ef9134SClemens Ladisch * fcp_avc_transaction - send an AV/C command and wait for its response 20931ef9134SClemens Ladisch * @unit: a unit on the target device 21031ef9134SClemens Ladisch * @command: a buffer containing the command frame; must be DMA-able 21131ef9134SClemens Ladisch * @command_size: the size of @command 21231ef9134SClemens Ladisch * @response: a buffer for the response frame 21331ef9134SClemens Ladisch * @response_size: the maximum size of @response 21431ef9134SClemens Ladisch * @response_match_bytes: a bitmap specifying the bytes used to detect the 21531ef9134SClemens Ladisch * correct response frame 21631ef9134SClemens Ladisch * 21731ef9134SClemens Ladisch * This function sends a FCP command frame to the target and waits for the 21831ef9134SClemens Ladisch * corresponding response frame to be returned. 21931ef9134SClemens Ladisch * 22031ef9134SClemens Ladisch * Because it is possible for multiple FCP transactions to be active at the 22131ef9134SClemens Ladisch * same time, the correct response frame is detected by the value of certain 22231ef9134SClemens Ladisch * bytes. These bytes must be set in @response before calling this function, 22331ef9134SClemens Ladisch * and the corresponding bits must be set in @response_match_bytes. 22431ef9134SClemens Ladisch * 22531ef9134SClemens Ladisch * @command and @response can point to the same buffer. 22631ef9134SClemens Ladisch * 22731ef9134SClemens Ladisch * Returns the actual size of the response frame, or a negative error code. 22831ef9134SClemens Ladisch */ 22931ef9134SClemens Ladisch int fcp_avc_transaction(struct fw_unit *unit, 23031ef9134SClemens Ladisch const void *command, unsigned int command_size, 23131ef9134SClemens Ladisch void *response, unsigned int response_size, 23231ef9134SClemens Ladisch unsigned int response_match_bytes) 23331ef9134SClemens Ladisch { 23431ef9134SClemens Ladisch struct fcp_transaction t; 23531ef9134SClemens Ladisch int tcode, ret, tries = 0; 23631ef9134SClemens Ladisch 23731ef9134SClemens Ladisch t.unit = unit; 23831ef9134SClemens Ladisch t.response_buffer = response; 23931ef9134SClemens Ladisch t.response_size = response_size; 24031ef9134SClemens Ladisch t.response_match_bytes = response_match_bytes; 24131ef9134SClemens Ladisch t.state = STATE_PENDING; 24231ef9134SClemens Ladisch init_waitqueue_head(&t.wait); 24331ef9134SClemens Ladisch 24400a7bb81STakashi Sakamoto if (*(const u8 *)command == 0x00 || *(const u8 *)command == 0x03) 24500a7bb81STakashi Sakamoto t.deferrable = true; 24600a7bb81STakashi Sakamoto 24731ef9134SClemens Ladisch spin_lock_irq(&transactions_lock); 24831ef9134SClemens Ladisch list_add_tail(&t.list, &transactions); 24931ef9134SClemens Ladisch spin_unlock_irq(&transactions_lock); 25031ef9134SClemens Ladisch 25131ef9134SClemens Ladisch for (;;) { 25231ef9134SClemens Ladisch tcode = command_size == 4 ? TCODE_WRITE_QUADLET_REQUEST 25331ef9134SClemens Ladisch : TCODE_WRITE_BLOCK_REQUEST; 25431ef9134SClemens Ladisch ret = snd_fw_transaction(t.unit, tcode, 25531ef9134SClemens Ladisch CSR_REGISTER_BASE + CSR_FCP_COMMAND, 2561b70485fSClemens Ladisch (void *)command, command_size, 0); 25731ef9134SClemens Ladisch if (ret < 0) 25831ef9134SClemens Ladisch break; 25900a7bb81STakashi Sakamoto deferred: 26031ef9134SClemens Ladisch wait_event_timeout(t.wait, t.state != STATE_PENDING, 26131ef9134SClemens Ladisch msecs_to_jiffies(FCP_TIMEOUT_MS)); 26231ef9134SClemens Ladisch 26300a7bb81STakashi Sakamoto if (t.state == STATE_DEFERRED) { 26400a7bb81STakashi Sakamoto /* 26500a7bb81STakashi Sakamoto * 'AV/C General Specification' define no time limit 26600a7bb81STakashi Sakamoto * on command completion once an INTERIM response has 26700a7bb81STakashi Sakamoto * been sent. but we promise to finish this function 26800a7bb81STakashi Sakamoto * for a caller. Here we use FCP_TIMEOUT_MS for next 26900a7bb81STakashi Sakamoto * interval. This is not in the specification. 27000a7bb81STakashi Sakamoto */ 27100a7bb81STakashi Sakamoto t.state = STATE_PENDING; 27200a7bb81STakashi Sakamoto goto deferred; 27300a7bb81STakashi Sakamoto } else if (t.state == STATE_COMPLETE) { 27431ef9134SClemens Ladisch ret = t.response_size; 27531ef9134SClemens Ladisch break; 27631ef9134SClemens Ladisch } else if (t.state == STATE_BUS_RESET) { 27731ef9134SClemens Ladisch msleep(ERROR_DELAY_MS); 27831ef9134SClemens Ladisch } else if (++tries >= ERROR_RETRIES) { 27931ef9134SClemens Ladisch dev_err(&t.unit->device, "FCP command timed out\n"); 28031ef9134SClemens Ladisch ret = -EIO; 28131ef9134SClemens Ladisch break; 28231ef9134SClemens Ladisch } 28331ef9134SClemens Ladisch } 28431ef9134SClemens Ladisch 28531ef9134SClemens Ladisch spin_lock_irq(&transactions_lock); 28631ef9134SClemens Ladisch list_del(&t.list); 28731ef9134SClemens Ladisch spin_unlock_irq(&transactions_lock); 28831ef9134SClemens Ladisch 28931ef9134SClemens Ladisch return ret; 29031ef9134SClemens Ladisch } 29131ef9134SClemens Ladisch EXPORT_SYMBOL(fcp_avc_transaction); 29231ef9134SClemens Ladisch 29331ef9134SClemens Ladisch /** 29431ef9134SClemens Ladisch * fcp_bus_reset - inform the target handler about a bus reset 29531ef9134SClemens Ladisch * @unit: the unit that might be used by fcp_avc_transaction() 29631ef9134SClemens Ladisch * 29731ef9134SClemens Ladisch * This function must be called from the driver's .update handler to inform 29831ef9134SClemens Ladisch * the FCP transaction handler that a bus reset has happened. Any pending FCP 29931ef9134SClemens Ladisch * transactions are retried. 30031ef9134SClemens Ladisch */ 30131ef9134SClemens Ladisch void fcp_bus_reset(struct fw_unit *unit) 30231ef9134SClemens Ladisch { 30331ef9134SClemens Ladisch struct fcp_transaction *t; 30431ef9134SClemens Ladisch 30531ef9134SClemens Ladisch spin_lock_irq(&transactions_lock); 30631ef9134SClemens Ladisch list_for_each_entry(t, &transactions, list) { 30731ef9134SClemens Ladisch if (t->unit == unit && 30800a7bb81STakashi Sakamoto (t->state == STATE_PENDING || 30900a7bb81STakashi Sakamoto t->state == STATE_DEFERRED)) { 31031ef9134SClemens Ladisch t->state = STATE_BUS_RESET; 31131ef9134SClemens Ladisch wake_up(&t->wait); 31231ef9134SClemens Ladisch } 31331ef9134SClemens Ladisch } 31431ef9134SClemens Ladisch spin_unlock_irq(&transactions_lock); 31531ef9134SClemens Ladisch } 31631ef9134SClemens Ladisch EXPORT_SYMBOL(fcp_bus_reset); 31731ef9134SClemens Ladisch 31831ef9134SClemens Ladisch /* checks whether the response matches the masked bytes in response_buffer */ 31931ef9134SClemens Ladisch static bool is_matching_response(struct fcp_transaction *transaction, 32031ef9134SClemens Ladisch const void *response, size_t length) 32131ef9134SClemens Ladisch { 32231ef9134SClemens Ladisch const u8 *p1, *p2; 32331ef9134SClemens Ladisch unsigned int mask, i; 32431ef9134SClemens Ladisch 32531ef9134SClemens Ladisch p1 = response; 32631ef9134SClemens Ladisch p2 = transaction->response_buffer; 32731ef9134SClemens Ladisch mask = transaction->response_match_bytes; 32831ef9134SClemens Ladisch 32931ef9134SClemens Ladisch for (i = 0; ; ++i) { 33031ef9134SClemens Ladisch if ((mask & 1) && p1[i] != p2[i]) 33131ef9134SClemens Ladisch return false; 33231ef9134SClemens Ladisch mask >>= 1; 33331ef9134SClemens Ladisch if (!mask) 33431ef9134SClemens Ladisch return true; 33531ef9134SClemens Ladisch if (--length == 0) 33631ef9134SClemens Ladisch return false; 33731ef9134SClemens Ladisch } 33831ef9134SClemens Ladisch } 33931ef9134SClemens Ladisch 34031ef9134SClemens Ladisch static void fcp_response(struct fw_card *card, struct fw_request *request, 34131ef9134SClemens Ladisch int tcode, int destination, int source, 34231ef9134SClemens Ladisch int generation, unsigned long long offset, 34331ef9134SClemens Ladisch void *data, size_t length, void *callback_data) 34431ef9134SClemens Ladisch { 34531ef9134SClemens Ladisch struct fcp_transaction *t; 34631ef9134SClemens Ladisch unsigned long flags; 34731ef9134SClemens Ladisch 34831ef9134SClemens Ladisch if (length < 1 || (*(const u8 *)data & 0xf0) != CTS_AVC) 34931ef9134SClemens Ladisch return; 35031ef9134SClemens Ladisch 35131ef9134SClemens Ladisch spin_lock_irqsave(&transactions_lock, flags); 35231ef9134SClemens Ladisch list_for_each_entry(t, &transactions, list) { 35331ef9134SClemens Ladisch struct fw_device *device = fw_parent_device(t->unit); 35431ef9134SClemens Ladisch if (device->card != card || 35531ef9134SClemens Ladisch device->generation != generation) 35631ef9134SClemens Ladisch continue; 35731ef9134SClemens Ladisch smp_rmb(); /* node_id vs. generation */ 35831ef9134SClemens Ladisch if (device->node_id != source) 35931ef9134SClemens Ladisch continue; 36031ef9134SClemens Ladisch 36131ef9134SClemens Ladisch if (t->state == STATE_PENDING && 36231ef9134SClemens Ladisch is_matching_response(t, data, length)) { 36300a7bb81STakashi Sakamoto if (t->deferrable && *(const u8 *)data == 0x0f) { 36400a7bb81STakashi Sakamoto t->state = STATE_DEFERRED; 36500a7bb81STakashi Sakamoto } else { 36631ef9134SClemens Ladisch t->state = STATE_COMPLETE; 36700a7bb81STakashi Sakamoto t->response_size = min_t(unsigned int, length, 36831ef9134SClemens Ladisch t->response_size); 36900a7bb81STakashi Sakamoto memcpy(t->response_buffer, data, 37000a7bb81STakashi Sakamoto t->response_size); 37100a7bb81STakashi Sakamoto } 37231ef9134SClemens Ladisch wake_up(&t->wait); 37331ef9134SClemens Ladisch } 37431ef9134SClemens Ladisch } 37531ef9134SClemens Ladisch spin_unlock_irqrestore(&transactions_lock, flags); 37631ef9134SClemens Ladisch } 37731ef9134SClemens Ladisch 37831ef9134SClemens Ladisch static struct fw_address_handler response_register_handler = { 37931ef9134SClemens Ladisch .length = 0x200, 38031ef9134SClemens Ladisch .address_callback = fcp_response, 38131ef9134SClemens Ladisch }; 38231ef9134SClemens Ladisch 38331ef9134SClemens Ladisch static int __init fcp_module_init(void) 38431ef9134SClemens Ladisch { 38531ef9134SClemens Ladisch static const struct fw_address_region response_register_region = { 38631ef9134SClemens Ladisch .start = CSR_REGISTER_BASE + CSR_FCP_RESPONSE, 38731ef9134SClemens Ladisch .end = CSR_REGISTER_BASE + CSR_FCP_END, 38831ef9134SClemens Ladisch }; 38931ef9134SClemens Ladisch 39031ef9134SClemens Ladisch fw_core_add_address_handler(&response_register_handler, 39131ef9134SClemens Ladisch &response_register_region); 39231ef9134SClemens Ladisch 39331ef9134SClemens Ladisch return 0; 39431ef9134SClemens Ladisch } 39531ef9134SClemens Ladisch 39631ef9134SClemens Ladisch static void __exit fcp_module_exit(void) 39731ef9134SClemens Ladisch { 39831ef9134SClemens Ladisch WARN_ON(!list_empty(&transactions)); 39931ef9134SClemens Ladisch fw_core_remove_address_handler(&response_register_handler); 40031ef9134SClemens Ladisch } 40131ef9134SClemens Ladisch 40231ef9134SClemens Ladisch module_init(fcp_module_init); 40331ef9134SClemens Ladisch module_exit(fcp_module_exit); 404