aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2023-01-19 18:03:35 +0900
committer坂本 貴史 <o-takashi@sakamocchi.jp>2023-01-23 18:29:42 +0900
commit6ae8f77d26cee09f10cc51ba3948b1e47d1de3e2 (patch)
treefc4d3453f0f8525c8a61e3564ae1fdcef16f7ee4
parent51e1af447e9e593f60b5082a265ce03d89f37ce2 (diff)
downloadlibhinawa-6ae8f77d26cee09f10cc51ba3948b1e47d1de3e2.tar.gz
fw_resp: get previous version of event back for request event
When application runs in Linux kernel with old ABI of FireWire subsystem, some event is not available. For the case, current implementation does not emit GObject signal corresponding to it. It's inconvenient. This commit emits the GObject signal in the case. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
-rw-r--r--src/fw_node.c17
-rw-r--r--src/fw_resp.c53
-rw-r--r--src/internal.h3
3 files changed, 65 insertions, 8 deletions
diff --git a/src/fw_node.c b/src/fw_node.c
index 3ca7235..65854a3 100644
--- a/src/fw_node.c
+++ b/src/fw_node.c
@@ -477,9 +477,20 @@ static gboolean dispatch_src(GSource *gsrc, GSourceFunc cb, gpointer user_data)
if (HINAWA_IS_FW_NODE(instance) && event_type == FW_CDEV_EVENT_BUS_RESET) {
handle_update(src->self);
- } else if (HINAWA_IS_FW_RESP(instance) && event_type == FW_CDEV_EVENT_REQUEST2) {
- hinawa_fw_resp_handle_request(HINAWA_FW_RESP(instance), &event->request2);
- } else if (HINAWA_IS_FW_REQ(instance) && event->common.type == FW_CDEV_EVENT_RESPONSE) {
+ } else if (HINAWA_IS_FW_RESP(instance)) {
+ HinawaFwResp *resp = HINAWA_FW_RESP(instance);
+
+ switch (event_type) {
+ case FW_CDEV_EVENT_REQUEST:
+ hinawa_fw_resp_handle_request(resp, &event->request);
+ break;
+ case FW_CDEV_EVENT_REQUEST2:
+ hinawa_fw_resp_handle_request2(resp, &event->request2);
+ break;
+ default:
+ break;
+ }
+ } else if (HINAWA_IS_FW_REQ(instance)) {
HinawaFwReq *req = HINAWA_FW_REQ(instance);
GList *entry;
diff --git a/src/fw_resp.c b/src/fw_resp.c
index a58e412..f9c5e35 100644
--- a/src/fw_resp.c
+++ b/src/fw_resp.c
@@ -412,8 +412,8 @@ void hinawa_fw_resp_set_resp_frame(HinawaFwResp *self, guint8 *frame,
}
}
-// NOTE: For HinawaFwNodee, internal.
-void hinawa_fw_resp_handle_request(HinawaFwResp *self, const struct fw_cdev_event_request2 *event)
+// NOTE: For HinawaFwNode, internal.
+void hinawa_fw_resp_handle_request(HinawaFwResp *self, const struct fw_cdev_event_request *event)
{
HinawaFwRespPrivate *priv;
HinawaFwRespClass *klass;
@@ -431,13 +431,58 @@ void hinawa_fw_resp_handle_request(HinawaFwResp *self, const struct fw_cdev_even
if (!priv->node || event->length > priv->width) {
rcode = RCODE_CONFLICT_ERROR;
} else if (klass->requested2 != NULL ||
- g_signal_has_handler_pending(self, fw_resp_sigs[FW_RESP_SIG_TYPE_REQ2], 0, TRUE)) {
+ g_signal_has_handler_pending(self, fw_resp_sigs[FW_RESP_SIG_TYPE_REQ2], 0, TRUE)) {
+ // Pass arguments as much as possible, else fill with invalid value (G_MAX_UINT).
+ g_signal_emit(self, fw_resp_sigs[FW_RESP_SIG_TYPE_REQ2], 0, event->tcode,
+ event->offset, G_MAXUINT, G_MAXUINT, G_MAXUINT, G_MAXUINT,
+ event->data, event->length, &rcode);
+ } else {
+ // For backward compatibility to use Hinawa.FwResp.get_req_frame().
+ memcpy(priv->req_frame, event->data, event->length);
+ priv->req_length = event->length;
+
+ rcode = HINAWA_FW_RCODE_ADDRESS_ERROR;
+ g_signal_emit(self, fw_resp_sigs[FW_RESP_SIG_TYPE_REQ], 0, event->tcode, &rcode);
+ }
+
+ if (priv->resp_length > 0) {
+ resp.length = priv->resp_length;
+ resp.data = (guint64)priv->resp_frame;
+ }
+
+ // Ignore ioctl error.
+ resp.rcode = (__u32)rcode;
+ resp.handle = event->handle;
+ hinawa_fw_node_ioctl(priv->node, FW_CDEV_IOC_SEND_RESPONSE, &resp, &error);
+ g_clear_error(&error);
+}
+
+// NOTE: For HinawaFwNode, internal.
+void hinawa_fw_resp_handle_request2(HinawaFwResp *self, const struct fw_cdev_event_request2 *event)
+{
+ HinawaFwRespPrivate *priv;
+ HinawaFwRespClass *klass;
+ struct fw_cdev_send_response resp = {0};
+ HinawaFwRcode rcode;
+ GError *error = NULL;
+
+ g_return_if_fail(HINAWA_IS_FW_RESP(self));
+ priv = hinawa_fw_resp_get_instance_private(self);
+ klass = HINAWA_FW_RESP_GET_CLASS(self);
+
+ memset(priv->resp_frame, 0, priv->width);
+ priv->resp_length = 0;
+
+ if (!priv->node || event->length > priv->width) {
+ rcode = RCODE_CONFLICT_ERROR;
+ } else if (klass->requested2 != NULL ||
+ g_signal_has_handler_pending(self, fw_resp_sigs[FW_RESP_SIG_TYPE_REQ2], 0, TRUE)) {
g_signal_emit(self, fw_resp_sigs[FW_RESP_SIG_TYPE_REQ2], 0, event->tcode,
event->offset, event->source_node_id, event->destination_node_id,
event->card, event->generation, event->data, event->length, &rcode);
} else if (klass->requested != NULL ||
g_signal_has_handler_pending(self, fw_resp_sigs[FW_RESP_SIG_TYPE_REQ], 0, TRUE)) {
- // For backward compatibility.
+ // For backward compatibility to use Hinawa.FwResp.get_req_frame().
memcpy(priv->req_frame, event->data, event->length);
priv->req_length = event->length;
diff --git a/src/internal.h b/src/internal.h
index e670258..efc8350 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -7,7 +7,8 @@
int hinawa_fw_node_ioctl(HinawaFwNode *self, unsigned long req, void *args, GError **exception);
void hinawa_fw_node_invalidate_transaction(HinawaFwNode *self, HinawaFwReq *req);
-void hinawa_fw_resp_handle_request(HinawaFwResp *self, const struct fw_cdev_event_request2 *event);
+void hinawa_fw_resp_handle_request(HinawaFwResp *self, const struct fw_cdev_event_request *event);
+void hinawa_fw_resp_handle_request2(HinawaFwResp *self, const struct fw_cdev_event_request2 *event);
void hinawa_fw_req_handle_response(HinawaFwReq *self, const struct fw_cdev_event_response *event);
void hinawa_snd_unit_write(HinawaSndUnit *self, const void *buf, size_t length,