Re: [PATCH BlueZ 1/5] AVRCP: use a vtable to simplify PDU parsing/handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Sep 12, 2011 at 8:29 AM, Luiz Augusto von Dentz
<luiz.dentz@xxxxxxxxx> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx>
>
> This simplify a bit the handling by introducing common checks before
> calling the handler callback, it is also much easier to add/remove
> new PDUs in this way.
> ---
>  audio/control.c |  321 +++++++++++++++++++++----------------------------------
>  1 files changed, 124 insertions(+), 197 deletions(-)
>
> diff --git a/audio/control.c b/audio/control.c
> index 9990b06..f84c7f7 100644
> --- a/audio/control.c
> +++ b/audio/control.c
> @@ -986,8 +986,9 @@ static void mp_set_media_attributes(struct control *control,
>        avctp_send_event(control, AVRCP_EVENT_TRACK_CHANGED, NULL);
>  }
>
> -static int avrcp_handle_get_capabilities(struct control *control,
> -                                               struct avrcp_spec_avc_pdu *pdu)
> +static uint8_t avrcp_handle_get_capabilities(struct control *control,
> +                                               struct avrcp_spec_avc_pdu *pdu,
> +                                               uint8_t transaction)
>  {
>        uint16_t len = ntohs(pdu->params_len);
>        unsigned int i;
> @@ -1008,31 +1009,35 @@ static int avrcp_handle_get_capabilities(struct control *control,
>                pdu->params_len = htons(2 + (3 * G_N_ELEMENTS(company_ids)));
>                pdu->params[1] = G_N_ELEMENTS(company_ids);
>
> -               return 2 + (3 * G_N_ELEMENTS(company_ids));
> +               return CTYPE_STABLE;
>        case CAP_EVENTS_SUPPORTED:
>                pdu->params_len = htons(4);
>                pdu->params[1] = 2;
>                pdu->params[2] = AVRCP_EVENT_PLAYBACK_STATUS_CHANGED;
>                pdu->params[3] = AVRCP_EVENT_TRACK_CHANGED;
>
> -               return 4;
> +               return CTYPE_STABLE;
>        }
>
>  err:
> +       pdu->params_len = htons(1);
>        pdu->params[0] = E_INVALID_PARAM;
> -       return -EINVAL;
> +
> +       return CTYPE_REJECTED;
>  }
>
> -static int avrcp_handle_list_player_attributes(struct control *control,
> -                                               struct avrcp_spec_avc_pdu *pdu)
> +static uint8_t avrcp_handle_list_player_attributes(struct control *control,
> +                                               struct avrcp_spec_avc_pdu *pdu,
> +                                               uint8_t transaction)

It might be my CFLAGS, but aren't you getting warnings of unused
parameters since now every handler carries the transaction id?

