Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled - arduino-esp32

I want to use timer interrupter combined with BLE to transmit in esp32.
I found that an error occurs when the transmission cycle is too fast.
I don't know what caused this error.
Help me plz.............................................................................................
The error
This is my code
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
////////////////////////////////////////////////////////////
#include <BLE2902.h>
#define PERIOD_MS 5
#define BAUD_RATE 115200
#define BLE_WR_EN 0x5A
#define BLE_WR_DIS 0x55
#define SERVICE_UUID "0000ffe0-0000-1000-8000-00805f9b34fb"
#define CHARACTERISTIC_UUID_RX "0000ffe2-0000-1000-8000-00805f9b34fb"
#define CHARACTERISTIC_UUID_TX "0000ffe1-0000-1000-8000-00805f9b34fb"
int PERIOD_US=PERIOD_MS*1000;
/* create a hardware timer */
hw_timer_t * timer = NULL;
/* LED pin */
int led = 2;
/* LED state */
volatile byte state = LOW;
int i=0;
BLEServer *pServer;
BLEService *pService;
BLECharacteristic *pCharacteristic;
void IRAM_ATTR onTimer(){
//state = !state;
if(i<700){
i++;
}
else{
i=0;
}
//Serial.println(state);
char txString[8];
dtostrf(i, 1, 2, txString);
pCharacteristic->setValue(txString);
pCharacteristic->notify();
std::string txValue=pCharacteristic->getValue();
Serial.print("txValue:");
Serial.println(txValue.c_str());
//digitalWrite(led, state);
}
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
Serial.println("********************************");
Serial.println("Connected");
Serial.println("********************************");
timerAlarmEnable(timer);
};
void onDisconnect(BLEServer* pServer) {
Serial.println("********************************");
Serial.println("Disconnected");
Serial.println("********************************");
timerAlarmDisable(timer);
//delay(1000);
///*
// Start the service
//pService->start();
// Start advertising
//pServer->getAdvertising()->start();
pServer->startAdvertising();
//*/
//ESP.restart();
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
std::string EN="Z";
std::string DIS="U";
Serial.print("rxValue:");
Serial.println(rxValue.c_str());
/*
//Serial.println(getvalue);
if (rxValue==EN ) {
//g_Timer.enable(g_TimerId);
timerAlarmEnable(timer);
digitalWrite(LED, HIGH);
}
else if (rxValue==DIS) {
//g_Timer.disable(g_TimerId);
timerAlarmDisable(timer);
//data_count = 0;
digitalWrite(LED, LOW);
}
*/
}
};
void setup() {
Serial.begin(115200);
Serial.begin(BAUD_RATE);
////////////////////////////////////////
Serial.println("Starting BLE Server!");
BLEDevice::init("ESP32-INTERRUT-Server");
/////////////////////////////////////////////////////////////////////////////////////
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_READ|
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
////////////////////////////////////////////////////////////////////
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, PERIOD_US, true);
timerAlarmDisable(timer);
}
void loop() {
}

Related

bluez pairing before exchange

