feat: add basic logging interface

Introduce a lightweight logger interface, allowing clients to register
custom info, warn, and error handlers. Adds initial integration into
transfer_list.h.

Change-Id: Ia2470ce58566385f3c7df068f600d236c09625ca
Signed-off-by: Harrison Mutai <harrison.mutai@arm.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6aa68d9..a1bd03f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -23,13 +23,13 @@
 add_library(tl
     STATIC
         ${PROJECT_SOURCE_DIR}/src/generic/transfer_list.c
+        ${PROJECT_SOURCE_DIR}/src/generic/logging.c
 )
 
 target_include_directories(tl
     PUBLIC
         ${PROJECT_SOURCE_DIR}/include
 )
-
 target_link_libraries(tl PUBLIC cxx_compiler_flags)
 
 if(PROJECT_API)
diff --git a/include/logging.h b/include/logging.h
new file mode 100644
index 0000000..fdfb2cd
--- /dev/null
+++ b/include/logging.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright The Transfer List Library Contributors
+ *
+ * SPDX-License-Identifier: MIT OR GPL-2.0-or-later
+ */
+
+#ifndef LOGGING_H
+#define LOGGING_H
+
+struct logger_interface {
+	void (*info)(const char *fmt, ...);
+	void (*warn)(const char *fmt, ...);
+	void (*error)(const char *fmt, ...);
+};
+
+extern struct logger_interface *logger;
+
+#define info(...)                                  \
+	do {                                       \
+		if (logger && logger->info)        \
+			logger->info(__VA_ARGS__); \
+	} while (0)
+
+#define warn(...)                                  \
+	do {                                       \
+		if (logger && logger->warn)        \
+			logger->warn(__VA_ARGS__); \
+	} while (0)
+
+#define error(...)                                  \
+	do {                                        \
+		if (logger && logger->error)        \
+			logger->error(__VA_ARGS__); \
+	} while (0)
+
+void libtl_register_logger(struct logger_interface *user_logger);
+
+#endif
diff --git a/src/generic/logging.c b/src/generic/logging.c
new file mode 100644
index 0000000..240a5f7
--- /dev/null
+++ b/src/generic/logging.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright The Transfer List Library Contributors
+ *
+ * SPDX-License-Identifier: MIT OR GPL-2.0-or-later
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "logging.h"
+
+static struct logger_interface _logger;
+struct logger_interface *logger = NULL;
+
+static void default_log(const char *level, const char *fmt, va_list args)
+{
+	printf("[%s] ", level);
+	vprintf(fmt, args);
+}
+
+static void libtl_info(const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	default_log("INFO", fmt, args);
+	va_end(args);
+}
+
+static void libtl_warn(const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	default_log("WARN", fmt, args);
+	va_end(args);
+}
+
+void libtl_error(const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	default_log("ERROR", fmt, args);
+	va_end(args);
+}
+
+void libtl_register_logger(struct logger_interface *user_logger)
+{
+	if (user_logger != NULL) {
+		logger = user_logger;
+	}
+
+	_logger.info = libtl_info;
+	_logger.warn = libtl_warn;
+	_logger.error = libtl_error;
+
+	logger = &_logger;
+};
diff --git a/src/generic/transfer_list.c b/src/generic/transfer_list.c
index 2e681dc..1af7ed7 100644
--- a/src/generic/transfer_list.c
+++ b/src/generic/transfer_list.c
@@ -9,6 +9,7 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <logging.h>
 #include <private/math_utils.h>
 #include <transfer_list.h>
 
@@ -20,22 +21,22 @@
 	if (!tl) {
 		return;
 	}
