How to send a bit to the parallel port on Linux (2nd part)

In this second part of how to send bits to the parallel port on Linux, i describe here basics on how to do the same on kernel space.
Here is a simple linux kernel module, that create a char device named parlport, and you can communicate directly with device using the /dev/parlport

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/unistd.h>
#include <asm/uaccess.h>
#include <linux/file.h>
#include <asm/io.h>

#define NAME “parlp”
#define VERSION “0.1”
#define LICENSE “GPL”
#define DESCPT “Simple Parallel Port LED driver”
#define AUTHOR “Mezgani Ali\n”\
“mail: mezgani [AT] nativelabs [.] org\n”\
“blog: https://securfox.wordpress.com/&#8221;

#define SUCCESS 0
#define DEVICE_NAME “parlport”
#define BASEPORT 0x0378

static int major = 61; /* major number assigned to our device driver */

static int __init start_module(void);
static void __exit clean_module(void);

static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, char *, size_t, loff_t *);

static struct file_operations fops = {
.open = device_open,
.release = device_release,
.read = device_read,
.write = device_write
};

static int
__init start_module(void)
{
int result;

result = register_chrdev(major, DEVICE_NAME, &fops);

if (result < 0) {
printk(KERN_ALERT “Registering device failed with %d\n”, major);
return result;
}

if (!(request_region(BASEPORT, 1, DEVICE_NAME))){
printk(KERN_WARNING “Winbond error request region: %X\n”, BASEPORT);
release_region(BASEPORT, 1);

return result;
}

printk(KERN_INFO “I was assigned major number %d. To talk to\n”, major);
printk(KERN_INFO “the driver, create a dev file with\n”);
printk(KERN_INFO “‘mknod /dev/%s c %d 0’.\n”, DEVICE_NAME, major);

return SUCCESS;
}

static void
__exit clean_module(void)
{
release_region(BASEPORT, 1);

unregister_chrdev(major, DEVICE_NAME);
printk(KERN_ALERT “unregister_chrdev && cleaning module\n”);

}

static int
device_open(struct inode *inode, struct file *file)
{
try_module_get(THIS_MODULE);
return SUCCESS;
}

static int
device_release(struct inode *inode, struct file *file)
{
module_put(THIS_MODULE);
return 0;
}

static ssize_t
device_read(struct file *filp, char *buffer, size_t length, loff_t * offset)
{
unsigned char pbuffer;
int len;

/* input a byte (8 bits) from a port, call inb(port), it returns the byte it got */
pbuffer = inb(BASEPORT);

len = copy_to_user(buffer, &pbuffer, 1);
if (len) return -EFAULT;

if (*offset == 0) {
*offset += 1;
return 1;
} else {
return 0;
}
}

static ssize_t
device_write(struct file *filp, char *buffer, size_t length, loff_t * offset)
{

char pbuffer, *ptr;
int len;

ptr = buffer + length – 1;
len = copy_from_user(&pbuffer, ptr, 1);
if (len) return -EFAULT;

/* output the data to parallel port */
outb(pbuffer, BASEPORT);
return 1;
}

module_init(start_module);
module_exit(clean_module);

MODULE_LICENSE(LICENSE);
MODULE_AUTHOR(AUTHOR);
MODULE_DESCRIPTION(DESCPT);
MODULE_VERSION(VERSION);

Example of use after compilation ;

# insmod parlport.ko
# mknod /dev/parlport c 61 0
# chown 666 /dev/parlport
# echo F > /dev/parlport

How to look up domain names and addresses.

To resolve host names and addresses in the domain name system or the local hosts, there are many functions defined as well as the function gethostbyname.

The gethostbyname() is a function that returns a structure of type hostent for the given host name.
Here name is either a host name, or an IPv4 address in standard dot notation.
You can find here an example of using gethostbyname(3).

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>

struct hostent *ptr;

/* The hostent structure is defined in as follows:
struct hostent {
char *h_name; //official name of host
char **h_aliases; //alias list
int h_addrtype; //host address type
int h_length; // length of address
char **h_addr_list; //list of addresses
}
#define h_addr h_addr_list[0]
*/

int
main(int argc, char **argv)
{

// two arguments are permitted
// the second one is the hostname

if (argc != 2) {
fprintf(stderr,”Usage: %s hostname\n”,argv[0]);
exit(0);
}

ptr = gethostbyname(argv[1]);
int i=0;

// gethostbyname() returns NULL pointer if failed.
if (ptr == NULL) {
fprintf(stderr,”gethostbyname() failed\n”);
exit(1);
} else {

// If the host name, has many translation address so, until there are addresses loop

// we will only use the s_addr field in the in_addr structure
// which records the host address number as an uint32_t

while(ptr -> h_addr_list[i]) {
if ( ptr -> h_addr_list[i] != NULL)
printf(“%s\n”, inet_ntoa( *( struct in_addr*)( ptr -> h_addr_list[i])));
i++;
}
}
return 0;

}

Static and Shared library

Creating Shared library:
First, create the object files that will go into the shared library using the gcc -fPIC or -fpic flag.
The -fPIC and -fpic options enable “position independent code” generation, a requirement for shared libraries.

$ gcc -fPIC -Wall -g -c foo.c

Every shared library has a special name called the “soname”. The soname has the prefix “lib”,
the name of the library, the phrase “.so”, followed by a period and a version number.

We can use ‘ld’, the GNU linker to create our shared library. The ld combines a number of object and archive files,
relocates their data and ties up symbol references.

$ ld -shared -soname libfoo.so.1 -o libfoo.so.1.0 foo.o

Creating Static library:
Static libraries are simply a collection of ordinary object files; conventionally, static libraries end with the ‘.a’‘ .
To generate object file use ‘-c‘ flag with gcc.

$ gcc -c bar.c -o bar.o

Flags:
-c Compile or assemble the source files, but do not link. The compiler output is object files corresponding to each source file.
-o To specifiy the output file name.

A static library can contain more than one object files. We need to copy all object file in to a single file.
This single file is our static library. We can use archiver(ar) to create to create our static library.

$ ar rcs libbar.a bar.o

Options:
r – Insert the files into archive (with replacement).
c – Create the archive.
s – Write an object-file index into the archive, or update an existing one, even if no other change is made to the archive.