diff mbox series

[BlueZ,4/4] monitor/att: Add decoding support for GMCS

Message ID 20221006143343.199055-5-abhay.maheshbhai.maheta@intel.com (mailing list archive)
State Superseded
Headers show
Series Media Control Profile Client | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/checkpatch fail [BlueZ,4/4] monitor/att: Add decoding support for GMCS WARNING:LEADING_SPACE: please, no spaces at the start of a line #113: FILE: monitor/att.c:1754: + char utf8_name[HCI_MAX_NAME_LENGTH + 2];$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #114: FILE: monitor/att.c:1755: + int i;$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #116: FILE: monitor/att.c:1757: + if (g_utf8_validate((const char *) name, len, NULL))$ ERROR:CODE_INDENT: code indent should use tabs where possible #117: FILE: monitor/att.c:1758: + return g_strndup((char *) name, len);$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #117: FILE: monitor/att.c:1758: + return g_strndup((char *) name, len);$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #119: FILE: monitor/att.c:1760: + len = MIN(len, sizeof(utf8_name) - 1);$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #121: FILE: monitor/att.c:1762: + memset(utf8_name, 0, sizeof(utf8_name));$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #122: FILE: monitor/att.c:1763: + strncpy(utf8_name, (char *) name, len);$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #125: FILE: monitor/att.c:1766: + for (i = 0; utf8_name[i] != '\0'; i++) {$ ERROR:CODE_INDENT: code indent should use tabs where possible #126: FILE: monitor/att.c:1767: + if (!isascii(utf8_name[i]))$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #126: FILE: monitor/att.c:1767: + if (!isascii(utf8_name[i]))$ WARNING:SUSPECT_CODE_INDENT: suspect code indent for conditional statements (8, 12) #126: FILE: monitor/att.c:1767: + if (!isascii(utf8_name[i])) + utf8_name[i] = ' '; ERROR:CODE_INDENT: code indent should use tabs where possible #127: FILE: monitor/att.c:1768: + utf8_name[i] = ' ';$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #127: FILE: monitor/att.c:1768: + utf8_name[i] = ' ';$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #128: FILE: monitor/att.c:1769: + }$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #131: FILE: monitor/att.c:1772: + g_strstrip(utf8_name);$ WARNING:LEADING_SPACE: please, no spaces at the start of a line #133: FILE: monitor/att.c:1774: + return g_strdup(utf8_name);$ WARNING:LONG_LINE_STRING: line length of 86 exceeds 80 columns #383: FILE: monitor/att.c:2024: + print_text(COLOR_ERROR, " Supported Playing Orders: invalid size"); WARNING:LONG_LINE: line length of 81 exceeds 80 columns #387: FILE: monitor/att.c:2028: + print_field(" Supported Playing Orders: 0x%4.4x", supported_orders); ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #451: FILE: monitor/att.c:2092: + {0x02 , "Pause"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #452: FILE: monitor/att.c:2093: + {0x03 , "Fast Rewind"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #453: FILE: monitor/att.c:2094: + {0x04 , "Fast Forward"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #454: FILE: monitor/att.c:2095: + {0x05 , "Stop"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #455: FILE: monitor/att.c:2096: + {0x10 , "Move Relative"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #456: FILE: monitor/att.c:2097: + {0x20 , "Previous Segment"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #457: FILE: monitor/att.c:2098: + {0x21 , "Next Segment"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #458: FILE: monitor/att.c:2099: + {0x22 , "First Segment"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #459: FILE: monitor/att.c:2100: + {0x23 , "Last Segment"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #460: FILE: monitor/att.c:2101: + {0x24 , "Goto Segment"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #461: FILE: monitor/att.c:2102: + {0x30 , "Previous Track"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #462: FILE: monitor/att.c:2103: + {0x31 , "Next Track"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #463: FILE: monitor/att.c:2104: + {0x32 , "First Track"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #464: FILE: monitor/att.c:2105: + {0x33 , "Last Track"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #465: FILE: monitor/att.c:2106: + {0x34 , "Goto Track"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #466: FILE: monitor/att.c:2107: + {0x40 , "Previous Group"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #467: FILE: monitor/att.c:2108: + {0x41 , "Next Group"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #468: FILE: monitor/att.c:2109: + {0x42 , "First Group"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #469: FILE: monitor/att.c:2110: + {0x43 , "Last Group"}, ^ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #470: FILE: monitor/att.c:2111: + {0x44 , "Goto Group"}, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #514: FILE: monitor/att.c:2155: + {0^I, "Play (0x00000001)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #514: FILE: monitor/att.c:2155: + {0 , "Play (0x00000001)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #515: FILE: monitor/att.c:2156: + {1^I, "Pause (0x00000002)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #515: FILE: monitor/att.c:2156: + {1 , "Pause (0x00000002)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #516: FILE: monitor/att.c:2157: + {2^I, "Fast Rewind^I(0x00000004)"^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #516: FILE: monitor/att.c:2157: + {2 , "Fast Rewind (0x00000004)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #517: FILE: monitor/att.c:2158: + {3^I, "Fast Forward (0x00000008)"^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #517: FILE: monitor/att.c:2158: + {3 , "Fast Forward (0x00000008)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #518: FILE: monitor/att.c:2159: + {4^I, "Stop (0x00000010)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #518: FILE: monitor/att.c:2159: + {4 , "Stop (0x00000010)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #519: FILE: monitor/att.c:2160: + {5^I, "Move Relative (0x00000020)"^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #519: FILE: monitor/att.c:2160: + {5 , "Move Relative (0x00000020)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #520: FILE: monitor/att.c:2161: + {6^I, "Previous Segment (0x00000040)"^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #520: FILE: monitor/att.c:2161: + {6 , "Previous Segment (0x00000040)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #521: FILE: monitor/att.c:2162: + {7^I, "Next Segment (0x00000080)"^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #521: FILE: monitor/att.c:2162: + {7 , "Next Segment (0x00000080)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #522: FILE: monitor/att.c:2163: + {8^I, "First Segment (0x00000100)"^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #522: FILE: monitor/att.c:2163: + {8 , "First Segment (0x00000100)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #523: FILE: monitor/att.c:2164: + {9^I, "Last Segment (0x00000200)"^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #523: FILE: monitor/att.c:2164: + {9 , "Last Segment (0x00000200)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #524: FILE: monitor/att.c:2165: + {10^I, "Goto Segment (0x00000400)"^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #524: FILE: monitor/att.c:2165: + {10 , "Goto Segment (0x00000400)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #525: FILE: monitor/att.c:2166: + {11^I, "Previous Track (0x00000800)" },$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #525: FILE: monitor/att.c:2166: + {11 , "Previous Track (0x00000800)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #526: FILE: monitor/att.c:2167: + {12^I, "Next Track (0x00001000)"^I^I },$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #526: FILE: monitor/att.c:2167: + {12 , "Next Track (0x00001000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #527: FILE: monitor/att.c:2168: + {13^I, "First Track (0x00002000)"^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #527: FILE: monitor/att.c:2168: + {13 , "First Track (0x00002000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #528: FILE: monitor/att.c:2169: + {14^I, "Last Track (0x00004000)"^I^I },$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #528: FILE: monitor/att.c:2169: + {14 , "Last Track (0x00004000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #529: FILE: monitor/att.c:2170: + {15^I, "Goto Track (0x00008000)"^I^I },$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #529: FILE: monitor/att.c:2170: + {15 , "Goto Track (0x00008000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #530: FILE: monitor/att.c:2171: + {16^I, "Previous Group (0x00010000)"^I },$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #530: FILE: monitor/att.c:2171: + {16 , "Previous Group (0x00010000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #531: FILE: monitor/att.c:2172: + {17^I, "Next Group (0x00020000)"^I^I },$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #531: FILE: monitor/att.c:2172: + {17 , "Next Group (0x00020000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #532: FILE: monitor/att.c:2173: + {18^I, "First Group (0x00040000)"^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #532: FILE: monitor/att.c:2173: + {18 , "First Group (0x00040000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #533: FILE: monitor/att.c:2174: + {19^I, "Last Group (0x00080000)"^I^I },$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #533: FILE: monitor/att.c:2174: + {19 , "Last Group (0x00080000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #534: FILE: monitor/att.c:2175: + {20 , "Goto Group (0x00100000)"^I^I },$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #534: FILE: monitor/att.c:2175: + {20 , "Goto Group (0x00100000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #535: FILE: monitor/att.c:2176: + {21^I, "RFU (0x00200000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #535: FILE: monitor/att.c:2176: + {21 , "RFU (0x00200000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #536: FILE: monitor/att.c:2177: + {22^I, "RFU (0x00400000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #536: FILE: monitor/att.c:2177: + {22 , "RFU (0x00400000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #537: FILE: monitor/att.c:2178: + {23^I, "RFU (0x00800000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #537: FILE: monitor/att.c:2178: + {23 , "RFU (0x00800000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #538: FILE: monitor/att.c:2179: + {24^I, "RFU (0x01000000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #538: FILE: monitor/att.c:2179: + {24 , "RFU (0x01000000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #539: FILE: monitor/att.c:2180: + {25^I, "RFU (0x02000000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #539: FILE: monitor/att.c:2180: + {25 , "RFU (0x02000000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #540: FILE: monitor/att.c:2181: + {26^I, "RFU (0x04000000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #540: FILE: monitor/att.c:2181: + {26 , "RFU (0x04000000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #541: FILE: monitor/att.c:2182: + {27^I, "RFU (0x08000000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #541: FILE: monitor/att.c:2182: + {27 , "RFU (0x08000000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #542: FILE: monitor/att.c:2183: + {28^I, "RFU (0x10000000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #542: FILE: monitor/att.c:2183: + {28 , "RFU (0x10000000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #543: FILE: monitor/att.c:2184: + {29^I, "RFU (0x20000000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #543: FILE: monitor/att.c:2184: + {29 , "RFU (0x20000000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #544: FILE: monitor/att.c:2185: + {30^I, "RFU (0x40000000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #544: FILE: monitor/att.c:2185: + {30 , "RFU (0x40000000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #545: FILE: monitor/att.c:2186: + {31^I, "RFU (0x80000000)"^I^I^I^I},$ ERROR:SPACING: space prohibited before that ',' (ctx:WxW) #545: FILE: monitor/att.c:2186: + {31 , "RFU (0x80000000)" }, ^ WARNING:LEADING_SPACE: please, no spaces at the start of a line #546: FILE: monitor/att.c:2187: + { }$ /github/workspace/src/13000446.patch total: 55 errors, 49 warnings, 535 lines checked NOTE: For some of the reported defects, checkpatch may be able to mechanically convert to the typical style using --fix or --fix-inplace. NOTE: Whitespace errors detected. You may wish to use scripts/cleanpatch or scripts/cleanfile /github/workspace/src/13000446.patch has style problems, please review. NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO NOTE: If any of the errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS.
tedd_an/gitlint success Gitlint PASS

