I wonder, how can I access TCP4Protocol to use in my DXE driver.
I already asked similar question: myFirstQestion
Now I can't find the solution to solve the error.
Because I get my debug string "Can't create child" when trying to load the driver. Picking my code below.
Or maybe somebody knows how to complete my task from the link through dxe driver.
Thank you.
#include "Uefi.h"
#include <Protocol/Tcp4.h>
#include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/ServiceBinding.h>
#include <Protocol/SimpleNetwork.h>
#include <Library/DebugLib.h>
EFI_STATUS
EFIAPI
Net1DriverDxeEntry(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
{
EFI_TCP4_PROTOCOL *TCP4protocol = NULL;
EFI_SERVICE_BINDING_PROTOCOL *TCP4ServiceBinding = NULL;
EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetworkProtocol = NULL;
EFI_HANDLE *HandleBuffer = NULL;
EFI_HANDLE *TCP4Handle = NULL;
UINTN HandleCount;
UINTN i;
CHAR16 *Deb1 = L"Simple network protocol not found\r\n";
CHAR16 *Deb2 = L"TCP4 protocol not found\r\n";
CHAR16 *Deb3 = L"Can't create child\r\n";
CHAR16 *Deb4 = L"Can't handle protocol\n\r\n";
EFI_STATUS Status = gBS->LocateProtocol(&gEfiSimpleNetworkProtocolGuid,NULL, (VOID**) &SimpleNetworkProtocol);
if (EFI_ERROR (Status))
{
DEBUG((-1, "ShowStatus: Simple network protocol not found\n"));
gST->ConOut->OutputString(gST->ConOut, Deb1);
return EFI_UNSUPPORTED;
}
Status = gBS->LocateHandleBuffer(ByProtocol,&gEfiTcp4ProtocolGuid, NULL, &HandleCount,&HandleBuffer);
if (EFI_ERROR (Status))
{
gST->ConOut->OutputString(gST->ConOut, Deb2);
DEBUG((-2, "ShowStatus: TCP4 protocol not found\n"));
return EFI_UNSUPPORTED;
}
for (i = 0; i < HandleCount; i ++)
{
Status = gBS->HandleProtocol(HandleBuffer[i], &gEfiTcp4ServiceBindingProtocolGuid,(VOID **) &TCP4ServiceBinding);
if(EFI_ERROR (Status))
{
DEBUG((-3, "\n"));
gST->ConOut->OutputString(gST->ConOut, Deb3);
return EFI_UNSUPPORTED;
}
TCP4ServiceBinding->CreateChild(TCP4ServiceBinding, TCP4Handle);
Status = gBS->HandleProtocol(TCP4Handle,&gEfiTcp4ProtocolGuid,(VOID **) &TCP4protocol);
if(EFI_ERROR (Status))
{
gST->ConOut->OutputString(gST->ConOut, Deb4);
DEBUG((-4, "ShowStatus: Can't handle protocol\n"));
return EFI_UNSUPPORTED;
}
}
return EFI_SUCCESS;
}
TCP4Handle should be of type EFI_HANDLE not EFI_HANDLE*.
EFI_HANDLE TCP4Handle = NULL;
//....
TCP4ServiceBinding->CreateChild(TCP4ServiceBinding, &TCP4Handle);
And you must look for gEfiTcp4ServiceBindingProtocolGuid not gEfiTcp4ProtocolGuid.
Status = gBS->LocateHandleBuffer(ByProtocol,&gEfiTcp4ServiceBindingProtocolGuid, NULL, &HandleCount,&HandleBuffer);
Related
I have created the following c program based on a provided sample in order just to get messages from iot hub :
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include "azure_c_shared_utility/shared_util_options.h"
#include "iothub_client.h"
#include "iothub_message.h"
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/platform.h"
#include "iothubtransportmqtt.h"
#include "iothub_client_options.h"
#include "iothub_device_client_ll.h"
#include "iothub_device_client.h"
#include "iothub_client_sample_mqtt_esp8266.h"
/*String containing Hostname, Device Id & Device Key in the format: */
/* "HostName=<host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>" */
/* "HostName=<host_name>;DeviceId=<device_id>;SharedAccessSignature=<device_sas_token>" */
static const char* connectionString = "HostName=mydevice";
static int callbackCounter;
//static char msgText[1024];
//static char propText[1024];
static bool g_continueRunning;
#define MESSAGE_COUNT 50
#define SET_TRUSTED_CERT_IN_SAMPLES
#define DOWORK_LOOP_NUM 3
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
#include "certs.h"
#endif
typedef struct EVENT_INSTANCE_TAG
{
IOTHUB_MESSAGE_HANDLE messageHandle;
size_t messageTrackingId; // For tracking the messages within the user callback.
} EVENT_INSTANCE;
static IOTHUBMESSAGE_DISPOSITION_RESULT ReceiveMessageCallback(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback)
{
int* counter = (int*)userContextCallback;
const char* buffer;
size_t size;
MAP_HANDLE mapProperties;
const char* messageId;
const char* correlationId;
// Message properties
if ((messageId = IoTHubMessage_GetMessageId(message)) == NULL)
{
messageId = "<null>";
}
if ((correlationId = IoTHubMessage_GetCorrelationId(message)) == NULL)
{
correlationId = "<null>";
}
// Message content
if (IoTHubMessage_GetByteArray(message, (const unsigned char**)&buffer, &size) != IOTHUB_MESSAGE_OK)
{
(void)printf("unable to retrieve the message data\r\n");
}
else
{
(void)printf("Received Message [%d]\r\n Message ID: %s\r\n Correlation ID: %s\r\n Data: <<<%.*s>>> & Size=%d\r\n", *counter, messageId, correlationId, (int)size, buffer, (int)size);
// If we receive the work 'quit' then we stop running
if (size == (strlen("quit") * sizeof(char)) && memcmp(buffer, "quit", size) == 0)
{
g_continueRunning = false;
}
}
// Retrieve properties from the message
mapProperties = IoTHubMessage_Properties(message);
if (mapProperties != NULL)
{
const char*const* keys;
const char*const* values;
size_t propertyCount = 0;
if (Map_GetInternals(mapProperties, &keys, &values, &propertyCount) == MAP_OK)
{
if (propertyCount > 0)
{
size_t index;
std::string uid;
printf(" Message Properties:\r\n");
for (index = 0; index < propertyCount; index++)
{
(void)printf("\tKey: %s Value: %s\r\n", keys[index], values[index]);
if (std::strcmp(keys[index],"uid") == 0 )
{
uid = values[index];
std::cout << "uid is " << uid << std::endl;
}
}
(void)printf("\r\n");
}
}
}
/* Some device specific action code goes here... */
(*counter)++;
return IOTHUBMESSAGE_ACCEPTED;
}
// static void SendConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback)
// {
// EVENT_INSTANCE* eventInstance = (EVENT_INSTANCE*)userContextCallback;
// size_t id = eventInstance->messageTrackingId;
// (void)printf("Confirmation[%d] received for message tracking id = %d with result = %s\r\n", callbackCounter, (int)id, MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result));
// /* Some device specific action code goes here... */
// callbackCounter++;
// IoTHubMessage_Destroy(eventInstance->messageHandle);
// }
static void connection_status_callback(IOTHUB_CLIENT_CONNECTION_STATUS result, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void* user_context)
{
(void)reason;
(void)user_context;
// This sample DOES NOT take into consideration network outages.
if (result == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED)
{
(void)printf("The device client is connected to iothub\r\n");
}
else
{
(void)printf("The device client has been disconnected\r\n");
}
}
void iothub_client_sample_mqtt_esp8266_run(void)
{
IOTHUB_CLIENT_HANDLE iotHubClientHandle;
g_continueRunning = true;
srand((unsigned int)time(NULL));
callbackCounter = 0;
int receiveContext = 0;
if (platform_init() != 0)
{
(void)printf("Failed to initialize the platform.\r\n");
}
else
{
if ((iotHubClientHandle = IoTHubClient_CreateFromConnectionString(connectionString, MQTT_Protocol)) == NULL)
{
(void)printf("ERROR: iotHubClientHandle is NULL!\r\n");
}
else
{
bool traceOn = true;
IoTHubClient_SetOption(iotHubClientHandle, OPTION_LOG_TRACE, &traceOn);
#ifdef SET_TRUSTED_CERT_IN_SAMPLES
// For mbed add the certificate information
if (IoTHubClient_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK)
{
(void)printf("failure to set option \"TrustedCerts\"\r\n");
}
#endif
(void)IoTHubDeviceClient_SetConnectionStatusCallback(iotHubClientHandle, connection_status_callback, NULL);
/* Setting Message call back, so we can receive Commands. */
if (IoTHubClient_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, &receiveContext) != IOTHUB_CLIENT_OK)
{
(void)printf("ERROR: IoTHubClient_LL_SetMessageCallback..........FAILED!\r\n");
}
else
{
(void)printf("IoTHubClient_LL_SetMessageCallback...successful.\r\n");
while (g_continueRunning)
{
ThreadAPI_Sleep(1000);
}
}
IoTHubClient_Destroy(iotHubClientHandle);
}
platform_deinit();
}
}
int main(void)
{
iothub_client_sample_mqtt_esp8266_run();
return 0;
}
Everything works fine. I get both messageid and correlationid correctly.
However I'd like to receive EventEnqueuedUtcTime at my callback which is mentioned here https://learn.microsoft.com/en-us/azure/stream-analytics/stream-analytics-define-inputs#configure-an-iot-hub-as-a-data-stream-input.
Since I'm quite new at this SDK I haven't a way to achieve this. Does anyone has an idea ?
I think you are confusing the device SDK and the service SDK. The EventEnqueuedUtcTime is available to a service side application that is reading the telemetry sent by devices to the IoT hub. I'm assuming that you expected to get that same value for a message delivered to your device via a Cloud to Device message which would be delivered to your callback function ReceiveMessageCallback. That property is not added to messages from the cloud to the device only messages from the device to the cloud.
I am trying to work with an API of one device, but it is using a WS interface with enforced Origin header, which is giving me troubles.
In Chrome, I can open the Console while a page with the correct Origin is loaded, create the WS connection, and send/receive messages without difficulties:
Note that sent messages (in green) are always acknowledged by the server.
For reference, this is what happens if I create the connection on a different page, which results in an Origin header mismatch, reported as 404:
To sidestep this problem, I turned to C, because the rest of my program is written in that anyway. This is the code I have right now, based mostly on this answer:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <libwebsockets.h>
#define KGRN "\033[0;32;32m"
#define KCYN "\033[0;36m"
#define KRED "\033[0;32;31m"
#define KYEL "\033[1;33m"
#define KBLU "\033[0;32;34m"
#define KCYN_L "\033[1;36m"
#define KBRN "\033[0;33m"
#define RESET "\033[0m"
static int destroy_flag = 0;
static int connection_flag = 0;
static int writeable_flag = 0;
static void INT_HANDLER(int signo) {
destroy_flag = 1;
}
struct session_data {
int fd;
};
struct pthread_routine_tool {
struct lws_context *context;
struct lws *wsi;
};
static int websocket_write_back(struct lws *wsi_in, char *str, int str_size_in)
{
if (str == NULL || wsi_in == NULL)
return -1;
int n;
int len;
char *out = NULL;
if (str_size_in < 1)
len = strlen(str);
else
len = str_size_in;
out = (char *)malloc(sizeof(char)*(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING));
//* setup the buffer*/
memcpy (out + LWS_SEND_BUFFER_PRE_PADDING, str, len );
//* write out*/
n = lws_write(wsi_in, out + LWS_SEND_BUFFER_PRE_PADDING, len, LWS_WRITE_TEXT);
printf(KBLU"[websocket_write_back] %s\n"RESET, str);
//* free the buffer*/
free(out);
return n;
}
static int ws_service_callback(
struct lws *wsi,
enum lws_callback_reasons reason, void *user,
void *in, size_t len)
{
switch (reason) {
case LWS_CALLBACK_CLIENT_ESTABLISHED:
printf(KYEL"[Main Service] Connect with server success.\n"RESET);
connection_flag = 1;
break;
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
printf(KRED"[Main Service] Connect with server error.\n"RESET);
destroy_flag = 1;
connection_flag = 0;
break;
case LWS_CALLBACK_CLOSED:
printf(KYEL"[Main Service] LWS_CALLBACK_CLOSED\n"RESET);
destroy_flag = 1;
connection_flag = 0;
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
printf(KCYN_L"[Main Service] Client recvived:%s\n"RESET, (char *)in);
if (writeable_flag)
destroy_flag = 1;
break;
case LWS_CALLBACK_CLIENT_WRITEABLE :
printf(KYEL"[Main Service] On writeable is called. send byebye message\n"RESET);
websocket_write_back(wsi, "{\"command\":\"subscribe\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"D0E91\\\"}\"}", -1);
websocket_write_back(wsi, "{\"command\":\"message\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"D0E91\\\"}\",\"data\":\"{\\\"value\\\":100,\\\"action\\\":\\\"set_buzz\\\"}\"}", -1);
writeable_flag = 1;
break;
default:
break;
}
return 0;
}
static void *pthread_routine(void *tool_in)
{
struct pthread_routine_tool *tool = tool_in;
printf(KBRN"[pthread_routine] Good day. This is pthread_routine.\n"RESET);
//* waiting for connection with server done.*/
while(!connection_flag)
usleep(1000*20);
//*Send greeting to server*/
lws_callback_on_writable(tool->wsi);
}
int main(void)
{
//* register the signal SIGINT handler */
struct sigaction act;
act.sa_handler = INT_HANDLER;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction( SIGINT, &act, 0);
struct lws_context *context = NULL;
struct lws_context_creation_info info;
struct lws *wsi = NULL;
struct lws_protocols protocol;
memset(&info, 0, sizeof info);
info.port = CONTEXT_PORT_NO_LISTEN;
info.iface = NULL;
info.protocols = &protocol;
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
info.extensions = lws_get_internal_extensions();
info.gid = -1;
info.uid = -1;
info.options = 0;
protocol.name = "websockets";
protocol.callback = &ws_service_callback;
protocol.per_session_data_size = sizeof(struct session_data);
protocol.rx_buffer_size = 0;
protocol.id = 0;
protocol.user = NULL;
context = lws_create_context(&info);
printf(KRED"[Main] context created.\n"RESET);
if (context == NULL) {
printf(KRED"[Main] context is NULL.\n"RESET);
return -1;
}
wsi = lws_client_connect(context, "mobu1.herokuapp.com", 443, 1,
"/cable", "mobu1.herokuapp.com", "link.motorbunny.com",
if (wsi == NULL) {
printf(KRED"[Main] wsi create error.\n"RESET);
return -1;
}
printf(KGRN"[Main] wsi create success.\n"RESET);
struct pthread_routine_tool tool;
tool.wsi = wsi;
tool.context = context;
pthread_t pid;
pthread_create(&pid, NULL, pthread_routine, &tool);
pthread_detach(pid);
while(!destroy_flag)
{
lws_service(context, 50);
}
lws_context_destroy(context);
return 0;
}
The result of running the above program is this:
As you can see, the periodic pings from server to my client are being picked up, but the lws_callback_on_writable(wsi); seems to have no effect as the LWS_CALLBACK_CLIENT_WRITEABLE callback never gets called. Additionally, if I call websocket_write_back() directly anywhere else, it doesn't seem to be sending anything to the server, and no acknowledgement is present either.
Is there something obvious I am doing wrong?
EDIT 1:
I found this neat wscat, where I can replicate the results from Chrome:
Now the question is, how can I interface this with my C program in a way that it can wait for the Welcome message from the server, and then send two messages?
And better yet, how to stay connected, so that my program can send multiple commands at different points of time without having to do the handshake all the time?
The reason why the LWS_CALLBACK_CLIENT_WRITEABLE callback never got called was because this particular server uses non-standard handshake. So, to bypass this, I forked a fork of libwsclient and modified the handshake checking function to not fail on mismatch. I also added an optional Origin header.
Now, all I need to do in my original program is
wsclient *client;
char sync_str[6];
void mb_send(int power, char* type)
{
char cmd[2048];
sprintf (cmd, "{\"command\":\"message\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"%s\\\"}\",\"data\":\"{\\\"value\\\":%d,\\\"action\\\":\\\"set_%s\\\"}\"}",sync_str,power,type);
libwsclient_send(client,cmd);
}
void mb_connect()
{
char cmd[2048];
sprintf (cmd, "{\"command\":\"subscribe\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"%s\\\"}\"}",sync_str);
libwsclient_send(client,cmd);
mb_send(0,"buzz");
}
int nop()
{
return 0;
}
int main()
{
client = libwsclient_new_extra("wss://mobu1.herokuapp.com/cable","https://link.motorbunny.com");
if(!client) {
fprintf(stderr, "Unable to initialize new WS client.\n");
exit(1);
}
libwsclient_onopen(client, &nop);
libwsclient_onmessage(client, &nop);
libwsclient_onerror(client, &nop);
libwsclient_onclose(client, &nop);
libwsclient_run(client);
...
mb_connect();
...
mb_send(200,"buzz");
mb_send(40,"twirl");
...
mb_send(0,"buzz");
mb_send(0,"twirl");
}
I found an ugly hack to make my C program send WebSocket messages to a server via the wsta program.
It requires a text file, into which my program will append whenever it wants to send a message to the server. The new lines are then picked up in the background by tail -f, and are piped to wsta which maintains the connection. Output can be redirected to /dev/null so that the wsta output doesn't pollute the output of my program, or sent to a file if responses from the server need to be parsed.
The whole script to make this work would look like this (or you could use FIFO pipe with cat instead of a file with tail):
#!/bin/bash
touch commands.txt
tail commands.txt -f -n 0 | wsta --header "Origin: https://link.motorbunny.com" "wss://mobu1.herokuapp.com/cable" &> /dev/null &
./program
In the C program, I just need to write to the commands.txt file:
FILE* cmd;
char sync_str[6];
void mb_connect()
{
fprintf (cmd, "{\"command\":\"subscribe\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"%s\\\"}\"}\n",sync_str);
fflush(cmd);
}
void mb_send(int power, char* type)
{
fprintf (cmd, "{\"command\":\"message\",\"identifier\":\"{\\\"channel\\\":\\\"DevicesChannel\\\",\\\"share_token\\\":\\\"%s\\\"}\",\"data\":\"{\\\"value\\\":%d,\\\"action\\\":\\\"set_%s\\\"}\"}\n",sync_str,power,type);
fflush(cmd);
}
int main()
{
cmd = fopen ("commands.txt","w");
...
mb_connect();
...
mb_send(200,"buzz");
...
mb_send(0,"buzz");
}
I have everything was working OK, until today I on MQOPEN got error
2085 MQRC_UNKNOWN_OBJECT_NAME
#include <stdio.h>
#include <cmqc.h>
#include <cmqxc.h>
#include "dte_mq.h"
#include <string.h>
#include <stdlib.h>
typedef struct tagDTE_QUEUE_DESCRIPTOR
{
MQHOBJ handle;
int IsSyncpointControled;
} DTE_QUEUE_DESCRIPTOR, *PDTE_QUEUE_DESCRIPTOR;
static MQHCONN sHConn = 0;
static MQLONG sCompCode = MQCC_OK;
static MQLONG sReason = MQRC_NONE;
static int sNumOpenQueues = 0;
static PDTE_QUEUE_DESCRIPTOR sQueues = NULL;
MQLONG OpenCode;
MQOD od = {MQOD_DEFAULT}; /* Object Descriptor */
MQMD md = {MQMD_DEFAULT};
MQPMO pmo = {MQPMO_DEFAULT};
MQLONG O_options;/* MQCONNX options */
MQCNO Connect_options = {MQCNO_DEFAULT};
/* Client connection channel */
MQCD ClientConn = {MQCD_CLIENT_CONN_DEFAULT};
#define MAX_NUM_OPEN_QUEUES 10
int dteMqOpen(const char *name, int *qd)
{
MQLONG options;
MQHOBJ hObj;
int i;
printf("SAM\n");
strncpy(od.ObjectName, name, MQ_Q_NAME_LENGTH);
printf("SAM2\n");
O_options = MQOO_INPUT_AS_Q_DEF + MQOO_FAIL_IF_QUIESCING;
printf("SAM3\n");
MQOPEN(sHConn, &od, O_options, &hObj, &sCompCode, &sReason);
printf("MQopen = %d and %d\n",sCompCode,sReason);
if (sCompCode != MQCC_OK)
{
printf("RETURN %d\n",DTE_MQR_FAILED);
return DTE_MQR_FAILED;
}
++sNumOpenQueues;
*qd = 1;
for(i = 0; i < MAX_NUM_OPEN_QUEUES; i++)
{
printf("In the loop1\n");
if(sQueues[i].handle == -1)
{
*qd = i;
printf("QDESC1 = %d\n",qd);
sQueues[i].handle = hObj;
sQueues[i].IsSyncpointControled = 0;
break;
}
printf("In the loop\n");
}
printf("QDESC = %d\n",qd);
return DTE_MQR_OK;
}
Function call is:
qd = -1;
dteretopen = dteMqOpen(QName, &qd);
printf ("Return code from dteMqOpen = %d\n",dteretopen);
if (dteretopen ==0)
{
printf("MQOPEN could not open MQ, check errpr log\n");
exit(99);
}
Error 2085. But several days before there was no such error
Connection is OK, but MQOPEN failed
dteretopen = dteMqOpen(QName, &qd);
Clearly 'QName' has an invalid value.
You have been posting question after question about the same program. Obviously, you have zero training in MQ programming. You need to get some MQ training ASAP. There is lots and lots of information on the web and videos too.
Why aren't you doing some basic debugging and outputting 'QName?
You need to take some initiative in debugging your program before posting questions here. We are not here to do your work.
I'm trying to develop a sound card driver with ALSA.
My goal eventually is to use:
PCM through I2S.
Control the volume through SPI.
For simplicity I started with volume control ONLY, no PCM.
I wrote the driver and compiled but I'm having 2 issues:
I cannot successfully call snd_card_free in the module exit. I tried storing the snd_card pointer which is successfully allocated in the module init in my custom "snd_adsp21479_chip" structure and use container_of to get the snd_card but the card is always null in the module_exit (it was not null in the module_init and is successfully allocated, I have the checks, I could also successfully call snd_card_free(card) in the module init function, but nowhere else). So every time I reload the module to the kernel, I end up with one more sound card and a new control in /dev/snd/ and proc/asound/devices
My biggest problem now is after loading the module I do see a new control (control1) in /dev/snd/ and a new card there, however using amixer I do not see the card's Volume control. I run amixer conctrols, and I do not see my new control.
Here's the code:
#include <linux/wait.h>
#include <sound/control.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#define LOW_SPEED_SPIDEV_SPI_BUS 0
#define LOW_SPEED_SPIDEV_SPI_CS 0
#define LOW_SPEED_SPIDEV_MAX_CLK_HZ 100000
#define SOUND_CARD_NAME "adsp21479"
static struct spi_board_info cal_spi_board_info = {
.modalias = "spidev",
.bus_num = LOW_SPEED_SPIDEV_SPI_BUS,
.chip_select = LOW_SPEED_SPIDEV_SPI_CS,
.max_speed_hz = LOW_SPEED_SPIDEV_MAX_CLK_HZ,
};
static struct spi_device *spi = NULL;
struct snd_adsp21479_chip {
struct spi_device *spi;
struct snd_card *card;
};
/*******************************CONTROL METHODS *******************************/
static int snd_adsp21479_stereo_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info * uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 100;
return 0;
}
static int snd_adsp21479_stereo_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return 0;
}
static int snd_adsp21479_stereo_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return 0;
}
static struct snd_kcontrol_new volume_control = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Volume",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = snd_adsp21479_stereo_info,
.get = snd_adsp21479_stereo_get,
.put = snd_adsp21479_stereo_put
};
static int snd_adsp21479_init(struct spi_device *spi)
{
struct snd_card * card = NULL;
int return_value;
char id[10] = SOUND_CARD_NAME;
struct snd_adsp21479_chip *chip;
pr_info("snd_adsp21479_init start\n");
return_value = snd_card_new(&spi->dev,-1,id,THIS_MODULE,sizeof(struct snd_adsp21479_chip),&card);
if(return_value<0)
{
pr_err("snd_card_new failed\n");
return return_value;
}
if(!card)
{
pr_err("snd_card_new did not allocate card");
return -ENODEV;
}
pr_info("sound card=%p created successfully",card);
chip = card->private_data;
chip->card = card;
chip->spi = spi;
strcpy(card->mixername,"adsp21479 Mixer");
return_value = snd_ctl_add(card,snd_ctl_new1(&volume_control,chip));
if(return_value<0)
{
pr_err("snd_ctl_add faile adding control\n");
return return_value;
}
pr_info("created a mixer control");
static struct snd_device_ops ops = { NULL};
strcpy(card->driver,SOUND_CARD_NAME);
strcpy(card->shortname,SOUND_CARD_NAME);
strcpy(card->longname,"DAQRI ADSP21479 Sound Driver");
//create an ALSA device component
return_value = snd_device_new(card, SNDRV_DEV_LOWLEVEL,chip,&ops);
if(return_value<0)
{
printk(KERN_ALERT"creating an ALSA device component failed");
return return_value;
}
pr_info("created an ASLA device SNDRV_DEV_LOWLEVEL");
return_value = snd_card_register(card);
if(return_value<0)
{
pr_err("snd_card_register failed\n");
return return_value;
}
if(!card)
{
pr_err("card turned into null\n");
}
pr_info("registered sound card\n");
pr_info("adsp21479_snd_driver loaded successfully\n");
return 0;
// card here is always ok, and if I call snd_card_free(card) here it works.
}
static int __init adsp21479_spi_module_init(void)
{
struct spi_master *master=NULL;
int err;
pr_info("module init\n");
err = -ENODEV;
master = spi_busnum_to_master(LOW_SPEED_SPIDEV_SPI_BUS);
pr_info("master=%p\n", master);
if (!master)
{
pr_err("spi_busnum_to_master failed");
return err;
}
spi = spi_new_device(master, &cal_spi_board_info);
pr_info("spi device =%p\n", spi);
if (!spi)
{
pr_err("spi_new_device failed");
return err;
}
pr_info("spi device registered\n");
err = 0;
return snd_adsp21479_init(spi);
}
static void __exit adsp21479_spi_module_exit(void)
{
struct snd_adsp21479_chip *chip;
pr_info("module exit");
if (spi)
{
chip = container_of(&spi,struct snd_adsp21479_chip,spi);
if(chip)
{
pr_info("chip is not null\n");
if(chip->spi == spi)
{
pr_info("spi match\n");
}
pr_info("card = %p",chip->card);
if(chip->card != NULL)
{
pr_info("freeing sound card=%p\n",chip->card); // I never get here, it's always null, or if I store card in a global variable, I get an exception. And if I store it with drv_set_drvdata(&spi->dev,card) in the init function and try to obtain it here with a dev_get_drvdata(&spi->dev); and try to free the card with snd_card_free I get an exception as well.
snd_card_free(chip->card);
}
}
pr_info("unregistering spi device\n");
spi_unregister_device(spi);
}
}
module_init(adsp21479_spi_module_init);
module_exit(adsp21479_spi_module_exit);
/***************************SPI DRIVER METHODS ****************************/
MODULE_LICENSE("GPL"); ///WE NEED TO CHANGE IT LATER MAYBE
MODULE_DESCRIPTION(" Sound driver for the ADSP-21479");
So to reiterate: No PCM here ,I'm just trying to control the volume through SPI, and my control doesn't show up in amixer, and I can't free my card. I'm using the spidev as my SPI BUS master, and this driver is for the Sound card SPI slave.
I currently use ldap_bind_s to bind to the server in my C application with SEC_WINNT_AUTH_IDENTITY struct, but the function is marked as deprecated. For this reason I would like to change it to the ldap_sasl_bind_s function.
int main(void) {
LDAP *ld;
int rc = 0;
char *binddn = "cn=admin,dc=local";
const int version = LDAP_VERSION3;
SEC_WINNT_AUTH_IDENTITY wincreds;
struct berval saslcred;
wincreds.User = "admin";
wincreds.UserLength = 5;
wincreds.Password = "secret";
wincreds.PasswordLength = 6;
wincreds.Domain = NULL;
wincreds.DomainLength = 0;
wincreds.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
ld = ldap_initA("localhost", LDAP_PORT);
ldap_set_optionA(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
rc = ldap_bind_sA(ld, binddn, (PCHAR)&wincreds, LDAP_AUTH_DIGEST);
printf("0x%x\n", rc); // It's OK (0x0)
ldap_unbind(ld);
saslcred.bv_val = "secret";
saslcred.bv_len = 6;
rc = ldap_sasl_bind_sA(ld, binddn, "DIGEST-MD5", &saslcred, NULL, NULL, NULL);
printf("0x%x\n", rc); // Returns with 0x59
ldap_unbind(ld)
return 0;
}
The ldap_sasl_bind_s returns with LDAP_PARAM_ERROR code. Clearly, the function parameters are wrong above, but I can't find a working sample code with winldap and SASL binding.
I would be grateful for some guide, how to make this code working.
The last parameter of ldap_sasl_bind_sA cannot be NULL. It has to point to a place the function can put the server's response (struct berval*).
...
struct berval* serverResponse = NULL;
rc = ldap_sasl_bind_sA(ld, binddn, "DIGEST-MD5", &saslcred, NULL, NULL, &serverResponse);
...
So finally, after some research and debugging in the past two weeks, I've managed to write a working example code that uses DIGEST-MD5 authentication with WinLDAP's ldap_sasl_bind_s function. The corresponding RFC, this answer and the official SSPI documentation gave me a lot of helps.
Some gotchas that I ran into:
Regardless what documentation says about the ldap_connect function: If you would like to use the ldap_sasl_bind_s function it is not just a "good programming practice" to call it first, it is necessary. Without it the ldap_sasl_bind_s returns with LDAP_SERVER_DOWN (0x51) error code.
The valid pszTargetName (digest-uri) parameter is crucial for the InitializeSecurityContext function to avoid invalid token error.
I hope it will help others to spend less time about figuring out how to use SASL binding mechanisms with WinLDAP.
#include <stdio.h>
#include <windows.h>
#include <winldap.h>
#define SECURITY_WIN32 1
#include <security.h>
#include <sspi.h>
int _tmain(int argc, _TCHAR* argv[]) {
LDAP *ld;
int rc = 0;
const int version = LDAP_VERSION3;
SEC_WINNT_AUTH_IDENTITY wincreds;
struct berval *servresp = NULL;
SECURITY_STATUS res;
CredHandle credhandle;
CtxtHandle newhandle;
SecBufferDesc OutBuffDesc;
SecBuffer OutSecBuff;
SecBufferDesc InBuffDesc;
SecBuffer InSecBuff;
unsigned long contextattr;
ZeroMemory(&wincreds, sizeof(wincreds));
// Set credential information
wincreds.User = (unsigned short *)L"root";
wincreds.UserLength = 4;
wincreds.Password = (unsigned short *)L"p#ssword";
wincreds.PasswordLength = 8;
wincreds.Domain = NULL;
wincreds.DomainLength = 0;
wincreds.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
res = AcquireCredentialsHandle(NULL, L"WDigest", SECPKG_CRED_OUTBOUND,
NULL, &wincreds, NULL, NULL, &credhandle, NULL);
// Buffer for the output token.
OutBuffDesc.ulVersion = 0;
OutBuffDesc.cBuffers = 1;
OutBuffDesc.pBuffers = &OutSecBuff;
OutSecBuff.BufferType = SECBUFFER_TOKEN;
OutSecBuff.pvBuffer = NULL;
ld = ldap_init(L"localhost", LDAP_PORT);
rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void*)&version);
rc = ldap_connect(ld, NULL); // Need to connect before SASL bind!
do {
if (servresp != NULL) {
InBuffDesc.ulVersion = 0;
InBuffDesc.cBuffers = 1;
InBuffDesc.pBuffers = &InSecBuff;
/* The digest-challenge will be passed as an input buffer to
InitializeSecurityContext function */
InSecBuff.cbBuffer = servresp->bv_len;
InSecBuff.BufferType = SECBUFFER_TOKEN;
InSecBuff.pvBuffer = servresp->bv_val;
/* The OutBuffDesc will contain the digest-response. */
res = InitializeSecurityContext(&credhandle, &newhandle, L"ldap/localhost", ISC_REQ_MUTUAL_AUTH | ISC_REQ_ALLOCATE_MEMORY,
0, 0, &InBuffDesc, 0, &newhandle, &OutBuffDesc, &contextattr, NULL);
}
else {
res = InitializeSecurityContext(&credhandle, NULL, L"ldap/localhost", ISC_REQ_MUTUAL_AUTH, 0, 0, NULL, 0, &newhandle, &OutBuffDesc, &contextattr, NULL);
}
switch (res) {
case SEC_I_COMPLETE_NEEDED:
case SEC_I_COMPLETE_AND_CONTINUE:
case SEC_E_OK:
case SEC_I_CONTINUE_NEEDED:
break;
case SEC_E_INVALID_HANDLE:
return -2;
case SEC_E_INVALID_TOKEN:
return -1;
default:
break;
}
struct berval cred;
cred.bv_len = OutSecBuff.cbBuffer;
/* The digest-response will be passed to the server
as credential after the second (loop)run. */
cred.bv_val = (char *)OutSecBuff.pvBuffer;
// The servresp will contain the digest-challange after the first call.
rc = ldap_sasl_bind_s(ld, L"", L"DIGEST-MD5", &cred, NULL, NULL, &servresp);
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &res)
} while (res == LDAP_SASL_BIND_IN_PROGRESS);
if (rc != LDAP_SUCCESS) {
printf("Bind failed with 0x%x\n", rc);
} else {
printf("Bind succeeded\n");
}
return 0;
}