I'm using code from An Introduction to Bluetooth Programming ► Chapter 4. Bluetooth programming in C with BlueZ4.2. ► RFCOMM sockets to send messages between two Raspberry Pi.
However, if I don't make the pairing between two devices through the bluetoothctl, I can't use the client because it gives me error:
uh oh: Invalid exchange.
Can you give me some hints on how can I make the pair through the C code? I need to use this "automatically" without need to pairing through the bluetoothctl before the C code.
Before getting into my answer, I am not sure how to achieve this using "libbluetooth" API's. But my below answer is based on DBUS API using GDBUS. This should most likely work with any recent bluez (with bluetoothd) running.
Note, with Bluez5 it's recommended to use DBUS API's.
To brief, you need to develop an Agent which accepts the Pairing request automatically, assuming "Confirmation" agent here. Please refer agent capabilities here.
With recent bluez version (atleast 5.47+), we have a new API "ConnectDevice" which can be used to connect device without scanning/discovery. From your question, I understand that you are trying to communicate between two RPi's, so you can find the BT address for both the bluetooth controllers. With BT address in places,
/*
* bluez_adapter_connect.c - Connect with device without StartDiscovery
* - This example registers an agen with NoInputOutput capability for the purpose of
* auto pairing
* - Use ConnectDevice method to connect with device using provided MAC address
* - Usual signal subscription to get the details of the connected device
* - Introduced new signal handler to exit the program gracefully
*
* Note: As "ConnectDevice" is new API and in experimental state (but mostly stable)
* one need to use "-E" option when starting "bluetoothd". Systems running systemd can
* edit /lib/systemd/system/bluetooth.service in ExecStart option
*
* When this API is useful?
* - When you already have the MAC address of end bluetooth Device to connect with, then
* you don't need to scan for the device (with or without filter) and connect it.
* - StartDiscovery + Pair + Connect => ConnectDevice
*
* How you will have MAC address before scanning?
* - When you have other communication (wired or wireless) medium to exchange the MAC address
* - For example, NFC OOB can be used to exchange the MAC address
* - Testing Bluetooth with same device (MAC address known)
*
* - Here Agent capability is registered as "NoInputOutput" for experimental purpose only, in
* real world scenario, Pair + Connect involves real Agents.
* - Also note, bluez_agent_call_method and bluez_adapter_call_method are two different methods doing
* the same work with difference in interface name and object path. This exist just to make the
* understanding more clear.
*
* gcc `pkg-config --cflags glib-2.0 gio-2.0` -Wall -Wextra -o ./bin/bluez_adapter_connect ./bluez_adapter_connect.c `pkg-config --libs glib-2.0 gio-2.0`
*/
#include <glib.h>
#include <gio/gio.h>
#include <signal.h>
GMainLoop *loop;
GDBusConnection *con;
static void bluez_property_value(const gchar *key, GVariant *value)
{
const gchar *type = g_variant_get_type_string(value);
g_print("\t%s : ", key);
switch(*type) {
case 'o':
case 's':
g_print("%s\n", g_variant_get_string(value, NULL));
break;
case 'b':
g_print("%d\n", g_variant_get_boolean(value));
break;
case 'u':
g_print("%d\n", g_variant_get_uint32(value));
break;
case 'a':
/* TODO Handling only 'as', but not array of dicts */
if(g_strcmp0(type, "as"))
break;
g_print("\n");
const gchar *uuid;
GVariantIter i;
g_variant_iter_init(&i, value);
while(g_variant_iter_next(&i, "s", &uuid))
g_print("\t\t%s\n", uuid);
break;
default:
g_print("Other\n");
break;
}
}
typedef void (*method_cb_t)(GObject *, GAsyncResult *, gpointer);
static int bluez_adapter_call_method(const char *method, GVariant *param, method_cb_t method_cb)
{
g_dbus_connection_call(con,
"org.bluez",
/* TODO Find the adapter path runtime */
"/org/bluez/hci0",
"org.bluez.Adapter1",
method,
param,
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
method_cb,
(void *)method);
return 0;
}
static void bluez_result_async_cb(GObject *con,
GAsyncResult *res,
gpointer data)
{
const gchar *key = (gchar *)data;
GVariant *result = NULL;
GError *error = NULL;
result = g_dbus_connection_call_finish((GDBusConnection *)con, res, &error);
if(error != NULL) {
g_print("Unable to get result: %s\n", error->message);
return;
}
if(result) {
result = g_variant_get_child_value(result, 0);
bluez_property_value(key, result);
}
g_variant_unref(result);
}
static void bluez_device_appeared(GDBusConnection *sig,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
(void)sig;
(void)sender_name;
(void)object_path;
(void)interface;
(void)signal_name;
(void)user_data;
GVariantIter *interfaces;
const char *object;
const gchar *interface_name;
GVariant *properties;
g_variant_get(parameters, "(&oa{sa{sv}})", &object, &interfaces);
while(g_variant_iter_next(interfaces, "{&s#a{sv}}", &interface_name, &properties)) {
if(g_strstr_len(g_ascii_strdown(interface_name, -1), -1, "device")) {
g_print("[ %s ]\n", object);
const gchar *property_name;
GVariantIter i;
GVariant *prop_val;
g_variant_iter_init(&i, properties);
while(g_variant_iter_next(&i, "{&sv}", &property_name, &prop_val))
bluez_property_value(property_name, prop_val);
g_variant_unref(prop_val);
}
g_variant_unref(properties);
}
return;
}
#define BT_ADDRESS_STRING_SIZE 18
static void bluez_device_disappeared(GDBusConnection *sig,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
(void)sig;
(void)sender_name;
(void)object_path;
(void)interface;
(void)signal_name;
GVariantIter *interfaces;
const char *object;
const gchar *interface_name;
char address[BT_ADDRESS_STRING_SIZE] = {'\0'};
g_variant_get(parameters, "(&oas)", &object, &interfaces);
while(g_variant_iter_next(interfaces, "s", &interface_name)) {
if(g_strstr_len(g_ascii_strdown(interface_name, -1), -1, "device")) {
int i;
char *tmp = g_strstr_len(object, -1, "dev_") + 4;
for(i = 0; *tmp != '\0'; i++, tmp++) {
if(*tmp == '_') {
address[i] = ':';
continue;
}
address[i] = *tmp;
}
g_print("\nDevice %s removed\n", address);
g_main_loop_quit((GMainLoop *)user_data);
}
}
return;
}
static void bluez_signal_adapter_changed(GDBusConnection *conn,
const gchar *sender,
const gchar *path,
const gchar *interface,
const gchar *signal,
GVariant *params,
void *userdata)
{
(void)conn;
(void)sender;
(void)path;
(void)interface;
(void)userdata;
GVariantIter *properties = NULL;
GVariantIter *unknown = NULL;
const char *iface;
const char *key;
GVariant *value = NULL;
const gchar *signature = g_variant_get_type_string(params);
if(strcmp(signature, "(sa{sv}as)") != 0) {
g_print("Invalid signature for %s: %s != %s", signal, signature, "(sa{sv}as)");
goto done;
}
g_variant_get(params, "(&sa{sv}as)", &iface, &properties, &unknown);
while(g_variant_iter_next(properties, "{&sv}", &key, &value)) {
if(!g_strcmp0(key, "Powered")) {
if(!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
g_print("Invalid argument type for %s: %s != %s", key,
g_variant_get_type_string(value), "b");
goto done;
}
g_print("Adapter is Powered \"%s\"\n", g_variant_get_boolean(value) ? "on" : "off");
}
if(!g_strcmp0(key, "Discovering")) {
if(!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
g_print("Invalid argument type for %s: %s != %s", key,
g_variant_get_type_string(value), "b");
goto done;
}
g_print("Adapter scan \"%s\"\n", g_variant_get_boolean(value) ? "on" : "off");
}
}
done:
if(properties != NULL)
g_variant_iter_free(properties);
if(value != NULL)
g_variant_unref(value);
}
static int bluez_adapter_set_property(const char *prop, GVariant *value)
{
GVariant *result;
GError *error = NULL;
result = g_dbus_connection_call_sync(con,
"org.bluez",
"/org/bluez/hci0",
"org.freedesktop.DBus.Properties",
"Set",
g_variant_new("(ssv)", "org.bluez.Adapter1", prop, value),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if(error != NULL)
return 1;
g_variant_unref(result);
return 0;
}
static int bluez_adapter_connect_device(char **argv)
{
int rc;
GVariantBuilder *b = g_variant_builder_new(G_VARIANT_TYPE_VARDICT);
g_variant_builder_add(b, "{sv}", "Address", g_variant_new_string(argv[1]));
GVariant *device_dict = g_variant_builder_end(b);
g_variant_builder_unref(b);
rc = bluez_adapter_call_method("ConnectDevice",
g_variant_new_tuple(&device_dict, 1),
bluez_result_async_cb);
if(rc) {
g_print("Not able to call ConnectDevice\n");
return 1;
}
return 0;
}
#define AGENT_PATH "/org/bluez/AutoPinAgent"
static int bluez_agent_call_method(const gchar *method, GVariant *param)
{
GVariant *result;
GError *error = NULL;
result = g_dbus_connection_call_sync(con,
"org.bluez",
"/org/bluez",
"org.bluez.AgentManager1",
method,
param,
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if(error != NULL) {
g_print("Register %s: %s\n", AGENT_PATH, error->message);
return 1;
}
g_variant_unref(result);
return 0;
}
static int bluez_register_autopair_agent(void)
{
int rc;
rc = bluez_agent_call_method("RegisterAgent", g_variant_new("(os)", AGENT_PATH, "NoInputNoOutput"));
if(rc)
return 1;
rc = bluez_agent_call_method("RequestDefaultAgent", g_variant_new("(o)", AGENT_PATH));
if(rc) {
bluez_agent_call_method("UnregisterAgent", g_variant_new("(o)", AGENT_PATH));
return 1;
}
return 0;
}
static void cleanup_handler(int signo)
{
if (signo == SIGINT) {
g_print("received SIGINT\n");
g_main_loop_quit(loop);
}
}
int main(int argc, char **argv)
{
int rc;
guint prop_changed;
guint iface_added;
guint iface_removed;
if(signal(SIGINT, cleanup_handler) == SIG_ERR)
g_print("can't catch SIGINT\n");
con = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
if(con == NULL) {
g_print("Not able to get connection to system bus\n");
return 1;
}
loop = g_main_loop_new(NULL, FALSE);
prop_changed = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.Properties",
"PropertiesChanged",
NULL,
"org.bluez.Adapter1",
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_signal_adapter_changed,
NULL,
NULL);
iface_added = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.ObjectManager",
"InterfacesAdded",
NULL,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_device_appeared,
loop,
NULL);
iface_removed = g_dbus_connection_signal_subscribe(con,
"org.bluez",
"org.freedesktop.DBus.ObjectManager",
"InterfacesRemoved",
NULL,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
bluez_device_disappeared,
loop,
NULL);
rc = bluez_adapter_set_property("Powered", g_variant_new("b", TRUE));
if(rc) {
g_print("Not able to enable the adapter\n");
goto fail;
}
rc = bluez_register_autopair_agent();
if(rc) {
g_print("Not able to register default autopair agent\n");
goto fail;
}
if(argc == 2) {
rc = bluez_adapter_connect_device(argv);
if(rc)
goto fail;
}
g_main_loop_run(loop);
rc = bluez_adapter_set_property("Powered", g_variant_new("b", FALSE));
if(rc)
g_print("Not able to disable the adapter\n");
fail:
g_dbus_connection_signal_unsubscribe(con, prop_changed);
g_dbus_connection_signal_unsubscribe(con, iface_added);
g_dbus_connection_signal_unsubscribe(con, iface_removed);
g_object_unref(con);
return 0;
}
you should be able to use the above program to connect the device. Here in this example, the agent is registered as "NoInputOutput" capability, something like bluetooth headphones, so that no pairing response is required.
But you should modify this example to client side (assuming this example going to run in RPi 1 as server, modify this to accept request in client side RPi 2).
You can find the detailed explanation about this example here and also some relevant GDBUS based examples here.

Strange behaviour with tiny tty linux device driver

I'm having troubles with the tiny tty driver found in the book Linux Device Drivers. I had to adopt the code slightly to fit my requirements, so kicked out any code that was not relevant (see code below).
I use a kernel thread that writes "hello world" to the TTY layer. If I open the device file in a terminal using the cat command, I receive the intended string.
But I'm facing two issues:
Why is tiny_write(...) called whenever tty_insert_flip_char(...) is
called in my kernel thread (tiny_thread)? Shouldn't tiny_write(...) function be called only if writing to the device file? How to distinguish in this function if it is called during a read or write operation?
Why do I get an error if using echo on the device file?
echo test > /dev/tiny_tty
bash: echo: write error: Invalid argument
The driver is running on the Raspberry Pi kernel 4.9.56-v7.
Thanks a lot!
Regards,
Thomas
UPDATE: The first issue is (partly) solved using the solution in tty_flip_buffer_push() sends data back to itself. Is there a way to do this directly in the device driver, so no interaction is required by the user?
/*
* Tiny TTY driver
*
* Base on tiny tty driver from Greg Kroah-Hartman
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <linux/kthread.h>
#include <linux/jiffies.h>
#define USE_SIMULATOR
#define DELAY_TIME HZ * 2 /* 2 seconds per character */
#define TINY_TTY_MAJOR 240 /* experimental range */
#define TINY_TTY_MINORS 1 /* only have 4 devices */
#if defined(USE_SIMULATOR)
static struct task_struct *thread_id;
static wait_queue_head_t wq_thread;
static DECLARE_COMPLETION(on_exit);
#endif /* USE_SIMULATOR */
struct tiny_serial {
struct tty_struct *tty; /* pointer to the tty for this device */
int open_count; /* number of times this port has been opened */
struct semaphore sem; /* locks this structure */
};
static struct tiny_serial *tiny_serial; /* initially all NULL */
#if defined(USE_SIMULATOR)
static int tiny_thread(void *thread_data)
{
unsigned int timeoutMs;
struct tiny_serial *tiny = (struct tiny_serial*)thread_data;
struct tty_struct *tty;
struct tty_port *port;
char buf[] = "hello world\n";
int i = 0;
allow_signal(SIGTERM);
pr_info("%s\n", __func__);
tty = tiny->tty;
port = tty->port;
while(kthread_should_stop() == 0)
{
timeoutMs = 1000;
timeoutMs = wait_event_interruptible_timeout(wq_thread, (timeoutMs==0), msecs_to_jiffies(timeoutMs));
if(timeoutMs == -ERESTARTSYS)
{
pr_info("%s - signal break\n", __func__);
up(&tiny->sem);
break;
}
pr_info("%s\n", __func__);
down(&tiny->sem);
if(tiny)
{
for (i = 0; i < strlen(buf); ++i)
{
if (!tty_buffer_request_room(tty->port, 1))
tty_flip_buffer_push(tty->port);
tty_insert_flip_char(tty->port, buf[i], TTY_NORMAL);
}
tty_flip_buffer_push(tty->port);
}
up(&tiny->sem);
}
complete_and_exit(&on_exit, 0);
}
#endif /* USE_SIMULATOR */
static int tiny_open(struct tty_struct *tty, struct file *file)
{
pr_info("%s\n", __func__);
/* initialize the pointer in case something fails */
tty->driver_data = NULL;
/* get the serial object associated with this tty pointer */
if(tiny_serial == NULL) {
/* first time accessing this device, let's create it */
tiny_serial = kmalloc(sizeof(*tiny_serial), GFP_KERNEL);
if (!tiny_serial)
return -ENOMEM;
sema_init(&tiny_serial->sem, 1);
tiny_serial->open_count = 0;
}
down(&tiny_serial->sem);
/* save our structure within the tty structure */
tty->driver_data = tiny_serial;
tiny_serial->tty = tty;
++tiny_serial->open_count;
if (tiny_serial->open_count == 1) {
/* this is the first time this port is opened */
/* do any hardware initialization needed here */
#if defined(USE_SIMULATOR)
if(thread_id == NULL)
thread_id = kthread_create(tiny_thread, (void*)tiny_serial, "tiny_thread");
wake_up_process(thread_id);
#endif /* USE_SIMULATOR */
}
up(&tiny_serial->sem);
return 0;
}
static void do_close(struct tiny_serial *tiny)
{
pr_info("%s\n", __func__);
down(&tiny->sem);
if (!tiny->open_count) {
/* port was never opened */
goto exit;
}
--tiny->open_count;
if (tiny->open_count <= 0) {
/* The port is being closed by the last user. */
/* Do any hardware specific stuff here */
#if defined(USE_SIMULATOR)
/* shut down our timer and free the memory */
if(thread_id)
{
kill_pid(task_pid(thread_id), SIGTERM, 1);
wait_for_completion(&on_exit);
thread_id = NULL;
}
#endif /* USE_SIMULATOR */
}
exit:
up(&tiny->sem);
}
static void tiny_close(struct tty_struct *tty, struct file *file)
{
struct tiny_serial *tiny = tty->driver_data;
pr_info("%s\n", __func__);
if (tiny)
do_close(tiny);
}
static int tiny_write(struct tty_struct *tty,
const unsigned char *buffer, int count)
{
struct tiny_serial *tiny = tty->driver_data;
int i;
int retval = -EINVAL;
if (!tiny)
return -ENODEV;
down(&tiny->sem);
if (!tiny->open_count)
/* port was not opened */
goto exit;
/* fake sending the data out a hardware port by
* writing it to the kernel debug log.
*/
printk(KERN_DEBUG "%s - ", __FUNCTION__);
for (i = 0; i < count; ++i)
{
printk("%02x ", buffer[i]);
}
printk("\n");
exit:
up(&tiny->sem);
return retval;
}
static int tiny_write_room(struct tty_struct *tty)
{
struct tiny_serial *tiny = tty->driver_data;
int room = -EINVAL;
pr_info("%s\n", __func__);
if (!tiny)
return -ENODEV;
down(&tiny->sem);
if (!tiny->open_count) {
/* port was not opened */
goto exit;
}
/* calculate how much room is left in the device */
room = 255;
exit:
up(&tiny->sem);
return room;
}
static void tiny_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
pr_info("%s\n", __func__);
}
static int tiny_install(struct tty_driver *driver, struct tty_struct *tty)
{
int retval = -ENOMEM;
pr_info("%s\n", __func__);
tty->port = kmalloc(sizeof *tty->port, GFP_KERNEL);
if (!tty->port)
goto err;
tty_init_termios(tty);
driver->ttys[0] = tty;
tty_port_init(tty->port);
tty_buffer_set_limit(tty->port, 8192);
tty_driver_kref_get(driver);
tty->count++;
return 0;
err:
pr_info("%s - err\n", __func__);
kfree(tty->port);
return retval;
}
static struct tty_operations serial_ops = {
.open = tiny_open,
.close = tiny_close,
.write = tiny_write,
.write_room = tiny_write_room,
.set_termios = tiny_set_termios,
.install = tiny_install,
};
static struct tty_driver *tiny_tty_driver;
static int __init tiny_init(void)
{
int retval;
pr_info("%s\n", __func__);
#if defined(USE_SIMULATOR)
init_waitqueue_head(&wq_thread);
thread_id = NULL;
#endif /* USE_SIMULATOR */
/* allocate the tty driver */
tiny_tty_driver = alloc_tty_driver(TINY_TTY_MINORS);
if (!tiny_tty_driver)
return -ENOMEM;
/* initialize the tty driver */
tiny_tty_driver->owner = THIS_MODULE;
tiny_tty_driver->driver_name = "tiny_tty";
tiny_tty_driver->name = "tiny_tty";
tiny_tty_driver->major = TINY_TTY_MAJOR,
tiny_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM,
tiny_tty_driver->subtype = SYSTEM_TYPE_CONSOLE,
tiny_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_UNNUMBERED_NODE,
tiny_tty_driver->init_termios = tty_std_termios;
tiny_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(tiny_tty_driver, &serial_ops);
/* register the tty driver */
retval = tty_register_driver(tiny_tty_driver);
if (retval) {
printk(KERN_ERR "failed to register tiny tty driver");
put_tty_driver(tiny_tty_driver);
return retval;
}
tty_register_device(tiny_tty_driver, 0, NULL);
//tiny_install(tiny_tty_driver, tiny_table[0]->tty);
return retval;
}
static void __exit tiny_exit(void)
{
pr_info("%s\n", __func__);
#if defined(USE_SIMULATOR)
if(thread_id)
{
/* shut down our timer and free the memory */
kill_pid(task_pid(thread_id), SIGTERM, 1);
wait_for_completion(&on_exit);
}
#endif /* USE_SIMULATOR */
tty_unregister_device(tiny_tty_driver, 0);
tty_unregister_driver(tiny_tty_driver);
if (tiny_serial) {
/* close the port */
while (tiny_serial->open_count)
do_close(tiny_serial);
if(tiny_serial->tty->port)
{
kfree(tiny_serial->tty->port);
tiny_serial->tty->port = NULL;
}
kfree(tiny_serial);
tiny_serial = NULL;
}
}
module_init(tiny_init);
module_exit(tiny_exit);
MODULE_AUTHOR("");
MODULE_DESCRIPTION("Tiny TTY driver");
MODULE_LICENSE("GPL");
The post is a bit dated already, but I've stumbled upon same issues and decided to share the solution:
you can turn off echo by setting appropriate flags in termios struct:
tiny_tty_driver->init_termios.c_lflag &= ~ECHO;
this is because tiny_write always returns -EINVAL, set retval = count; before return to fix this.

Http get request using Arduino and Azure mobile services

I have hooked up my arduino with Azure mobile services and http post request is working fine where I am able to send data from sensor. But when using a http get request to access data from the tables, I am landing up with this data whereas I should be getting a json data in the Serial Window.
X-cache-Lookup: MISS from Webmaster:8080
Here is the code that is on my Arduino. I have no idea where I am wrong.
#include <ArduinoJson.h>
#include <SPI.h>
#include <Ethernet.h>
#define RESPONSE_JSON_DATA_LINENNO 10
// Ethernet shield MAC address (sticker in the back)
byte mac[] = { 0xA4, 0x5D, 0x36, 0x6A, 0xE1, 0xE1 };
int qq=0;
const char* server= "avirup.azure-mobile.net";
const char* table_name= "iottest";
const char* ams_key="rkIEUqVlFrgtmqNeMmaamgUQywwMjE42";
char stat;
EthernetClient client;
char fin='0';
char buffer[64];
int charIndex=0;
StaticJsonBuffer<200> jsonbuffer;
void send_request()
{
Serial.println("\nconnecting...");
if (client.connect(server, 80)) {
Serial.print("sending ");
// GET URI
sprintf(buffer, "GET /tables/%s HTTP/1.1", table_name);
Serial.println(buffer);
client.println(buffer);
// Host header
sprintf(buffer, "Host: %s", server);
client.println(buffer);
// Azure Mobile Services application key
sprintf(buffer, "X-ZUMO-APPLICATION: %s", ams_key);
client.println(buffer);
// JSON content type
client.println("Content-Type: application/json");
//POST body
sprintf(buffer, "", "");
//Content length
client.print("Content-Length: ");
client.println(strlen(buffer));
Serial.print("Content length: ");
Serial.println(strlen(buffer));
// End of headers
client.println();
// Request body
client.println(buffer);
}
else {
Serial.
println("connection failed");
}
}
/*
** Wait for response
*/
void wait_response()
{
while (!client.available()) {
if (!client.connected()) {
return;
}
}
}
/*
** Read the response and dump to serial
*/
// Read the response and dump to serial
void read_response()
{
int jsonStringLength;
int jsonBufferCntr=0;
int numline=RESPONSE_JSON_DATA_LINENNO;
//Ignore the response except for the 10th line
while (client.available()) {
char c = client.read();
if (c == '\n')
{
numline -=1;
}
else
{
if (numline == 0 )
{
//Capture the 10th line in the response
//To do: Could be more deterministic about this:
// Expect certain content, checks and balances etc.
buffer[jsonBufferCntr++] = c;
buffer[jsonBufferCntr] = '\0';
}
}
}
Serial.println("Received:");
Serial.println(buffer);
Serial.println("");
}
/*
** Close the connection
*/
void parse()
{
//char json[] = "{\"id\":\"34CCC60D-15D2-4B53-AB8E-FF3745FDC945\",\"control\":1}";
JsonObject& root = jsonbuffer.parseObject(buffer);
if(!root.success())
{
Serial.println("PARSING FAILED!!!");
return;
}
//fin= root["control"][0];
int f= root["control"][0];
Serial.println("Decoded: ");
Serial.println(f);
}
void end_request()
{
client.stop();
}
/*
** Arduino Setup
*/
void setup()
{
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect.
}
if (Ethernet.begin(mac) == 0) {
Serial.println("ethernet failed");
for (;;) ;
}
// give the Ethernet shield a second to initialize:
delay(1000);
}
/*
** Arduino Loop
*/
void loop()
{
send_request();
wait_response();
read_response();
end_request();
delay(1000);
}

work with parallel port interrupt

I am working on parallel port driver. Now i had seen the methods to get interrupt from parallel port.
by one of them,
First make 4th pin of control reg 1(IRQ).
then make nACK low.
so i make a switch in between data pin 8 and nACK. so, if i write some data which has msb 1 then it will be interrupted, if that switch is on. Now i have a problem. If i disconnected that switch and again connect then it will not give me interrupt.
So, how can i do that thing by which i got interrupt by means of switch is connect or not.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/parport.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <asm/irq.h>
#include <linux/kthread.h>
#define DEVICE_NAME "parlelport"
struct pardevice *pdev;
static int dummy;
int ret;
static irqreturn_t recv_handler(int irq, void *dev_id)
{
printk("we inside if isr");
return 0;
}
int led_open(struct inode *inode, struct file *file)
{
printk("1\n");
printk("Device File Opened\n");
char byte1;
byte1=inb(0x37A);
printk("%d \n",byte1);
return 0;
}
ssize_t led_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
printk("2\n");
char byte=inb(0x37A);
printk("%d",byte);
byte = byte | 0x10; // 0x10= 00010000, 4th pin of CTRL reg
outb(byte, 0x37A); //which enable IRQ
char kbuf;
copy_from_user(&kbuf, buf, 1);
parport_claim_or_block(pdev); /* Claim the port */
parport_write_data(pdev->port, kbuf); /* Write to the device */
//parport_release (pdev);
return count;
}
int led_release(struct inode *inode, struct file *file)
{
printk("3\n");
printk("Device File Released\n");
char byte;
byte=inb(0x37A);
printk("%d", byte);
return 0;
}
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
.release = led_release,
};
static int led_preempt(void *handle)
{
printk("4\n");
return 1;
}
static void led_attach(struct parport *port)
{
printk("5\n");
pdev = parport_register_device(port, DEVICE_NAME, led_preempt, NULL, NULL, 0, NULL);
printk("Port attached\n");
char byte1;
byte1=inb(0x37A);
printk("%d \n",byte1);
}
static void led_detach(struct parport *port)
{
printk("6\n");
parport_unregister_device (pdev);
printk("Port Deattached\n");
}
static struct parport_driver led_driver = {
.name= "led",
.attach = led_attach,
.detach = led_detach,
};
int __init led_init(void)
{
printk("7\n");
if (register_chrdev(89, DEVICE_NAME, &led_fops))
{
printk("Can't register device\n");
return -1;
}
char byte=inb(0x37A);
printk("%d",byte);
byte = byte | 0x10;
outb(byte, 0x37A);
char byte1;
byte1=inb(0x37A);
printk("%d %d \n",byte,byte1);
parport_register_driver(&led_driver);
ret= request_irq(7, recv_handler, IRQF_SHARED, "parlelport", &dummy);
printk("%d",ret);
return 0;
}
void __exit led_cleanup(void)
{
printk("8\n");
unregister_chrdev(89, DEVICE_NAME);
if(!ret)
free_irq(7, &dummy);
parport_unregister_driver(&led_driver);
printk("LED Driver unregistered.\n");
return;
}
module_init(led_init);
module_exit(led_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vikrant Patel");
Test.c file
int main()
{
int fd=open("/dev/parlelport",O_RDWR);
char byte;
printf("Enter Value to send on parallel port");
scanf("%c",&byte);
printf("Byte value is %c\n",byte);
if(write(fd,&byte,sizeof(char)))
{
printf("\nSuccessfully written on port");
}
getchar();
getchar();
close(fd);
}
I got it.
First make a thread
put the Enable IRQ code in that thread
so it will continuously execute it
whenever i connect pins at my hardware then it will be interrupted.
check this code for your ref.
#include <linux/module.h>
#include <linux/parport.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#define DEVICE_NAME "parlelport"
#define DATA 0x378
#define STATUS 0x379
#define CONTROL 0x37A
struct pardevice *pdev;
struct task_struct *ts1, *ts2;
int dummy;
char buf1='1',buf2='2';
char byte='0';
int thread1(void *data)
{
while(1)
{
outb(byte, CONTROL); /* 0x30 = 0011 0000 , makes IRQ pin(5th bit) enable */
printk("Thread1\n");
parport_claim_or_block(pdev); /* Claim the port */
parport_write_data(pdev->port, buf1); /* Write to the device */
parport_release(pdev); /* Release the port */
msleep(4000);
if (kthread_should_stop())
break;
}
return 0;
}
int thread2(void *data)
{
while(1)
{
outb(byte,CONTROL); /* 0x30 = 0011 0000 , makes IRQ pin(5th bit) enable */
printk("Thread2\n");
parport_claim_or_block(pdev); /* Claim the port */
parport_write_data(pdev->port, buf2); /* Write to the device */
parport_release(pdev); /* Release the port */
msleep(4000);
if (kthread_should_stop())
break;
}
return 0;
}
int led_open(struct inode *inode, struct file *file)
{
printk("Device File Opened\n");
ts1=kthread_run(thread1,NULL,"kthread"); /* Initiation of thread 1 */
msleep(2000);
ts2=kthread_run(thread2,NULL,"kthread"); /* Initiation of thread 2 */
return 0;
}
ssize_t led_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
return count;
}
int led_release(struct inode *inode, struct file *file)
{
printk("Device File Released\n");
kthread_stop(ts1);
kthread_stop(ts2);
buf1='1';
buf2='2';
outb_p(0x00,DATA);
return 0;
}
static irqreturn_t recv_handler(int irq, void *unused)
{
printk("we inside of isr");
buf1= buf1 ^ 0x7F;
buf2= buf2 ^ 0x7F;
return 0;
}
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.write = led_write,
.release = led_release,
};
static int led_preempt(void *handle)
{
return 1;
}
static void led_attach(struct parport *port)
{
pdev = parport_register_device(port, DEVICE_NAME, led_preempt, NULL, NULL, 0, NULL);
printk("Port attached\n");
}
static void led_detach(struct parport *port)
{
parport_unregister_device (pdev);
printk("Port Deattached\n");
}
static struct parport_driver led_driver = {
.name= "led",
.attach = led_attach,
.detach = led_detach,
};
int __init led_init(void)
{
/*Register our ISR with the kernel for PARALLEL_IRQ */
if (request_irq(7, recv_handler, IRQF_SHARED, DEVICE_NAME ,&dummy))
{
printk("Registering ISR failed\n");
return -ENODEV;
}
/*Register Character Device Driver at 89 Major number*/
if (register_chrdev(89, DEVICE_NAME, &led_fops))
{
printk("Can't register device\n");
return -1;
}
/*Register parallel port driver with parport structure led_driver*/
parport_register_driver(&led_driver);
return 0;
}
void __exit led_cleanup(void)
{
unregister_chrdev(89, DEVICE_NAME); /* Unregister char driver */
free_irq(7, &dummy); /* Free the ISR from IRQ7 */
parport_unregister_driver(&led_driver); /* Unregister the parallel port driver */
printk("LED Driver unregistered.\n");
return;
}
module_init(led_init);
module_exit(led_cleanup);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vikrant Patel");

Custom ALSA driver does not execute the open functions from struct snd_pcm_ops

I am trying to create my own custom sound driver using ALSA. So far I have succeeded loading the module, by which I mean:
my probe function is executed
the constructor is executed
I see the interrupt being executed
I found this out by the dumps I placed in these functions.
But when I try to use the snd_pcm_open() function in my application, to connect to my driver, I do not see the dumps I added in the .open() function stored in struct snd_pcm_ops. So for some reason my driver is not seen from my application.
I loaded the original driver and executed the same application and it worked fine.
Do you have any idea why my driver is no accessible from user space?
Thank you.
And here is the code:
#include <linux/fs.h>
#include <linux/module.h> // MOD_DEVICE_TABLE,
#include <linux/init.h>
#include <linux/pci.h> // pci_device_id,
#include <linux/interrupt.h>
#include <linux/version.h> // KERNEL_VERSION,
#include <iso646.h>
#include <linux/kobject.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h> // copy_to_user,
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <linux/time.h>
MODULE_LICENSE("GPL");
// vendor and device id of the PCI device
#define VENDOR_ID 0x8086
#define DEVICE_ID 0x2415
/*************** DATA **********************/
/* module parameters (see "Module Parameters") */
/* SNDRV_CARDS: maximum number of cards supported by this module */
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
#define BARS 6
enum bars{bar0=0, bar1=1, bar2=2, bar3=3, bar4=4, bar5=5};
#define IOREG_0 0
#define IOREG_1 1
/*OFFSETS TO REGISTER*/
#define GLOBAL_STATUS_REGISTER_OFFSET 0x30
struct mem_regions
{
unsigned int start_addr;
unsigned int end_addr;
unsigned int mem_len;
unsigned int bar;
unsigned int flag;
void __iomem *mem_mapped_addr;
};
struct mychip {
struct snd_card *card;
struct pci_dev *pci;
unsigned long port;
int irq;
struct mem_regions memregs[6];
struct snd_pcm *pcm;
struct snd_pcm_substream *substream;
};
/*******************************************/
/******************** FUNCTION PROTOTYPES *********************************/
static int __devinit snd_mychip_create(struct snd_card *card,
struct pci_dev *pci,
struct mychip **rchip);
static int snd_mychip_free(struct mychip *chip);
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id);
static int __devinit snd_mychip_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id);
static void snd_mychip_remove(struct pci_dev *pci);
static int snd_mychip_dev_free(struct snd_device *device);
static int reserve_mem_regions(struct mychip *chip);
static void clear_mem_regions(struct mychip *chip);
static void memdump(struct mychip *chip);
/* ------------ PCM functions ------------- */
/* ---- constructor ---- */
static int __devinit snd_pcm_constructor(struct mychip *chip);
/* ---- destructor ---- */
static void snd_pcm_destructor(struct snd_pcm *pcm);
/* ---- file operations fcns ---- */
static int snd_pcm_playback_open(struct snd_pcm_substream *substream);
static int snd_pcm_playback_close(struct snd_pcm_substream *substream);
static int snd_pcm_capture_open(struct snd_pcm_substream *substream);
static int snd_pcm_capture_close(struct snd_pcm_substream *substream);
/*snd_pcm_lib_ioctl();*/
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params);
static int snd_pcm_hw_free(struct snd_pcm_substream *substream);
static int snd_pcm_prepare(struct snd_pcm_substream *substream);
static int snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
static snd_pcm_uframes_t snd_pcm_pointer(struct snd_pcm_substream *substream);
/* ---------------------------------------- */
/**************************************************************************/
/************************* IMPLEMENTATION *******************************/
/*prototyped*/
static int snd_mychip_free(struct mychip *chip)
{
/* disable hardware here if any */
//.... /* (not implemented in this document) */
/* release the irq */
if (chip->irq >= 0)
free_irq(chip->irq, chip);
/* release the I/O ports & memory */
/*pci_release_regions(chip->pci);*/
clear_mem_regions(chip);
/* disable the PCI entry */
pci_disable_device(chip->pci);
/* release the data */
kfree(chip);
return 0;
}
/*prototyped*/
static int snd_mychip_dev_free(struct snd_device *device)
{
return snd_mychip_free(device->device_data);
}
/*prototyped*/
static void snd_mychip_remove(struct pci_dev *pci)
{
/*Clear the card data and PCI data*/
snd_card_free(pci_get_drvdata(pci));
pci_set_drvdata(pci, NULL);
}
/* constructor -- see "Constructor" sub-section *//*prototyped*/
static int __devinit snd_mychip_probe(struct pci_dev *pci,
const struct pci_device_id *pci_id)
{
static int dev;
struct snd_card *card;
struct mychip *chip;
int err;
printk(KERN_ERR "Probing ...\n");
/* (1) Check and increment the device index */
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!enable[dev]) {
dev++;
return -ENOENT;
}
/* (2) Create a card instance */
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
if (err < 0)
return err;
/* (3) Create a main component */
/* chip-specific constructor: allocate PCI resources */
err = snd_mychip_create(card, pci, &chip);
if (err < 0) {
snd_card_free(card);
return err;
}
/* (4) Set driver ID and name strings */
strcpy(card->driver, "My Chip");
strcpy(card->shortname, "My Own Chip 123");
sprintf(card->longname, "%s at 0x%lx irq %i",
card->shortname, chip->port, chip->irq);
/* (5) Create other components PCM, mixers, MIDI etc */
/* implemented later */
/* (6) Register card instance */
err = snd_card_register(card);
if (err < 0) {
snd_card_free(card);
return err;
}
/* (7) Set the PCI driver data */
pci_set_drvdata(pci, card);
dev++;
/*Call PCM constructor*/
err = snd_pcm_constructor(chip);
if(err < 0)
printk(KERN_ERR "Failed to execute PCM constructor!\n");
printk(KERN_ERR "Probing done!\n");
return 0;
}
/*prototyped*/
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
{
struct mychip *chip = dev_id;
struct timeval timeval;
unsigned int status = 0;
static int executed = 0;
do_gettimeofday(&timeval);
if(executed < 10)
{
/*get the global status register*/
status = ioread32((void*)chip->memregs[IOREG_0].mem_mapped_addr + GLOBAL_STATUS_REGISTER_OFFSET);
status = ioread32((void*)chip->memregs[IOREG_1].mem_mapped_addr + GLOBAL_STATUS_REGISTER_OFFSET);
printk(KERN_ERR "\n---------- ISR -----------\n");
executed ++;
}
return IRQ_HANDLED;
}
/* chip-specific constructor *//*prototyped*/
static int __devinit snd_mychip_create(struct snd_card *card,
struct pci_dev *pci,
struct mychip **rchip)
{
struct mychip *chip;
int err;
static struct snd_device_ops ops = {
.dev_free = snd_mychip_dev_free,
};
printk(KERN_ERR "Enabling PCI device ...");
*rchip = NULL;
/* initialize the PCI entry */
err = pci_enable_device(pci);
if (err < 0)
return err;
/* check PCI availability (28bit DMA) */
if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
printk(KERN_ERR "error to set 28bit mask DMA\n");
pci_disable_device(pci);
return -ENXIO;
}
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (chip == NULL) {
pci_disable_device(pci);
return -ENOMEM;
}
/* initialize the stuff */
chip->card = card;
chip->pci = pci;
chip->irq = -1;
err = reserve_mem_regions(chip);
if (err < 0) {
kfree(chip);
pci_disable_device(pci);
return err;
}
/* (1) PCI resource allocation */
if (request_irq(pci->irq, snd_mychip_interrupt,
IRQF_SHARED, "My Chip", chip)) {
printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
snd_mychip_free(chip);
return -EBUSY;
}
chip->irq = pci->irq;
printk(KERN_ERR "Gain access to PCI IRQ line ... line %d\n", pci->irq);
printk(KERN_ERR "Gain access to PCI IO ports ... ports 0x%x\n", (unsigned int)chip->port);
/* (2) initialization of the chip hardware */
/* (not implemented in this document) */
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
if (err < 0) {
snd_mychip_free(chip);
return err;
}
snd_card_set_dev(card, &pci->dev);
*rchip = chip;
return 0;
}
static void memdump(struct mychip *chip)
{
int i;
for(i=0; i<BARS; i++)
{
printk(KERN_ERR "\n-----------------------------------\n");
printk(KERN_ERR "chip->memregs[i].bar = %d\n", chip->memregs[i].bar);
printk(KERN_ERR "chip->memregs[i].start_addr = 0x%x\n", chip->memregs[i].start_addr);
printk(KERN_ERR "chip->memregs[i].end_addr = 0x%x\n", chip->memregs[i].end_addr);
printk(KERN_ERR "chip->memregs[i].mem_len = %d\n", chip->memregs[i].mem_len);
printk(KERN_ERR "chip->memregs[i].flag = 0x%x\n", chip->memregs[i].flag);
printk(KERN_ERR "chip->memregs[i].mem_mapped_addr = 0x%p\n", chip->memregs[i].mem_mapped_addr);
}
}
static int reserve_mem_regions(struct mychip *chip)
{
int res = 0;
int i=0;
res = pci_request_regions(chip->pci, "My Chip");
if (res < 0) {
return res;
}
for(i=0; i<BARS; i++)
{
chip->memregs[i].bar = i;
chip->memregs[i].start_addr = pci_resource_start( chip->pci, i );
chip->memregs[i].end_addr = pci_resource_end( chip->pci, i );
chip->memregs[i].mem_len = pci_resource_len( chip->pci, i );
chip->memregs[i].flag = pci_resource_flags( chip->pci, i );
chip->memregs[i].mem_mapped_addr = pci_iomap(chip->pci, i, 0);
}
memdump(chip);
return res;
}
static void clear_mem_regions(struct mychip *chip)
{
int i = 0;
for(i=0; i<BARS; i++)
{
chip->memregs[i].bar = 0xFFFF;
chip->memregs[i].start_addr = 0;
chip->memregs[i].end_addr = 0;
chip->memregs[i].mem_len = 0;
chip->memregs[i].flag = 0xFFFF;
pci_iounmap(chip->pci, chip->memregs[i].mem_mapped_addr);
chip->memregs[i].mem_mapped_addr = NULL;
}
pci_release_regions(chip->pci);
}
/* ------------ PCM functions ------------- */
static struct snd_pcm_hardware snd_hardware_setup =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_8000_48000,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 1,
.periods_max = 1024,
.fifo_size = 0,
};
/* ---- operator structs ---- */
static struct snd_pcm_ops snd_pcm_playback_ops = {
.open = snd_pcm_playback_open,
.close = snd_pcm_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_pcm_hw_params,
.hw_free = snd_pcm_hw_free,
.prepare = snd_pcm_prepare,
.trigger = snd_pcm_trigger,
.pointer = snd_pcm_pointer,
};
static struct snd_pcm_ops snd_pcm_capture_ops = {
.open = snd_pcm_capture_open,
.close = snd_pcm_capture_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_pcm_hw_params,
.hw_free = snd_pcm_hw_free,
.prepare = snd_pcm_prepare,
.trigger = snd_pcm_trigger,
.pointer = snd_pcm_pointer,
};
/* ---- file operations fcns ---- */
static int snd_pcm_capture_open(struct snd_pcm_substream *substream)
{
struct mychip *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
int err = -10;
printk(KERN_ERR ">>> snd_pcm_capture_open()\n");
runtime->hw = snd_hardware_setup;
chip->substream = substream;
return err;
};
static int snd_pcm_capture_close(struct snd_pcm_substream *substream)
{
int err = -10;
printk(KERN_ERR ">>> snd_pcm_capture_close()\n");
return err;
};
static int snd_pcm_playback_open(struct snd_pcm_substream *substream)
{
struct mychip *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
int err = -10;
printk(KERN_ERR ">>> snd_pcm_playback_open()\n");
runtime->hw = snd_hardware_setup;
chip->substream = substream;
return err;
};
static int snd_pcm_playback_close(struct snd_pcm_substream *substream)
{
int err = -10;
printk(KERN_ERR ">>> snd_pcm_playback_close()\n");
return err;
};
/*snd_pcm_lib_ioctl();*/
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
int err = 0;
return err;
};
static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
{
int err = 0;
return err;
};
static int snd_pcm_prepare(struct snd_pcm_substream *substream)
{
int err = 0;
return err;
};
static int snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
int err = 0;
return err;
};
static snd_pcm_uframes_t snd_pcm_pointer(struct snd_pcm_substream *substream)
{
int err = 0;
return err;
};
/* ---- constructor ---- */
static int __devinit snd_pcm_constructor(struct mychip *chip)
{
struct snd_pcm *pcm = NULL;
int err = 0;
printk(KERN_ERR ">>> PCM CONSTRUCTOR: running...\n");
err = snd_pcm_new(chip->card, "My Own Chip", 0, 1, 1, &pcm);
if(err < 0)
{
printk(KERN_ERR ">>> PCM CONSTRUCTOR: Failed to execute snd_pcm_new()!\n");
return err;
}
pcm->private_data = chip;
pcm->private_free = snd_pcm_destructor;
strcpy(pcm->name, "My Own Chip");
chip->pcm = pcm;
/*set operators*/
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_pcm_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_pcm_capture_ops);
/*stream preallocation of buffers*/
err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
if(err < 0)
{
printk(KERN_ERR ">>> PCM CONSTRUCTOR: Failed to execute snd_pcm_lib_preallocate_pages_for_all()!\n");
return err;
}
printk(KERN_ERR ">>> PCM CONSTRUCTOR: ... exiting.\n");
return 0;
}
/* ---- destructor ---- */
static void snd_pcm_destructor(struct snd_pcm *pcm)
{
/*
struct mychip *chip = snd_pcm_chip(pcm);
*/
}
/* ---------------------------------------- */
/* PCI IDs */
static struct pci_device_id snd_mychip_ids[] = {
{ VENDOR_ID, DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, snd_mychip_ids);
/* pci_driver definition */
static struct pci_driver driver = {
.name = "My Own Chip",
.id_table = snd_mychip_ids,
.probe = snd_mychip_probe,
.remove = __devexit_p(snd_mychip_remove),
};
/**************** MODULE EXCUTED FUNCTIONS ****************************/
/* module initialization */
static int __init alsa_card_mychip_init(void)
{
printk(KERN_ERR "\n\n\n###########################################\n");
printk(KERN_ERR "-->>> Module init: !!!");
return pci_register_driver(&driver);
}
/* module clean up */
static void __exit alsa_card_mychip_exit(void)
{
pci_unregister_driver(&driver);
printk(KERN_ERR "-->>> Module exit: ");
}
module_init(alsa_card_mychip_init)
module_exit(alsa_card_mychip_exit)
And the output I get from dmesg:
[ 227.202006] ###########################################
[ 227.202430] -->>> Module init: !!!
[ 227.202507] Probing ...
[ 227.203959] Enabling PCI device ...
[ 227.207882]
[ 227.207882] -----------------------------------
[ 227.208097] chip->memregs[i].bar = 0
[ 227.208124] chip->memregs[i].start_addr = 0xd100
[ 227.208148] chip->memregs[i].end_addr = 0xd1ff
[ 227.208174] chip->memregs[i].mem_len = 256
[ 227.208198] chip->memregs[i].flag = 0x40101
[ 227.208223] chip->memregs[i].mem_mapped_addr = 0x0001d100
[ 227.208246]
[ 227.208246] -----------------------------------
[ 227.208271] chip->memregs[i].bar = 1
[ 227.208294] chip->memregs[i].start_addr = 0xd200
[ 227.208318] chip->memregs[i].end_addr = 0xd23f
[ 227.208341] chip->memregs[i].mem_len = 64
[ 227.208364] chip->memregs[i].flag = 0x40101
[ 227.208388] chip->memregs[i].mem_mapped_addr = 0x0001d200
[ 227.208410]
[ 227.208410] -----------------------------------
[ 227.208435] chip->memregs[i].bar = 2
.....
[ 227.209080] Gain access to PCI IRQ line ... line 5
[ 227.209104] Gain access to PCI IO ports ... ports 0x0
[ 227.224202] >>> PCM CONSTRUCTOR: running...
[ 227.225378] >>> PCM CONSTRUCTOR: ... exiting.
[ 227.225403] Probing done!
[ 227.295404]
[ 227.295404] ---------- ISR -----------
[ 227.313297]
[ 227.313297] ---------- ISR -----------
[ 227.327248]
[ 227.327248] ---------- ISR -----------
[ 227.344968]
[ 227.344968] ---------- ISR -----------
[ 227.351703]
[ 227.351703] ---------- ISR -----------
[ 227.360189]
[ 227.360189] ---------- ISR -----------
[ 227.371751]
[ 227.371751] ---------- ISR -----------
[ 227.387809]
[ 227.387809] ---------- ISR -----------
[ 227.396767]
[ 227.396767] ---------- ISR -----------
[ 227.413297]
[ 227.413297] ---------- ISR -----------
You see here the
probe function being called(Probing ...)
enabling the PCI device(Enabling PCI device ...)
the memory regions being allocated
the interrupt line (line 5)
the PCM constructors (>>> PCM CONSTRUCTOR: running...)
some dumps from the interrupt handler.
And some lines from my application:
/* Open PCM device for playback. */
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
printf(
"unable to open pcm device: %s\n",
snd_strerror(rc));
exit(1);
}
printf("Device opened ... rc = %d \n", rc);
Here I try to open my device. If you pay attention to the driver code above the playback_open() function should printk() some message and should return -10. I did this intentionally. But my application shows that the result from snd_pcm_open() is OK(zero I mean). So it looks like my application does not see my driver but tries to use something else.
I will place also all sound the modules being loaded currently:
Module Size Used by
...
alsa 13273 0 //this is my driver
snd_ac97_codec 105592 0
snd_pcm 80357 2 alsa,snd_ac97_codec
snd_page_alloc 14036 1 snd_pcm
ac97_bus 12670 1 snd_ac97_codec
snd_seq_midi 13132 0
snd_rawmidi 25382 1 snd_seq_midi
snd_seq_midi_event 14475 1 snd_seq_midi
snd_seq 51256 2 snd_seq_midi,snd_seq_midi_event
snd_timer 24503 2 snd_pcm,snd_seq
snd_seq_device 14137 3 snd_seq_midi,snd_rawmidi,snd_seq
snd 62027 7 alsa,snd_ac97_codec,snd_pcm,snd_rawmidi,
snd_seq,snd_timer,snd_seq_device
soundcore 14599 1 snd
Here is the output from lspci -v which will show the info for the audio device:
00:05.0 Multimedia audio controller: Intel Corporation 82801AA AC'97 Audio Controller (rev 01)
Subsystem: Intel Corporation Device 0000
Flags: bus master, medium devsel, latency 0, IRQ 5
I/O ports at d100 [size=256]
I/O ports at d200 [size=64]
Kernel driver in use: My Own Chip
Kernel modules: snd-nedelinxalsaxpci, snd-intel8x0
I build my kernel with my driver, because I thought this might help, but it did not(snd-nedelinxalsaxpci is my driver, and snd-intel8x0 is the original module). "My Own Chip" comes from my driver.
I don't know what other info I could give you.
And thanks a lot for the support.
Your problem is that you are calling the PCM constructor after the call to snd_card_register.
Sound card devices are accessible to userspace only if they are registered after they are created.
There is even a comment in your code that tells you about the correct place to do this:
/* (5) Create other components PCM, mixers, MIDI etc */

Resources