-	printf("Dump transfer list:\n");
-	printf("signature  0x%x\n", tl->signature);
-	printf("checksum   0x%x\n", tl->checksum);
-	printf("version    0x%x\n", tl->version);
-	printf("hdr_size   0x%x\n", tl->hdr_size);
-	printf("alignment  0x%x\n", tl->alignment);
-	printf("size       0x%x\n", tl->size);
-	printf("max_size   0x%x\n", tl->max_size);
-	printf("flags      0x%x\n", tl->flags);
+	info("Dump transfer list:\n");
+	info("signature  0x%x\n", tl->signature);
+	info("checksum   0x%x\n", tl->checksum);
+	info("version    0x%x\n", tl->version);
+	info("hdr_size   0x%x\n", tl->hdr_size);
+	info("alignment  0x%x\n", tl->alignment);
+	info("size       0x%x\n", tl->size);
+	info("max_size   0x%x\n", tl->max_size);
+	info("flags      0x%x\n", tl->flags);
 	while (true) {
 		te = transfer_list_next(tl, te);
 		if (!te) {
 			break;
 		}
 
-		printf("Entry %d:\n", i++);
+		info("Entry %d:\n", i++);
 		transfer_entry_dump(te);
 	}
 }
@@ -43,11 +44,11 @@
 void transfer_entry_dump(struct transfer_list_entry *te)
 {
 	if (te) {
-		printf("tag_id     0x%x\n", te->tag_id);
-		printf("hdr_size   0x%x\n", te->hdr_size);
-		printf("data_size  0x%x\n", te->data_size);
-		printf("data_addr  0x%lx\n",
-		       (unsigned long)transfer_list_entry_data(te));
+		info("tag_id     0x%x\n", te->tag_id);
+		info("hdr_size   0x%x\n", te->hdr_size);
+		info("data_size  0x%x\n", te->data_size);
+		info("data_addr  0x%lx\n",
+		     (unsigned long)transfer_list_entry_data(te));
 	}
 }
 
@@ -139,46 +140,44 @@
 	}
 
 	if (tl->signature != TRANSFER_LIST_SIGNATURE) {
-		printf("Bad transfer list signature %#" PRIx32 "\n",
-		       tl->signature);
+		warn("Bad transfer list signature %#" PRIx32 "\n",
+		     tl->signature);
 		return TL_OPS_NON;
 	}
 
 	if (!tl->max_size) {
-		printf("Bad transfer list max size %#" PRIx32 "\n",
-		       tl->max_size);
+		warn("Bad transfer list max size %#" PRIx32 "\n", tl->max_size);
 		return TL_OPS_NON;
 	}
 
 	if (tl->size > tl->max_size) {
-		printf("Bad transfer list size %#" PRIx32 "\n", tl->size);
+		warn("Bad transfer list size %#" PRIx32 "\n", tl->size);
 		return TL_OPS_NON;
 	}
 
 	if (tl->hdr_size != sizeof(struct transfer_list_header)) {
-		printf("Bad transfer list header size %#" PRIx32 "\n",
-		       tl->hdr_size);
+		warn("Bad transfer list header size %#" PRIx32 "\n",
+		     tl->hdr_size);
 		return TL_OPS_NON;
 	}
 
 	if (!transfer_list_verify_checksum(tl)) {
-		printf("Bad transfer list checksum %#" PRIx32 "\n",
-		       tl->checksum);
+		warn("Bad transfer list checksum %#" PRIx32 "\n", tl->checksum);
 		return TL_OPS_NON;
 	}
 
 	if (tl->version == 0) {
-		printf("Transfer list version is invalid\n");
+		warn("Transfer list version is invalid\n");
 		return TL_OPS_NON;
 	} else if (tl->version == TRANSFER_LIST_VERSION) {
-		printf("Transfer list version is valid for all operations\n");
+		info("Transfer list version is valid for all operations\n");
 		return TL_OPS_ALL;
 	} else if (tl->version > TRANSFER_LIST_VERSION) {
-		printf("Transfer list version is valid for read-only\n");
+		info("Transfer list version is valid for read-only\n");
 		return TL_OPS_RO;
 	}
 
-	printf("Old transfer list version is detected\n");
+	info("Old transfer list version is detected\n");
 	return TL_OPS_CUS;
 }