>  {
>        uint16_t len = ntohs(pdu->params_len);
>        struct media_player *mp = control->mp;
>        unsigned int i;
>
>        if (len != 0) {
> +               pdu->params_len = htons(1);
>                pdu->params[0] = E_INVALID_PARAM;
> -               return -EINVAL;
> +               return CTYPE_REJECTED;
>        }
>
>        if (!mp)
> @@ -1052,11 +1057,12 @@ done:
>        pdu->params[0] = len;
>        pdu->params_len = htons(len + 1);
>
> -       return len + 1;
> +       return CTYPE_STABLE;
>  }
>
> -static int avrcp_handle_list_player_values(struct control *control,
> -                                               struct avrcp_spec_avc_pdu *pdu)
> +static uint8_t avrcp_handle_list_player_values(struct control *control,
> +                                               struct avrcp_spec_avc_pdu *pdu,
> +                                               uint8_t transaction)
>  {
>        uint16_t len = ntohs(pdu->params_len);
>        struct media_player *mp = control->mp;
> @@ -1077,15 +1083,17 @@ static int avrcp_handle_list_player_values(struct control *control,
>        pdu->params[0] = len;
>        pdu->params_len = htons(len + 1);
>
> -       return len + 1;
> +       return CTYPE_STABLE;
>
>  err:
> +       pdu->params_len = htons(1);
>        pdu->params[0] = E_INVALID_PARAM;
> -       return -EINVAL;
> +       return CTYPE_REJECTED;
>  }
>
> -static int avrcp_handle_get_element_attributes(struct control *control,
> -                                               struct avrcp_spec_avc_pdu *pdu)
> +static uint8_t avrcp_handle_get_element_attributes(struct control *control,
> +                                               struct avrcp_spec_avc_pdu *pdu,
> +                                               uint8_t transaction)
>  {
>        uint16_t len = ntohs(pdu->params_len);
>        uint64_t *identifier = (void *) &pdu->params[0];
> @@ -1145,14 +1153,16 @@ done:
>        pdu->params[0] = len;
>        pdu->params_len = htons(pos);
>
> -       return pos;
> +       return CTYPE_STABLE;
>  err:
> +       pdu->params_len = htons(1);
>        pdu->params[0] = E_INVALID_PARAM;
> -       return -EINVAL;
> +       return CTYPE_REJECTED;
>  }
>
> -static int avrcp_handle_get_current_player_value(struct control *control,
> -                                               struct avrcp_spec_avc_pdu *pdu)
> +static uint8_t avrcp_handle_get_current_player_value(struct control *control,
> +                                               struct avrcp_spec_avc_pdu *pdu,
> +                                               uint8_t transaction)
>  {
>        uint16_t len = ntohs(pdu->params_len);
>        struct media_player *mp = control->mp;
> @@ -1202,19 +1212,21 @@ static int avrcp_handle_get_current_player_value(struct control *control,
>                pdu->params[0] = len;
>                pdu->params_len = htons(2 * len + 1);
>
> -               return 2 * len + 1;
> +               return CTYPE_STABLE;
>        }
>
>        error("No valid attributes in request");
>
>  err:
> +       pdu->params_len = htons(1);
>        pdu->params[0] = E_INVALID_PARAM;
>
> -       return -EINVAL;
> +       return CTYPE_REJECTED;
>  }
>
> -static int avrcp_handle_set_player_value(struct control *control,
> -                                               struct avrcp_spec_avc_pdu *pdu)
> +static uint8_t avrcp_handle_set_player_value(struct control *control,
> +                                               struct avrcp_spec_avc_pdu *pdu,
> +                                               uint8_t transaction)
>  {
>        uint16_t len = ntohs(pdu->params_len);
>        unsigned int i;
> @@ -1256,16 +1268,38 @@ static int avrcp_handle_set_player_value(struct control *control,
>        if (len) {
>                pdu->params_len = 0;
>
> -               return 0;
> +               return CTYPE_STABLE;
>        }
>
>  err:
> +       pdu->params_len = htons(1);
>        pdu->params[0] = E_INVALID_PARAM;
> -       return -EINVAL;
> +       return CTYPE_REJECTED;
>  }
>
> -static int avrcp_handle_ct_battery_status(struct control *control,
> -                                               struct avrcp_spec_avc_pdu *pdu)
> +static uint8_t avrcp_handle_displayable_charset(struct control *control,
> +                                               struct avrcp_spec_avc_pdu *pdu,
> +                                               uint8_t transaction)
> +{
> +       uint16_t len = ntohs(pdu->params_len);
> +
> +       if (len < 3) {
> +               pdu->params_len = htons(1);
> +               pdu->params[0] = E_INVALID_PARAM;
> +               return CTYPE_REJECTED;
> +       }
> +
> +       /*
> +        * We acknowledge the commands, but we always use UTF-8 for
> +        * encoding since CT is obliged to support it.
> +        */
> +       pdu->params_len = 0;
> +       return CTYPE_STABLE;
> +}
> +
> +static uint8_t avrcp_handle_ct_battery_status(struct control *control,
> +                                               struct avrcp_spec_avc_pdu *pdu,
> +                                               uint8_t transaction)
>  {
>        uint16_t len = ntohs(pdu->params_len);
>        const char *valstr;
> @@ -1282,15 +1316,17 @@ static int avrcp_handle_ct_battery_status(struct control *control,
>                                        DBUS_TYPE_STRING, &valstr);
>        pdu->params_len = 0;
>
> -       return 0;
> +       return CTYPE_STABLE;
>
>  err:
> +       pdu->params_len = htons(1);
>        pdu->params[0] = E_INVALID_PARAM;
> -       return -EINVAL;
> +       return CTYPE_REJECTED;
>  }
>
> -static int avrcp_handle_get_play_status(struct control *control,
> -                                               struct avrcp_spec_avc_pdu *pdu)
> +static uint8_t avrcp_handle_get_play_status(struct control *control,
> +                                               struct avrcp_spec_avc_pdu *pdu,
> +                                               uint8_t transaction)
>  {
>        uint16_t len = ntohs(pdu->params_len);
>        uint32_t elapsed;
> @@ -1298,8 +1334,9 @@ static int avrcp_handle_get_play_status(struct control *control,
>        uint8_t status;
>
>        if (len != 0) {
> +               pdu->params_len = htons(1);
>                pdu->params[0] = E_INVALID_PARAM;
> -               return -EINVAL;
> +               return CTYPE_REJECTED;
>        }
>
>        if (control->mp) {
> @@ -1319,10 +1356,10 @@ static int avrcp_handle_get_play_status(struct control *control,
>
>        pdu->params_len = htons(9);
>
> -       return 9;
> +       return CTYPE_STABLE;
>  }
>
> -static int avrcp_handle_register_notification(struct control *control,
> +static uint8_t avrcp_handle_register_notification(struct control *control,
>                                                struct avrcp_spec_avc_pdu *pdu,
>                                                uint8_t transaction)
>  {
> @@ -1369,24 +1406,59 @@ static int avrcp_handle_register_notification(struct control *control,
>
>        pdu->params_len = htons(len);
>
> -       return len;
> +       return CTYPE_INTERIM;
>
>  err:
> +       pdu->params_len = htons(1);
>        pdu->params[0] = E_INVALID_PARAM;
> -       return -EINVAL;
> +       return CTYPE_REJECTED;
>  }
>
> +static struct pdu_handler {
> +       uint8_t pdu_id;
> +       uint8_t code;
> +       uint8_t (*func) (struct control *control,
> +                                       struct avrcp_spec_avc_pdu *pdu,
> +                                       uint8_t transaction);
> +} handlers[] = {
> +               { AVRCP_GET_CAPABILITIES, CTYPE_STATUS,
> +                                       avrcp_handle_get_capabilities },
> +               { AVRCP_LIST_PLAYER_ATTRIBUTES, CTYPE_STATUS,
> +                                       avrcp_handle_list_player_attributes },
> +               { AVRCP_LIST_PLAYER_VALUES, CTYPE_STATUS,
> +                                       avrcp_handle_list_player_values },
> +               { AVRCP_GET_ELEMENT_ATTRIBUTES, CTYPE_STATUS,
> +                                       avrcp_handle_get_element_attributes },
> +               { AVRCP_GET_CURRENT_PLAYER_VALUE, CTYPE_STATUS,
> +                                       avrcp_handle_get_current_player_value },
> +               { AVRCP_SET_PLAYER_VALUE, CTYPE_CONTROL,
> +                                       avrcp_handle_set_player_value },
> +               { AVRCP_GET_PLAYER_ATTRIBUTE_TEXT, CTYPE_STATUS,
> +                                       NULL },
> +               { AVRCP_GET_PLAYER_VALUE_TEXT, CTYPE_STATUS,
> +                                       NULL },
> +               { AVRCP_DISPLAYABLE_CHARSET, CTYPE_STATUS,
> +                                       avrcp_handle_displayable_charset },
> +               { AVRCP_CT_BATTERY_STATUS, CTYPE_STATUS,
> +                                       avrcp_handle_ct_battery_status },
> +               { AVRCP_GET_PLAY_STATUS, CTYPE_STATUS,
> +                                       avrcp_handle_get_play_status },
> +               { AVRCP_REGISTER_NOTIFICATION, CTYPE_NOTIFY,
> +                                       avrcp_handle_register_notification },
> +               { },
> +};
> +
>  /* handle vendordep pdu inside an avctp packet */
>  static int handle_vendordep_pdu(struct control *control,
>                                        struct avctp_header *avctp,
>                                        struct avrcp_header *avrcp,
>                                        int operand_count)
>  {
> +       struct pdu_handler *handler;
>        struct avrcp_spec_avc_pdu *pdu = (void *) avrcp + AVRCP_HEADER_LENGTH;
>        uint32_t company_id = (pdu->company_id[0] << 16) |
>                                (pdu->company_id[1] << 8) |
>                                (pdu->company_id[2]);
> -       int len;
>
>        if (company_id != IEEEID_BTSIG ||
>                                pdu->packet_type != AVCTP_PACKET_SINGLE) {
> @@ -1397,177 +1469,32 @@ static int handle_vendordep_pdu(struct control *control,
>        pdu->packet_type = 0;
>        pdu->rsvd = 0;
>
> -       if (operand_count + 3 < AVRCP_SPECAVCPDU_HEADER_LENGTH) {
> -               pdu->params[0] = E_INVALID_COMMAND;
> +       if (operand_count + 3 < AVRCP_SPECAVCPDU_HEADER_LENGTH)
>                goto err_metadata;
> -       }
> -
> -       switch (pdu->pdu_id) {
> -       case AVRCP_GET_CAPABILITIES:
> -               if (avrcp->code != CTYPE_STATUS) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
> -
> -               len = avrcp_handle_get_capabilities(control, pdu);
> -               if (len < 0)
> -                       goto err_metadata;
> -
> -               avrcp->code = CTYPE_STABLE;
> -
> -               break;
> -       case AVRCP_LIST_PLAYER_ATTRIBUTES:
> -               if (avrcp->code != CTYPE_STATUS) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
>
> -               len = avrcp_handle_list_player_attributes(control, pdu);
> -               if (len < 0)
> -                       goto err_metadata;
> -
> -               avrcp->code = CTYPE_STABLE;
> -
> -               break;
> -       case AVRCP_LIST_PLAYER_VALUES:
> -               if (avrcp->code != CTYPE_STATUS) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
> -
> -               len = avrcp_handle_list_player_values(control, pdu);
> -               if (len < 0)
> -                       goto err_metadata;
> -
> -               avrcp->code = CTYPE_STABLE;
> -
> -               break;
> -       case AVRCP_GET_ELEMENT_ATTRIBUTES:
> -               if (avrcp->code != CTYPE_STATUS) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
> -
> -               len = avrcp_handle_get_element_attributes(control, pdu);
> -               if (len < 0)
> -                       goto err_metadata;
> -
> -               avrcp->code = CTYPE_STABLE;
> -
> -               break;
> -       case AVRCP_GET_CURRENT_PLAYER_VALUE:
> -               if (avrcp->code != CTYPE_STATUS) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
> -
> -               len = avrcp_handle_get_current_player_value(control, pdu);
> -               if (len < 0)
> -                       goto err_metadata;
> -
> -               avrcp->code = CTYPE_STABLE;
> -
> -               break;
> -       case AVRCP_SET_PLAYER_VALUE:
> -               if (avrcp->code != CTYPE_CONTROL) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
> -
> -               len = avrcp_handle_set_player_value(control, pdu);
> -               if (len < 0)
> -                       goto err_metadata;
> -
> -               avrcp->code = CTYPE_STABLE;
> -
> -               break;
> -       case AVRCP_GET_PLAYER_ATTRIBUTE_TEXT:
> -       case AVRCP_GET_PLAYER_VALUE_TEXT:
> -               if (avrcp->code != CTYPE_STATUS) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
> +       for (handler = handlers; handler; handler++) {
> +               if (handler->pdu_id == pdu->pdu_id)
> +                       break;
> +       }
>
> -               /*
> -                * As per sec. 5.2.5 of AVRCP 1.3 spec, this command is
> -                * expected to be used only for extended attributes, i.e.
> -                * custom attributes defined by the application. As we
> -                * currently don't have any such attribute, we respond with
> -                * invalid param id.
> -                */
> -               pdu->params[0] = E_INVALID_PARAM;
> +       if (!handler || handler->code != avrcp->code) {
> +               pdu->params[0] = E_INVALID_COMMAND;
>                goto err_metadata;
> -       case AVRCP_DISPLAYABLE_CHARSET:
> -               if (avrcp->code != CTYPE_STATUS) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
> -
> -               if (pdu->params[0] < 3) {
> -                       pdu->params[0] = E_INVALID_PARAM;
> -                       goto err_metadata;
> -               }
> -
> -               /*
> -                * We acknowledge the commands, but we always use UTF-8 for
> -                * encoding since CT is obliged to support it.
> -                */
> -               pdu->params_len = 0;
> -               avrcp->code = CTYPE_STABLE;
> -               len = 0;
> -
> -               break;
> -       case AVRCP_CT_BATTERY_STATUS:
> -               if (avrcp->code != CTYPE_STATUS) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
> -
> -               len = avrcp_handle_ct_battery_status(control, pdu);
> -               if (len < 0)
> -                       goto err_metadata;
> -
> -               avrcp->code = CTYPE_STABLE;
> -
> -               break;
> -       case AVRCP_GET_PLAY_STATUS:
> -               if (avrcp->code != CTYPE_STATUS) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
> -
> -               len = avrcp_handle_get_play_status(control, pdu);
> -               if (len < 0)
> -                       goto err_metadata;
> -
> -               avrcp->code = CTYPE_STABLE;
> -
> -               break;
> -       case AVRCP_REGISTER_NOTIFICATION:
> -               if (avrcp->code != CTYPE_NOTIFY) {
> -                       pdu->params[0] = E_INVALID_COMMAND;
> -                       goto err_metadata;
> -               }
> -
> -               len = avrcp_handle_register_notification(control, pdu,
> -                                                       avctp->transaction);
> -               if (len < 0)
> -                       goto err_metadata;
> -
> -               avrcp->code = CTYPE_INTERIM;
> +       }
>
> -               break;
> -       default:
> -               /* Invalid pdu_id */
> -               pdu->params[0] = E_INVALID_COMMAND;
> +       if (!handler->func) {
> +               pdu->params[0] = E_INVALID_PARAM;
>                goto err_metadata;
>        }
>
> -       return AVRCP_HEADER_LENGTH + AVRCP_SPECAVCPDU_HEADER_LENGTH + len;
> +       avrcp->code = handler->func(control, pdu, avctp->transaction);
> +
> +       return AVRCP_HEADER_LENGTH + AVRCP_SPECAVCPDU_HEADER_LENGTH +
> +                                               ntohs(pdu->params_len);
>
>  err_metadata:
> -       avrcp->code = CTYPE_REJECTED;
>        pdu->params_len = htons(1);
> +       avrcp->code = CTYPE_REJECTED;
>
>        return AVRCP_HEADER_LENGTH + AVRCP_SPECAVCPDU_HEADER_LENGTH + 1;
>  }

Otherwise looks good.



Lucas De Marchi
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux