I have the following gstreamer basic tutorial. When I compile and run the program, I am only getting a blank screen. The same happens when I use mplayer, but I supply -vo x11 option to it and it works well(for mplayer). So, I am guessing the issue gstreamer is also the same. So, my question is..."What should I do to tell the program that my output driver is x11?" How do I get rid of the blank screen?
Thanks
#include <gst/gst.h>
int main(int argc, char *argv[]) {
GstElement *pipeline;
GstBus *bus;
GstMessage *msg;
/* Initialize GStreamer */
gst_init (&argc, &argv);
/* Build the pipeline */
/*
pipeline = gst_parse_launch ("playbin2 uri=http://docs.gstreamer.com/media/sintel_trailer-480p.webm", NULL);
*/
pipeline = gst_parse_launch ("playbin2 uri=file:///home/mylogin/gstreamerstuff/sintel_trailer-480p.webm", NULL);
/* Start playing */
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* Wait until error or EOS */
bus = gst_element_get_bus (pipeline);
msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
/* Free resources */
if (msg != NULL)
gst_message_unref (msg);
gst_object_unref (bus);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}
Try adding this code, before setting the pipeline to playing.
{
GstElement* vsink = gst_element_factory_make ("ximagesink", NULL);
g_object_set (G_OBJECT (pipeline), "video-sink", vsink, NULL);
}
The above code makes sure that the pipeline uses the GstElement called ximagesink.
This element (type = sink) is X11 based and dumps (to screen) the incoming buffers using
X11 APIs
Related
Disclaimer - I have to admit that it's the 1'st time I'm using this kernel interface (socket).
I'm currently working on a design of a kernel module that is based on a netlink socket .
I'm using Ubuntu14.04 and linux kernel 4.
As a starter, I wanted to make sure that I can use the netlink socket in both directions.
I've written an application that does the following:
1) User send a message to kernel via the netlink socket.
2) Kernel, upon receiving the message – sends "ABCD" string message to a workqueue.
3) When the "ABCD" message is received by the workqueue, it calls a function (named - my_wq_function) which send it back to the user space via netlink socket.
4) In the user space I'm using a recvmsg function (blocking until a message is received) and displays the "ABCD" message.
My problem is that the return value from the recvmsg function is 20 (instead of 4), and the data itself (i.e. NLMSG_DATA) is empty.
During the debug I tried to change the message to "ABCD1234" and got a return value of 24 bytes, however the data is still empty.
I also verified that my entire path until the point of sending the "ABCD" from kernel to the socket is OK.
Not sure what I'm doing wrong here & will highly appreciate your help.
Thanks in advance, MotiC.
my code example can be found below:
User space code:
printf("netlink receiver thread started...\n");
nlh_rcv = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
while(true) //endless loop on netlink socket
{
memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov_rcv.iov_base = (void *)nlh_rcv;
iov_rcv.iov_len = nlh_rcv->nlmsg_len;
msg_rcv.msg_name = (void *)&dest_addr;
msg_rcv.msg_namelen = sizeof(dest_addr);
msg_rcv.msg_iov = &iov;
msg_rcv.msg_iovlen = 1;
ret=recvmsg(sock_fd, &msg_rcv, 0);
printf("errno=%i bytes=%i message from kernel: %s\n",errno, ret, (char*)NLMSG_DATA(nlh_rcv));
uint8_t mymsg[100];
memcpy(mymsg, NLMSG_DATA(nlh_rcv), 100);
printf("message from kernel: %s\n",mymsg);
}
Kernel space code:
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
MODULE_LICENSE("GPL");
#include "rf_Kdriver_main.h"
//------ definitions ------------------------------------------------------------------------------------------------------------
#define NETLINK_USER 31
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sock *nl_sk = NULL;
struct nlmsghdr *nlh;
struct nlmsghdr *nlh_out;
struct sk_buff *skb_out;
char buf_to_user[100];
int pid;
//------------------------------------------------------------------------------------------------------------------------------
struct workqueue_struct *my_wq;
typedef struct {
struct work_struct my_work;
uint8_t msg_to_pc[128];
uint8_t msg_len;
} my_work_t;
my_work_t *work, *work2;
//-----------------------------------------------------------------------------------------------------------------------------
static void my_wq_function( struct work_struct *work)
{
int res;
my_work_t *my_work = (my_work_t *)work;
skb_out = nlmsg_new(my_work->msg_len,0);
if (!skb_out)
{
printk("Failed to allocate new skb\n");
return;
}
nlh_out = nlmsg_put(skb_out, 0, 0, NLMSG_DONE,my_work->msg_len, 0);
NETLINK_CB(skb_out).dst_group = 0;
memcpy((char*)NLMSG_DATA(nlh_out), my_work->msg_to_pc , my_work->msg_len);
printk( "dequeue message to pc=%s len=%i\n", (char*)NLMSG_DATA(nlh_out), (int)strlen((char*)NLMSG_DATA(nlh_out)));
res = nlmsg_unicast(nl_sk, skb_out, pid);
if (res<0)
printk("Failed to send message from kernel to user\n");
kfree( (void *)work );
return;
}
//-----------------------------------------------------------------------------------------------------------------------------
int send_up_msg_to_workque(uint8_t msg_to_pc[], uint8_t msg_len)
{
int ret=0;
work = (my_work_t *)kmalloc(sizeof(my_work_t), GFP_KERNEL);
if (work) {
INIT_WORK( (struct work_struct *)work, my_wq_function );
memcpy(work->msg_to_pc, msg_to_pc, msg_len);
work->msg_len = msg_len;
ret = queue_work( my_wq, /*(struct work_struct *)RR*/work );
printk("kuku ret=%i msg=%s\n",ret,work->msg_to_pc);
}
return ret;
}
//------------------------------------------------------------------------------------------------------------------------------
static void netlink_recv_msg(struct sk_buff *skb)
{
char *msg = "ABCD1234";
printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
nlh=(struct nlmsghdr*)skb->data;
printk(KERN_INFO "Netlink at kernel received msg payload: %s\n",(char*)NLMSG_DATA(nlh));
//rr
pid = nlh->nlmsg_pid;
send_up_msg_to_workque((uint8_t*) msg, strlen(msg));
}
//-------------------------------------------------------------------------------------------------------------------------------------
struct netlink_kernel_cfg cfg = {
.input = netlink_recv_msg,
};
static int __init rf_driver_start(void)
{
printk(KERN_INFO "Loading RF Driver module1...\n");
my_wq = create_workqueue("my_queue");
if (!my_wq)
{
printk("Failed to create work queue\n");
}
printk("Entering: %s\n",__FUNCTION__);
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
if(!nl_sk)
{
printk(KERN_ALERT "Error creating socket.\n");
return -10;
}
return 0;
}
//--------------------------------------------------------------------------------------------------------------
static void __exit rf_driver_end(void)
{
netlink_kernel_release(nl_sk);
flush_workqueue(my_wq);
destroy_workqueue(my_wq);
printk(KERN_INFO "RF Driver exit...\n");
}
module_init(rf_driver_start);
module_exit(rf_driver_end);
Update,
I changed my user space function to:
char buf[100];
ret=recv(sock_fd, buf, 100, 0);
instead of:
ret=recvmsg(sock_fd, &msg_rcv, 0);
and it works...
does anyone have an idea regarding this strange behavior ?
Thanks.
Can you please paste complete userspace code.
I guess 'len' int this code is the issue:
memset(nlh_rcv, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov_rcv.iov_len = nlh_rcv->nlmsg_len; << check to what value is it getting initialized.
I am trying to show the gstreamer video in qt frameless window .
My gstreamer pipeline for which i am creating code is : gst-launch-1.0 -v rtspsrc location=rtsp://192.168.1.15:8554/test ! rtpjitterbuffer ! rtph264depay ! avdec_h264 ! d3dvideosink sync=false
This is my first question please answer me. My code is as below
My code is working for a qt window. It is showing the video which it is receiving
from rtsp link but i have two major issues in it:
1. When i minimize this window, It loses it's output video and starts to show a blank screen. 2. I want to open this video in a frameless window but if i do so then it displays nothing.
I am using Qt-4.8.12 and gstreamer version 1.4.5 for windows 7 64 bit. Any help regarding these two issues is highly appreciated. Thanks in Advance.
#include <glib.h>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>
#include <QApplication>
#include <QTimer>
#include <QWidget>
#include <stdio.h>
#include "qmainwindow.h"
static void on_pad_added (GstElement *element, GstPad *pad, gpointer data);
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data);
int main(int argc, char *argv[])
{
if (!g_thread_supported ())
g_thread_init (NULL);
/* Initialize GStreamer */
gst_init (&argc, &argv);
QApplication app(argc, argv);
app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit ()));
/* Creating Elements */
//GstElement *pipeLine = gst_pipeline_new ("xvoverlay");
QWidget window;
// QMainWindow window;
window.resize(1024,768);
WId xwinid=window.winId();
GMainLoop *loop;
GstElement *pipeLine, *rtspSrc, *rtpJitterBuffer, *rtpH264Depay, *avDecH264, *videoSink;
rtspSrc = gst_element_factory_make("rtspsrc", NULL);
rtpJitterBuffer = gst_element_factory_make("rtpjitterbuffer", NULL);
rtpH264Depay = gst_element_factory_make("rtph264depay", NULL);
avDecH264 = gst_element_factory_make("avdec_h264", NULL);
videoSink = gst_element_factory_make("d3dvideosink", NULL);
loop = g_main_loop_new (NULL, FALSE);
if (!rtspSrc || !rtpJitterBuffer || !rtpH264Depay || !avDecH264 || !videoSink)
{
g_printerr ("Not all elements could be created.\n");
return -1;
}
/* Set element properties */
g_object_set( rtspSrc, "location", "rtsp://192.168.1.16:8554/test" , NULL);
g_object_set( videoSink, "sync", false, NULL);
/*Initializing Pipeline*/
pipeLine = gst_pipeline_new ("TestPipeLine");
if (!pipeLine)
{
g_printerr ("Pipeline could not be created.");
}
/* we add a message handler */
GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (pipeLine));
gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
/*Adding Components to the pipeline */
gst_bin_add_many (GST_BIN(pipeLine),
rtspSrc,
rtpJitterBuffer,
rtpH264Depay,
avDecH264,
videoSink,
NULL);
/* if (gst_element_link (rtspSrc, rtpJitterBuffer) != TRUE)
{
g_printerr ("rtspSrc & rtpJitterBuffer could not be linked.\n");
gst_object_unref (pipeLine);
return -1;
}
*/
if (gst_element_link (rtpJitterBuffer, rtpH264Depay) != TRUE)
{
g_printerr ("rtpJitterBuffer and rtpH264Depay could not be linked.\n");
gst_object_unref (pipeLine);
return -1;
}
if (gst_element_link (rtpH264Depay, avDecH264) != TRUE)
{
g_printerr ("rtpH264Depay and avDecH264 could not be linked.\n");
gst_object_unref (pipeLine);
return -1;
}
if (gst_element_link (avDecH264, videoSink) != TRUE)
{
g_printerr ("avDecH264 and videoSink could not be linked.\n");
gst_object_unref (pipeLine);
return -1;
}
g_signal_connect (rtspSrc, "pad-added", G_CALLBACK (on_pad_added), rtpJitterBuffer);
window.setWindowFlags(Qt::FramelessWindowHint);
// else
// g_printerr("Pipeline created");zz
gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY(videoSink), guintptr(xwinid));
window.show();
/* Set the pipeline to "playing" state*/
g_print ("Now playing: %s\n", argv[1]);
gst_element_set_state (pipeLine, GST_STATE_PLAYING);
app.exec();
/* Iterate */
g_print ("Running...\n");
g_main_loop_run (loop);
/* Out of the main loop, clean up nicely */
g_print ("Returned, stopping playback\n");
gst_element_set_state (pipeLine, GST_STATE_NULL);
g_print ("Deleting pipeline\n");
gst_object_unref (GST_OBJECT (pipeLine));
return 0;
}
static void on_pad_added (GstElement *element, GstPad *pad, gpointer data)
{
GstPad *sinkpad;
GstElement *decoder = (GstElement *) data;
/* We can now link this pad with the vorbis-decoder sink pad */
g_print ("Dynamic pad created, linking demuxer/decoder\n");
sinkpad = gst_element_get_static_pad (decoder, "sink");
gst_pad_link (pad, sinkpad);
gst_object_unref (sinkpad);
}
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
g_print ("End of stream\n");
g_main_loop_quit (loop);
break;
case GST_MESSAGE_ERROR: {
gchar *debug;
GError *error;
gst_message_parse_error (msg, &error, &debug);
g_free (debug);
g_printerr ("Error: %s\n", error->message);
g_error_free (error);
g_main_loop_quit (loop);
break;
}
default:
break;
}
return TRUE;
}
If you switch back to using QWindow, this will work:
window.setWindowFlags (Qt::FramelessWindowHint);
I'm not sure how, but I think something similar is available for QWidget.
I have been following the Linux 2.6 Kernel Module Programming Guide, when I ran into the first example from Chapter 5, called procfs1.c.
It would not compile out of the box, and after checking various related questions, it still took me quite some time to figure out the correct changes to make it compile and work as intended.
Therefore, I am posting my updated code for people in the future. I am running kernel 2.6.32-279.el6.x86_64.
Here is an updated version of the example that works with kernel version 2.6.32-279.el6.x86_64.
/*
* procfs1.c - create a "file" in /proc
*
*/
#include <linux/module.h> /* Specifically, a module */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
#define procfs_name "helloworld"
/**
* This structure hold information about the /proc file
*
*/
struct proc_dir_entry *Our_Proc_File;
static ssize_t procfile_read(struct file *filp,
char *buffer,
size_t length,
loff_t * offset)
{
int ret;
printk(KERN_INFO "procfile_read (/proc/%s) called\n", procfs_name);
if (*offset > 0) {
/* we have finished to read, return 0 */
ret = 0;
} else {
/* fill the buffer, return the buffer size */
ret = sprintf(buffer, "HelloWorld!\n");
*offset = ret;
}
return ret;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.read = procfile_read,
};
int init_module()
{
Our_Proc_File = proc_create(procfs_name, S_IFREG | S_IRUGO, NULL, &fops);
if (Our_Proc_File == NULL) {
remove_proc_entry(procfs_name, NULL);
printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
procfs_name);
return -ENOMEM;
}
Our_Proc_File->uid = 0;
Our_Proc_File->gid = 0;
Our_Proc_File->size = 37;
printk(KERN_INFO "/proc/%s created\n", procfs_name);
return 0; /* everything is ok */
}
void cleanup_module()
{
remove_proc_entry(procfs_name, NULL);
printk(KERN_INFO "/proc/%s removed\n", procfs_name);
}
I've been following the examples on Audio Units from Learning Core Audio book by Adamson and Avila. I'm getting the above error for some reason. I #include <CoreAudio/CoreAudio.h> even just to make sure I am importing the possible libraries for Audio, and made sure to configure the "Link Binary with Libraries" under the "Build Phases" part of target. I even changed the Base SDK to OSX 10.7 (as opposed to the default 10.8) to see what happens, but no cigar. And according to the documentation, the Speech Synthesis API is not fully deprecated in anyway -- some functions are, however. My MacBook is running 10.7.5. XCode is Version 4.6 (4H127.
Below I put a comment on where I got the error in CAPS. Any ideas?
//
// main.c
// CAsamplerSynthesisGraph
//
// Created by Edderic Ugaddan on 6/25/13.
// Copyright (c) 2013 Edderic Ugaddan. All rights reserved.
//
//#include <CoreFoundation/CoreFoundation.h>
#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioToolbox.h>
#include <CoreAudio/CoreAudio.h>
// #define PART_II
#pragma mark user-data struct
// Insert Listing 7.19 here
typedef struct MyAUGraphPlayer {
AUGraph graph;
AudioUnit samplerAU;
} MyAUGraphPlayer;
#pragma mark utility functions
// Insert Listing 4.2 here
static void CheckError(OSStatus error, const char *operation) {
if (error == noErr) return;
char errorString[20];
// See if it appears to be a 4-char-code.
*(UInt32 *)*(errorString + 1) = CFSwapInt32HostToBig(error);
if (isprint(errorString[1]) && isprint(errorString[2]) &&
isprint(errorString[3]) && isprint(errorString[4])) {
errorString[0] = errorString[5] = '\'';
errorString[6] = '\0';
}
else {
// No, format it as an integer.
sprintf(errorString, "%d", (int) error);
fprintf(stderr, "Error: %s (%s)\n", operation, errorString);
exit(1);
}
}
void CreateMyAUGraph(MyAUGraphPlayer *player) {
// Insert Listing 7.21 here
// Create a new graph
CheckError(NewAUGraph(&player->graph),
"NewAUGraph failed");
// Generates a description that matches our output device (speakers)
AudioComponentDescription outputcd = {0};
outputcd.componentType = kAudioUnitType_Output;
outputcd.componentSubType = kAudioUnitSubType_DefaultOutput;
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
// Adds a node with above description to the graph
AUNode outputNode;
CheckError(AUGraphAddNode(player->graph,
&outputcd,
&outputNode),
"AUGraphAddNode[kAudioUnitSubType_DefaultOutput] failed");
// Generates a description that will match a generator AU
// of type: sampler synthesizer
AudioComponentDescription samplercd = {0};
samplercd.componentType = kAudioUnitType_Generator;
samplercd.componentSubType = kAudioUnitSubType_SpeechSynthesis; // I GET ERROR HERE
samplercd.componentManufacturer = kAudioUnitManufacturer_Apple;
// Adds a node with above description to the graph
AUNode samplerNode;
CheckError(AUGraphAddNode(player->graph,
&samplercd,
&samplerNode),
"AUGraphAddNode[kAudioUnitSubType_samplerSynthesis] failed");
// Opening the graph opens all contained audio units, but
// does not allocate any resources yet
CheckError(AUGraphOpen(player->graph),
"AUGraphOpen failed");
// Gets the reference to the AudioUnit object for the
// sampler graph node
CheckError(AUGraphNodeInfo(player->graph,
samplerNode,
NULL,
&player->samplerAU),
"AUGraphNodeInfo failed");
#ifdef PART_II
// Insert Listing 7.24 - 7.26 here
#else
// Insert Listing 7.22 here
// Connect the output source of the sampler synthesis AU
// to the input source of the output node
CheckError(AUGraphConnectNodeInput(player->graph,
samplerNode,
0,
outputNode,
0),
"AUGraphConnectNodeInput failed");
#endif
}
// Replace with listing 7.23
void PrepareSamplerAU(MyAUGraphPlayer *player) {
// Sampler
}
#pragma mark main function
// Replace with listing 7.20
int main(int argc, const char * argv[])
{
MyAUGraphPlayer player = {0};
// Build a basic sampler->speakers graph
CreateMyAUGraph(&player);
// Configure the sampler synthesizer
PrepareSamplerAU(&player);
// Start playing
CheckError(AUGraphStart(player.graph),
"AUGraphStart failed");
// Sleep a while so the sampler can play out
usleep ((int)(10 * 1000. * 1000.));
// Cleanup
AUGraphStop(player.graph);
AUGraphUninitialize(player.graph);
AUGraphClose(player.graph);
return 0;
}
kAudioUnitSubType_SpeechSynthesis is declared in SpeechSynthesis.framework, which lives within the ApplicationServices.framework umbrella framework, so you should #import < ApplicationServices.framework>.
I'm a beginner to the Linux programming and trying my hands on some device driver examples while practising.
The below code (a trimmed down version of tiny_tty.c) loads perfectly using insmod and I'm able to see it in /proc/tty/drivers , /proc/modules and device nodes are getting created under /dev. When I try to write to device file like echo "abcd" > /dev/ttyms0 (I hope this is fine) or read like cat /dev/ttyms0, the kernel panics with a call trace on the screen. I'm on kernel 3.5.0 under Ubuntu. Unfortunately I'm not able to capture the trace , as when it panics I'm left with no option but reboot using power button. I believe some issue with timer is here, as the trace shows a line on top saying :
"*kernel bug at /build/buildd/linux-3.5.0/kernel/timer.c:901*", then the call trace , followed by
"*EIP is at add_timer+0x18/0x20*"
Below is the full code. Any guidance is very much appreciated in anticipation.
10May2013 : I tried initializing the timer in open function and this time below is the call trace for "kernel panic - not syncing : fatal exception in interrupt panic occurred, switching back to text console":
update_sd_lb_stats+0xcd/0x4b0
find_busiest_group+0x2e/0x420
enqueue_entity+0xcb/0x510
load_balance+0x7e/0x5e0
rebalance_domains+0xed/0x150
__do_softirq+0xdb/0x180
local_bh_enable_ip+0x90/0x90
<IRQ>
copy_to_user0x41/0x60
sys_gettimeofday+0x2a/0x70
sysenter_do_call0x12/0x20
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/wait.h>
#include <linux/errno.h>
#include <linux/slab.h> /* kmalloc() */
#include <linux/tty_driver.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/mutex.h>
#include <linux/serial.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/termios.h>
MODULE_LICENSE("GPL");
#define MS_TTY_MAJOR 250 //test value
#define MS_TTY_NUM_DEV 2
#define DELAY_TIME HZ * 2 /* 2 seconds per character */
#define TINY_DATA_CHARACTER 't'
static int major_num;
//static int minor_num=0;
//static int num_tty_dev=2;
/* Below structure is a wrapper for device specific fields */
struct ms_tty_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 */
struct timer_list *timer;
};
static struct ms_tty_serial *ms_tty_table[MS_TTY_NUM_DEV]; /* initially all NULL */
static void ms_tty_timer(unsigned long timer_data)
{
struct ms_tty_serial *ms_ptr = (struct ms_tty_serial *)timer_data;
struct tty_struct *tty;
char data[1] = {TINY_DATA_CHARACTER};
int data_size = 1;
if (!ms_ptr)
return;
tty = ms_ptr->tty;
tty->low_latency=1;
/* send the data to the tty layer for users to read. This doesn't
* actually push the data through unless tty->low_latency is set */
tty_buffer_request_room (tty, data_size);
tty_insert_flip_string(tty, data, data_size);
tty_flip_buffer_push(tty);
/* resubmit the timer again */
ms_ptr->timer->expires = jiffies + DELAY_TIME;
add_timer(ms_ptr->timer);
}
//// Define the open function ////
static int tty_ms_open(struct tty_struct *tty_this, struct file *file_this)
{
printk(KERN_ALERT "tty_ms driver: OPENED ...\n");
struct ms_tty_serial *ms_ptr;
struct timer_list *timer;
int index;
/* initialize the pointer in case something fails */
tty_this->driver_data = NULL;
/* get the serial object associated with this tty pointer */
index = tty_this->index;
ms_ptr = ms_tty_table[index];
if (ms_ptr == NULL) {
/* first time accessing this device, create it */
ms_ptr = kmalloc(sizeof(*ms_ptr), GFP_KERNEL);
if (!ms_ptr)
return -ENOMEM;
// init_MUTEX(&ms_ptr->sem); /* didn't work for this kernel version 3.5.0 */
#ifndef init_MUTEX /* sema_init is to be used for kernel 2.6.37 and above */
sema_init(&ms_ptr->sem,1);
#else
init_MUTEX(&ms_ptr->sem);
#endif
ms_ptr->open_count = 0;
ms_ptr->timer = NULL;
ms_tty_table[index] = ms_ptr;
}
down(&ms_ptr->sem);
/* save our structure within the tty structure */
tty_this->driver_data = ms_ptr;
ms_ptr->tty = tty_this;
ms_ptr->filp = file_this; // to be tried
++ms_ptr->open_count;
if (ms_ptr->open_count == 1) {
/* this is the first time this port is opened */
/* do any hardware initialization needed here */
/* create timer and submit it */
if (!ms_ptr->timer) {
timer = kmalloc(sizeof(*timer), GFP_KERNEL);
if (!timer) {
up(&ms_ptr->sem);
return -ENOMEM;
}
ms_ptr->timer = timer;
}
init_timer (ms_ptr->timer); // to be tried
ms_ptr->timer->data = (unsigned long )ms_ptr;
ms_ptr->timer->expires = jiffies + DELAY_TIME;
ms_ptr->timer->function = ms_tty_timer;
add_timer(ms_ptr->timer);
}
up(&ms_ptr->sem);
return 0;
}
//// Define the close function ////
static void do_close(struct ms_tty_serial *ms_ptr)
{
down(&ms_ptr->sem);
if (!ms_ptr->open_count) {
/* port was never opened */
goto exit;
}
--ms_ptr->open_count;
if (ms_ptr->open_count <= 0) {
/* The port is being closed by the last user. */
/* Do any hardware specific stuff here */
/* shut down our timer */
del_timer(ms_ptr->timer);
}
exit:
up(&ms_ptr->sem);
}
static void tty_ms_close(struct tty_struct *tty_this, struct file *file_this)
{
printk(KERN_ALERT "tty_ms driver: CLOSING ...\n");
struct ms_tty_serial *ms_ptr = tty_this->driver_data;
if (ms_ptr)
do_close(ms_ptr);
}
//// Define the write function ////
static int tty_ms_write(struct tty_struct *tty_this, const unsigned char *tty_buff, int count)
{
printk(KERN_ALERT "tty_ms driver: WRITING ...\n");
struct ms_tty_serial *ms_ptr = tty_this->driver_data;
int i;
int retval = -EINVAL;
if (!ms_ptr)
return -ENODEV;
down(&ms_ptr->sem);
if (!ms_ptr->open_count)
/* port was not opened */
{
up(&ms_ptr->sem);
return retval;
}
/* 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 ", tty_buff[i]);
printk("\n");
return 0;
}
// Define the operations for tty driver in tty_operations struct //
static struct tty_operations tty_ms_ops = {
.open = tty_ms_open,
.close = tty_ms_close,
.write = tty_ms_write,
//.set_termios = tty_ms_set_termios,
};
///////////////////////////////////////// Module Initialization Starts ////////////////////////////////////
static struct tty_driver *tty_ms_driver;
static int tty_ms_init(void)
{
// static int result;
static int retval,iter;
// Allocate the tty_driver struct for this driver //
tty_ms_driver = alloc_tty_driver(MS_TTY_NUM_DEV);
if (!tty_ms_driver)
return -ENOMEM; // Error NO Memory , allocation failed
else
printk(KERN_INFO "tty_driver structure allocated..!!"); //debug line
// Initialize the allocated tty_driver structure //
tty_ms_driver->magic=TTY_DRIVER_MAGIC;
tty_ms_driver->owner = THIS_MODULE;
tty_ms_driver->driver_name = "tty_ms";
tty_ms_driver->name = "ttyms";
tty_ms_driver->major = MS_TTY_MAJOR,
tty_ms_driver->type = TTY_DRIVER_TYPE_SERIAL,
tty_ms_driver->subtype = SERIAL_TYPE_NORMAL,
tty_ms_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV,
tty_ms_driver->init_termios = tty_std_termios;
tty_ms_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(tty_ms_driver, &tty_ms_ops);
printk(KERN_INFO "allocated tty_driver structure -INITIALIZED."); //debug line
//// Register this driver with the tty core ////
retval = tty_register_driver(tty_ms_driver);
if (retval) {
printk(KERN_ERR "failed to register tty_ms driver\n tty registration returned %d", retval);
put_tty_driver(tty_ms_driver);
return retval;
}
//// Register the tty devices(nodes) with the tty core ////
for (iter = 0; iter < MS_TTY_NUM_DEV ; ++iter)
tty_register_device(tty_ms_driver, iter, NULL);
return 0; // All initializations done
} // init func ends
///////////////////////////////////////// Module Initialization Ends ////////////////////////////////////
///////////////////////////////////////// Module cleanup Starts ////////////////////////////////////
static void tty_ms_terminate(void)
{
static int iter;
struct ms_tty_serial *tty_ser;
printk(KERN_ALERT "tty_ms driver: Unloading...\n");
for(iter=1;iter<=MS_TTY_NUM_DEV;iter++)
tty_unregister_device(tty_ms_driver,iter); //unregister all the devices, from tty layer
tty_unregister_driver(tty_ms_driver); // Now unregister the driver from tty layer
/* shut down all of the timers and free the memory */
for (iter = 0; iter < MS_TTY_NUM_DEV; ++iter) {
tty_ser = ms_tty_table[iter];
if (tty_ser) {
/* close the port */
while (tty_ser->open_count)
do_close(tty_ser);
/* shut down our timer and free the memory */
del_timer(tty_ser->timer);
kfree(tty_ser->timer);
kfree(tty_ser);
ms_tty_table[iter] = NULL;
}
}
dev_t devno=MKDEV(major_num,0); // wrap major/minor numbers in a dev_t structure , to pass for deassigning.
unregister_chrdev_region(devno,MS_TTY_NUM_DEV);
}
///////////////////////////////////////// Module cleanup ends ////////////////////////////////////
module_init(tty_ms_init);
module_exit(tty_ms_terminate);