blob: 8346a0afdd99497ee3dcd0dfa0ec9b6f62c678dc [file] [log] [blame]
/*
* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "qrb.h"
#include <assert.h>
#include <stdio.h>
#include "qmidev.h"
#include "qmimsg.h"
#include "util.h"
/* TODO: Need to remove/free qrbs while in qrbset_complete. */
/* TODO: Do we need to refcount these? */
struct qrb {
int flags;
uint8_t service;
uint8_t client;
uint16_t transaction;
qrb_callback callback;
void *priv;
struct qrb *next;
struct qrb *prev;
};
struct qrb *qrb_alloc(uint8_t s, uint8_t c, uint16_t t, int flags,
qrb_callback cb, void *priv)
{
struct qrb *qrb = xmalloc(sizeof(*qrb));
qrb->flags = flags;
qrb->service = s;
qrb->client = c;
qrb->transaction = t;
qrb->callback = cb;
qrb->priv = priv;
qrb->next = NULL;
qrb->prev = NULL;
return qrb;
}
void qrb_free(struct qrb *qrb)
{
assert(qrb);
/* close(qrb->timerfd); */
xfree(qrb);
}
void *qrb_priv(struct qrb *qrb)
{
assert(qrb);
return qrb->priv;
}
void qrb_set_priv(struct qrb *qrb, void *priv)
{
assert(qrb);
qrb->priv = priv;
}
static void qrb_complete(struct qrb *qrb, struct qmimsg *msg)
{
assert(qrb);
(qrb->callback)(qrb, msg);
}
static int qrb_match(struct qrb *qrb, struct qmimsg *msg)
{
assert(qrb);
assert(msg);
uint8_t service;
uint8_t client;
uint16_t transaction;
qmimsg_get_header(msg, &service, &client, &transaction);
if (service != qrb->service)
return 0;
if (client != qrb->client && client != QMI_CLIENT_BROADCAST)
return 0;
/* TODO: Sometimes we don't have a tid. */
if (transaction != qrb->transaction)
return 0;
return 1;
}
struct qrbset {
struct qrb *head;
};
struct qrbset *qrbset_alloc(void)
{
struct qrbset *set = xmalloc(sizeof(*set));
set->head = NULL;
return set;
}
void qrbset_add(struct qrbset *set, struct qrb *qrb)
{
assert(set);
assert(qrb);
if (set->head)
set->head->prev = qrb;
qrb->prev = NULL;
qrb->next = set->head;
set->head = qrb;
}
void qrbset_remove(struct qrbset *set, struct qrb *qrb)
{
assert(set);
assert(qrb);
if (set->head == qrb)
set->head = qrb->next;
if (qrb->prev)
qrb->prev->next = qrb->next;
if (qrb->next)
qrb->next->prev = qrb->prev;
}
int qrbset_complete(struct qrbset *set, struct qmimsg *msg)
{
assert(set);
assert(msg);
struct qrb *qrb, *next;
int found = 0;
if (!set->head)
goto out;
for (qrb = set->head, next = qrb->next;
qrb;
qrb = next) {
next = qrb->next;
if (qrb_match(qrb, msg)) {
qrb_complete(qrb, msg);
found = 1;
if (!(qrb->flags & QRB_PERSISTENT)) {
qrbset_remove(set, qrb);
}
}
}
out:
return found;
}
void qrbset_free(struct qrbset *set)
{
assert(set);
/* TODO: unlink qrbs? */
assert(!set->head);
xfree(set);
}