Commit Message

Abhay Maheta Oct. 6, 2022, 2:33 p.m. UTC
This adds decoding support for GMCS attributes.

< ACL Data TX: Handle 3585 flags 0x00 dlen 7
      ATT: Read Request (0x0a) len 2
        Handle: 0x0056 Type: Media Control Point Opcodes Supported (0x2ba5)
> ACL Data RX: Handle 3585 flags 0x02 dlen 9
      ATT: Read Response (0x0b) len 4
        Value: 33180000
        Handle: 0x0056 Type: Media Control Point Opcodes Supported (0x2ba5)
              Supported Opcodes: 0x00001833
                Play (0x00000001)
                Pause (0x00000002)
                Stop (0x00000010)
                Move Relative (0x00000020)
                Previous Track (0x00000800)
                Next Track (0x00001000)
---
 monitor/att.c | 511 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 511 insertions(+)
diff mbox series

Patch

diff --git a/monitor/att.c b/monitor/att.c
index f5fc32cb0..1bb9f58f6 100644
--- a/monitor/att.c
+++ b/monitor/att.c
@@ -14,6 +14,7 @@ 
 #endif
 
 #define _GNU_SOURCE
+#include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -22,6 +23,8 @@ 
 #include <errno.h>
 #include <linux/limits.h>
 
+#include <glib.h>
+
 #include "lib/bluetooth.h"
 #include "lib/uuid.h"
 #include "lib/hci.h"
@@ -1746,6 +1749,497 @@  static void vol_flag_notify(const struct l2cap_frame *frame)
 	print_vcs_flag(frame);
 }
 
+static char *name2utf8(const uint8_t *name, uint16_t len)
+{
+    char utf8_name[HCI_MAX_NAME_LENGTH + 2];
+    int i;
+
+    if (g_utf8_validate((const char *) name, len, NULL))
+        return g_strndup((char *) name, len);
+
+    len = MIN(len, sizeof(utf8_name) - 1);
+
+    memset(utf8_name, 0, sizeof(utf8_name));
+    strncpy(utf8_name, (char *) name, len);
+
+    /* Assume ASCII, and replace all non-ASCII with spaces */
+    for (i = 0; utf8_name[i] != '\0'; i++) {
+        if (!isascii(utf8_name[i]))
+            utf8_name[i] = ' ';
+    }
+
+    /* Remove leading and trailing whitespace characters */
+    g_strstrip(utf8_name);
+
+    return g_strdup(utf8_name);
+}
+
+static void print_mp_name(const struct l2cap_frame *frame)
+{
+	char *name;
+
+	name = name2utf8((uint8_t *)frame->data, frame->size);
+
+	print_field("  Media Player Name: %s", name);
+}
+
+static void mp_name_read(const struct l2cap_frame *frame)
+{
+	print_mp_name(frame);
+}
+
+static void mp_name_notify(const struct l2cap_frame *frame)
+{
+	print_mp_name(frame);
+}
+
+static void print_track_changed(const struct l2cap_frame *frame)
+{
+	print_field("  Track Changed");
+}
+
+static void track_changed_notify(const struct l2cap_frame *frame)
+{
+	print_track_changed(frame);
+}
+
+static void print_track_title(const struct l2cap_frame *frame)
+{
+	char *name;
+
+	name = name2utf8((uint8_t *)frame->data, frame->size);
+
+	print_field("  Track Title: %s", name);
+}
+
+static void track_title_read(const struct l2cap_frame *frame)
+{
+	print_track_title(frame);
+}
+
+static void track_title_notify(const struct l2cap_frame *frame)
+{
+	print_track_title(frame);
+}
+
+static void print_track_duration(const struct l2cap_frame *frame)
+{
+	int32_t duration;
+
+	if (!l2cap_frame_get_le32((void *)frame, (uint32_t *)&duration)) {
+		print_text(COLOR_ERROR, "  Track Duration: invalid size");
+		goto done;
+	}
+
+	print_field("  Track Duration: %u", duration);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void track_duration_read(const struct l2cap_frame *frame)
+{
+	print_track_duration(frame);
+}
+
+static void track_duration_notify(const struct l2cap_frame *frame)
+{
+	print_track_duration(frame);
+}
+
+static void print_track_position(const struct l2cap_frame *frame)
+{
+	int32_t position;
+
+	if (!l2cap_frame_get_le32((void *)frame, (uint32_t *)&position)) {
+		print_text(COLOR_ERROR, "  Track Position: invalid size");
+		goto done;
+	}
+
+	print_field("  Track Position: %u", position);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void track_position_read(const struct l2cap_frame *frame)
+{
+	print_track_position(frame);
+}
+
+static void track_position_write(const struct l2cap_frame *frame)
+{
+	print_track_position(frame);
+}
+
+static void track_position_notify(const struct l2cap_frame *frame)
+{
+	print_track_position(frame);
+}
+
+static void print_playback_speed(const struct l2cap_frame *frame)
+{
+	int8_t playback_speed;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&playback_speed)) {
+		print_text(COLOR_ERROR, "  Playback Speed: invalid size");
+		goto done;
+	}
+
+	print_field("  Playback Speed: %u", playback_speed);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void playback_speed_read(const struct l2cap_frame *frame)
+{
+	print_playback_speed(frame);
+}
+
+static void playback_speed_write(const struct l2cap_frame *frame)
+{
+	print_playback_speed(frame);
+}
+
+static void playback_speed_notify(const struct l2cap_frame *frame)
+{
+	print_playback_speed(frame);
+}
+
+static void print_seeking_speed(const struct l2cap_frame *frame)
+{
+	int8_t seeking_speed;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&seeking_speed)) {
+		print_text(COLOR_ERROR, "  Seeking Speed: invalid size");
+		goto done;
+	}
+
+	print_field("  Seeking Speed: %u", seeking_speed);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void seeking_speed_read(const struct l2cap_frame *frame)
+{
+	print_seeking_speed(frame);
+}
+
+static void seeking_speed_notify(const struct l2cap_frame *frame)
+{
+	print_seeking_speed(frame);
+}
+
+const char *play_order_str(uint8_t order)
+{
+	switch (order) {
+	case 0x01:
+		return "Single once";
+	case 0x02:
+		return "Single repeat";
+	case 0x03:
+		return "In order once";
+	case 0x04:
+		return "In order repeat";
+	case 0x05:
+		return "Oldest once";
+	case 0x06:
+		return "Oldest repeat";
+	case 0x07:
+		return "Newest once";
+	case 0x08:
+		return "Newest repeat";
+	case 0x09:
+		return "Shuffle once";
+	case 0x0A:
+		return "Shuffle repeat";
+	default:
+		return "RFU";
+	}
+}
+
+static void print_playing_order(const struct l2cap_frame *frame)
+{
+	int8_t playing_order;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&playing_order)) {
+		print_text(COLOR_ERROR, "  Playing Order: invalid size");
+		goto done;
+	}
+
+	print_field("  Playing Order: %s", play_order_str(playing_order));
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void playing_order_read(const struct l2cap_frame *frame)
+{
+	print_playing_order(frame);
+}
+
+static void playing_order_write(const struct l2cap_frame *frame)
+{
+	print_playing_order(frame);
+}
+
+static void playing_order_notify(const struct l2cap_frame *frame)
+{
+	print_playing_order(frame);
+}
+
+static const struct bitfield_data playing_orders_table[] = {
+	{  0, "Single once (0x0001)"	    },
+	{  1, "Single repeat (0x0002)"		},
+	{  2, "In order once (0x0004)"		},
+	{  3, "In Order Repeat (0x0008)"	},
+	{  4, "Oldest once (0x0010)"		},
+	{  5, "Oldest repeat (0x0020)"		},
+	{  6, "Newest once (0x0040)"		},
+	{  7, "Newest repeat (0x0080)"	    },
+	{  8, "Shuffle once (0x0100)"		},
+	{  9, "Shuffle repeat (0x0200)"		},
+	{  10, "RFU (0x0400)"			    },
+	{  11, "RFU (0x0800)"		        },
+	{  12, "RFU (0x1000)"				},
+	{  13, "RFU (0x2000)"				},
+	{  14, "RFU (0x4000)"				},
+	{  15, "RFU (0x8000)"				},
+	{ }
+};
+
+static void print_playing_orders_supported(const struct l2cap_frame *frame)
+{
+	uint16_t supported_orders;
+	uint16_t mask;
+
+	if (!l2cap_frame_get_le16((void *)frame, &supported_orders)) {
+		print_text(COLOR_ERROR, "    Supported Playing Orders: invalid size");
+		goto done;
+	}
+
+	print_field("      Supported Playing Orders: 0x%4.4x", supported_orders);
+
+	mask = print_bitfield(8, supported_orders, playing_orders_table);
+	if (mask)
+		print_text(COLOR_WHITE_BG, "    Unknown fields (0x%4.4x)",
+								mask);
+
+done:
+	if (frame->size)
+		print_hex_field("    Data", frame->data, frame->size);
+}
+
+static void playing_orders_supported_read(const struct l2cap_frame *frame)
+{
+	print_playing_orders_supported(frame);
+}
+
+const char *media_state_str(uint8_t state)
+{
+	switch (state) {
+	case 0x00:
+		return "Inactive";
+	case 0x01:
+		return "Playing";
+	case 0x02:
+		return "Paused";
+	case 0x03:
+		return "Seeking";
+	default:
+		return "RFU";
+	}
+}
+
+static void print_media_state(const struct l2cap_frame *frame)
+{
+	int8_t state;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&state)) {
+		print_text(COLOR_ERROR, "  Media State: invalid size");
+		goto done;
+	}
+
+	print_field("  Media State: %s", media_state_str(state));
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void media_state_read(const struct l2cap_frame *frame)
+{
+	print_media_state(frame);
+}
+
+static void media_state_notify(const struct l2cap_frame *frame)
+{
+	print_media_state(frame);
+}
+
+struct media_cp_opcode {
+	uint8_t opcode;
+	const char *opcode_str;
+} media_cp_opcode_table[] = {
+	{0x01, "Play"},
+	{0x02 ,	"Pause"},
+	{0x03 ,	"Fast Rewind"},
+	{0x04 ,	"Fast Forward"},
+	{0x05 ,	"Stop"},
+	{0x10 ,	"Move Relative"},
+	{0x20 ,	"Previous Segment"},
+	{0x21 ,	"Next Segment"},
+	{0x22 ,	"First Segment"},
+	{0x23 ,	"Last Segment"},
+	{0x24 ,	"Goto Segment"},
+	{0x30 ,	"Previous Track"},
+	{0x31 ,	"Next Track"},
+	{0x32 ,	"First Track"},
+	{0x33 ,	"Last Track"},
+	{0x34 ,	"Goto Track"},
+	{0x40 ,	"Previous Group"},
+	{0x41 ,	"Next Group"},
+	{0x42 ,	"First Group"},
+	{0x43 ,	"Last Group"},
+	{0x44 ,	"Goto Group"},
+};
+
+const char *cp_opcode_str(uint8_t opcode)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(media_cp_opcode_table); i++) {
+		const char *str = media_cp_opcode_table[i].opcode_str;
+
+		if (opcode == media_cp_opcode_table[i].opcode)
+			return str;
+	}
+
+	return "RFU";
+}
+
+static void print_media_cp(const struct l2cap_frame *frame)
+{
+	int8_t opcode;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&opcode)) {
+		print_text(COLOR_ERROR, "  Media Control Point: invalid size");
+		goto done;
+	}
+
+	print_field("  Media Control Point: %s", cp_opcode_str(opcode));
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void media_cp_write(const struct l2cap_frame *frame)
+{
+	print_media_cp(frame);
+}
+
+static void media_cp_notify(const struct l2cap_frame *frame)
+{
+	print_media_cp(frame);
+}
+
+static const struct bitfield_data supported_opcodes_table[] = {
+    {0	, "Play (0x00000001)"				},
+    {1	, "Pause (0x00000002)"				},
+    {2	, "Fast Rewind	(0x00000004)"		},
+    {3	, "Fast Forward (0x00000008)"		},
+    {4	, "Stop (0x00000010)"				},
+    {5	, "Move Relative (0x00000020)"		},
+    {6	, "Previous Segment (0x00000040)"	},
+    {7	, "Next Segment (0x00000080)"		},
+    {8	, "First Segment (0x00000100)"		},
+    {9	, "Last Segment (0x00000200)"		},
+    {10	, "Goto Segment (0x00000400)"		},
+    {11	, "Previous Track (0x00000800)"     },
+    {12	, "Next Track (0x00001000)"		    },
+    {13	, "First Track (0x00002000)"		},
+    {14	, "Last Track (0x00004000)"		    },
+    {15	, "Goto Track (0x00008000)"		    },
+    {16	, "Previous Group (0x00010000)"	    },
+    {17	, "Next Group (0x00020000)"		    },
+    {18	, "First Group (0x00040000)"		},
+    {19	, "Last Group (0x00080000)"		    },
+    {20 , "Goto Group (0x00100000)"		    },
+    {21	, "RFU (0x00200000)"				},
+    {22	, "RFU (0x00400000)"				},
+    {23	, "RFU (0x00800000)"				},
+    {24	, "RFU (0x01000000)"				},
+    {25	, "RFU (0x02000000)"				},
+    {26	, "RFU (0x04000000)"				},
+    {27	, "RFU (0x08000000)"				},
+    {28	, "RFU (0x10000000)"				},
+    {29	, "RFU (0x20000000)"				},
+    {30	, "RFU (0x40000000)"				},
+    {31	, "RFU (0x80000000)"				},
+    { }
+};
+
+static void print_media_cp_op_supported(const struct l2cap_frame *frame)
+{
+	uint32_t supported_opcodes;
+	uint32_t mask;
+
+	if (!l2cap_frame_get_le32((void *)frame, &supported_opcodes)) {
+		print_text(COLOR_ERROR, "    value: invalid size");
+		goto done;
+	}
+
+	print_field("      Supported Opcodes: 0x%8.8x", supported_opcodes);
+
+	mask = print_bitfield(8, supported_opcodes, supported_opcodes_table);
+	if (mask)
+		print_text(COLOR_WHITE_BG, "    Unknown fields (0x%4.4x)",
+								mask);
+
+done:
+	if (frame->size)
+		print_hex_field("    Data", frame->data, frame->size);
+}
+
+static void media_cp_op_supported_read(const struct l2cap_frame *frame)
+{
+	print_media_cp_op_supported(frame);
+}
+
+static void media_cp_op_supported_notify(const struct l2cap_frame *frame)
+{
+	print_media_cp_op_supported(frame);
+}
+
+static void print_content_control_id(const struct l2cap_frame *frame)
+{
+	int8_t ccid;
+
+	if (!l2cap_frame_get_u8((void *)frame, (uint8_t *)&ccid)) {
+		print_text(COLOR_ERROR, "  Content Control ID: invalid size");
+		goto done;
+	}
+
+	print_field("  Content Control ID: 0x%2.2x", ccid);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void content_control_id_read(const struct l2cap_frame *frame)
+{
+	print_content_control_id(frame);
+}
+
 #define GATT_HANDLER(_uuid, _read, _write, _notify) \
 { \
 	.uuid = { \
@@ -1776,6 +2270,23 @@  struct gatt_handler {
 	GATT_HANDLER(0x2b7d, vol_state_read, NULL, vol_state_notify),
 	GATT_HANDLER(0x2b7e, NULL, vol_cp_write, NULL),
 	GATT_HANDLER(0x2b7f, vol_flag_read, NULL, vol_flag_notify),
+	GATT_HANDLER(0x2b93, mp_name_read, NULL, mp_name_notify),
+	GATT_HANDLER(0x2b96, NULL, NULL, track_changed_notify),
+	GATT_HANDLER(0x2b97, track_title_read, NULL, track_title_notify),
+	GATT_HANDLER(0x2b98, track_duration_read, NULL, track_duration_notify),
+	GATT_HANDLER(0x2b99, track_position_read, track_position_write,
+					track_position_notify),
+	GATT_HANDLER(0x2b9a, playback_speed_read, playback_speed_write,
+					playback_speed_notify),
+	GATT_HANDLER(0x2b9b, seeking_speed_read, NULL, seeking_speed_notify),
+	GATT_HANDLER(0x2ba1, playing_order_read, playing_order_write,
+					playing_order_notify),
+	GATT_HANDLER(0x2ba2, playing_orders_supported_read, NULL, NULL),
+	GATT_HANDLER(0x2ba3, media_state_read, NULL, media_state_notify),
+	GATT_HANDLER(0x2ba4, NULL, media_cp_write, media_cp_notify),
+	GATT_HANDLER(0x2ba5, media_cp_op_supported_read, NULL,
+					media_cp_op_supported_notify),
+	GATT_HANDLER(0x2bba, content_control_id_read, NULL, NULL),
 };
 
 static struct gatt_handler *get_handler(struct gatt_db_attribute *attr)