Standard Parallel Port Control Using the Custom Device Driver liftmon_snowcon


Standard Parallel Port Control Using the Custom Device Driver liftmon_snowcon

The Project Trailblazer engineers could barely contain their enthusiasm. They had an interface circuit that connected I/O modules to the parallel port. They had written code using inb and outb to control their interface board. They had created, compiled, and tested a proc module. Now they needed to take a really big step: Combine all these accomplishments and develop the custom lift monitoring and snow-making control device driver, liftmon_snowcon.

The engineers created the following requirements for liftmon_snowcon:

  • LS1: The driver should load at startup. This is easily accomplished by adding a line to an /etc/init.d/rcS or using the kernel module load file /etc/modules.

  • LS2: When it is loaded, the driver should enable the latch output to drive the output modules. The driver's module_init function needs to assert OUTPUT_ENABLE and its module_exit function should de-assert OUTPUT_ENABLE.

  • LS3: The driver should shield software developers from interface logic specifics. The device driver should provide a hardware control interface so that the developer doesn't need to know about OUTPUT_ENABLE, OUTPUT_LATCH, data lines, INPUT_ENABLE, or assertion levels.

  • LS4: The driver should offer control of individual pieces of snow-making equipment, without requiring the developer to perform bit manipulation. The device driver should create a /proc file for each of the output modules: snowwatervalve1, snowwatervalve2, snowwatervalve3, and snowheater1. Writing 1 or 0 to a specific file should turn the specific module on or off. For example, this turns on the Water Valve 2 output module:

     echo 1 > /proc/trailblazer/snowwatervalve2 

    Notice that there is no bit manipulation and the device driver provides actual named files that correspond to the physical world. Internal to the device driver should be an unsigned char variable called snowcondata. The driver should perform the necessary bit manipulation within snowcondata.

  • LS5: The driver should offer monitoring of individual lift modules, without requiring the developer to perform bit manipulation. The device driver should create a /proc file for each of the input modules: liftacmains, liftmotorcontroller, liftslowspeed, lifthighspeed, liftoperatorswitchbase, and liftoperatorswitchtop. Reading a specific file should return the status of an input module. For example, this returns either 1 or 0:

     cat /proc/trailblazer/liftacmains 

    Notice that there is no bit manipulation and that the device driver provides actual named files that correspond to the physical world.

These requirements should simplify system integration using bash scripts. Scripts should work with named lift monitoring and snow-making files in the /proc directory. This device driver overcomes the limitations of port I/O and ppdev by automatically enabling the OUTPUT_ENABLE signal and maintaining the latch output value internally. This approach is more robust and less prone to errors. Code can be added to helloworld_proc_module.c to implement these liftmon_snowcon requirements.

Enhancements to helloworld_proc_module to Create liftmon_snowcon

The liftmon_snowcon module has module_init, module_exit, proc_read, and proc_write routines, just like helloworld_proc_module. The liftmon_snowcon init code doesn't create /proc entries in the /proc directory. Rather, it first creates the directory /proc/trailblazer. Then it creates all the liftmon_snowcon entries snowwatervalve1, snowwatervalve2, liftacmains, liftmotorcontroller, and so on in the directory /proc/trailblazer. The init function then fills each of the proc file's data, read_proc, write_proc, and owner fields. init then writes 0 to the latch. This turns off all the output modules. init then asserts the OUTPUT_ENABLE signal. init completes by writing a message to the system log.


You should separate your /proc file entries from other system entries by making a directory within the /proc directory, using the proc_mkdir function. This makes it easy to identify your project's /proc files.

Notice that in Listing 7.5 there isn't separate proc_read and proc_write functions for each /proc file. The snow-making control files share the same write_proc routine, proc_write_snowcondata, and share the same read_proc routine, proc_read_snowcondata. The data structure liftmon_snowcon_data_t contains a bitmask to distinguish one proc file from another. The bitmask matches up with the hardware bit that is used to control the output port. For example, the snowwatervalve3 proc file's data field contains a pointer to snowwatervalve3_data. snowwatervalve3_data.mask = SNOWWATERVALVE3, which equals 0x04. 0x04 corresponds to D3, which controls the third output module (Water Valve 3). Similarly, the liftmon proc files share the same proc_read function and use data.mask to distinguish one from another.

The module_exit routine, cleanup_liftmon_snowcon, latches a 0, disables the latch, removes the proc file entries and the /proc/trailblazer directory, and completes by writing a message to the system log file. The liftmon_snowcon code is shown in Listing 7.5.

Listing 7.5 The liftmon_snowcon.c Device Driver
 /*  * liftmon_snowcon v1.0 9/26/01  *  *  * The original location of this code is  *  *  * Copyright (C) 2001 by Craig Hollabaugh  *  * This program is free software; you can redistribute it and/or modify  * it under the terms of the GNU Library General Public License as  * published by the Free Software Foundation; either version 2 of the  * License, or (at your option) any later version.  *  * This program is distributed in the hope that it will be useful, but  * WITHOUT ANY WARRANTY; without even the implied warranty of  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  * Library General Public License for more details.  *  * You should have received a copy of the GNU Library General Public  * License along with this program; if not, write to the  * Free Software Foundation, Inc.,  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA  */ /*  * liftmon_snowcon.c is based on procfs_example.c by Erik Mouw.  * For more information, please see The Linux Kernel Procfs Guide,  *  */ /* liftmon_snowcon  * liftmon_snowcon uses inb and outp port I/O system calls to control  * an interface circuit connected the PC parallel printer port. The port's  * control port drives the interface circuit's output latch signals and  * input buffer. This module performs all bit operations for the data bus.  * Bash script need only read and write to /proc entry files to determine  * status or control equipment. In addition, the module's init code asserts  * the OUTPUT_ENABLE signal and its exit code deasserts the OUTPUT_ENABLE  * signal.  *  * This module creates these /proc entries:  * Trailblazer directory  /proc/trailblazer  * Lift Monitoring  *  AC Mains              /proc/trailblazer/liftacmains  *  Motor Controller      /proc/trailblazer/liftmotorcontroller  *  Low Speed Operation   /proc/trailblazer/liftslowspeed  *  High Speed Operation  /proc/trailblazer/lifthighspeed  *  Operator Switch Base  /proc/trailblazer/liftoperatorswitchbase  *  Operator Switch Top   /proc/trailblazer/liftoperatorswitchtop  * Snow-Making Control  *  Water Value 1         /proc/trailblazer/snowwatervalve1  *  Water Value 2         /proc/trailblazer/snowwatervalve2  *  Water Value 3         /proc/trailblazer/snowwatervalve3  *  Heater                /proc/trailblazer/snowheater1  */ /* gcc -O2 -D__KERNEL__ -DMODULE -I/usr/src/linux/include \     -c liftmon_snowcon.c -o liftmon_snowcon.o */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/sched.h> #include <asm/uaccess.h> #include <asm/io.h> #define MODULE_VERSION "1.0" #define MODULE_NAME    "liftmon_snowcon" /* Standard Parallel Port (SPP) definitions */ #define SPPDATAPORT     0x378 #define SPPSTATUSPORT  (SPPDATAPORT + 1) #define SPPCONTROLPORT (SPPDATAPORT + 2) /* SPP control port bit definitions */ #define OUTPUTENABLE           0x02 #define OUTPUTLATCH            0x04 #define INPUTENABLE            0x08 #define SPPPORTREAD            0x20 /* SPP input bit definitions */ #define LIFTACMAINS            0x01 #define LIFTMOTORCONTROLLER    0x02 #define LIFTSLOWSPEED          0x04 #define LIFTHIGHSPEED          0x08 #define LIFTOPERATORSWITCHBASE 0x10 #define LIFTOPERATORSWITCHTOP  0x20 /* SPP output bit definitions */ #define SNOWWATERVALVE1        0x01 #define SNOWWATERVALVE2        0x02 #define SNOWWATERVALVE3        0x04 #define SNOWHEATER1            0x08 /* define a bitmask, each *_file uses this to determine who it is */ struct liftmon_snowcon_data_t {         unsigned char mask; }; /* snowcondata is the output latch value stored internally. Control    changes made by user scripts writing to /proc/trailblazer entries    result in bits being either cleared or set in snowcondata. We    write snowcondata to the output latch every time a control change    occurs */ unsigned char snowcondata; /* this are the data structures that hold the mask. When a /proc    file is read or written to, the read_proc or write_proc routine    receives a pointer to this structure */ struct liftmon_snowcon_data_t liftacmains_data,                               liftmotorcontroller_data,                               liftslowspeed_data,                               lifthighspeed_data,                               liftoperatorswitchbase_data,                               liftoperatorswitchtop_data,                               snowwatervalve1_data,                               snowwatervalve2_data,                               snowwatervalve3_data,                               snowheater1_data; /* These are the pointers to the /proc directory entries */ static struct proc_dir_entry  *tb_dir,                               *liftacmains_file,                               *liftmotorcontroller_file,                               *liftslowspeed_file,                               *lifthighspeed_file,                               *liftoperatorswitchbase_file,                               *liftoperatorswitchtop_file,                               *snowwatervalve1_file,                               *snowwatervalve2_file,                               *snowwatervalve3_file,                               *snowheater1_file; /* proc_read - proc_read_liftmon  * proc_read_liftmon is the callback function that the kernel calls when  * there's a read file operation on these /proc/trailblazer files:  * liftacmains, lifthighspeed, liftmotorcontroller, liftoperatorswitchbase  * liftoperatorswitchtop, and liftslowspeed. The file's data pointer is  * passed in the data parameter. You first cast it to the  * liftmon_snowcon_data_t structure. The input module rack values are  * read by configuring SPP data for input and asserting the input buffer.  * This places the state of the input modules on the SPP data port. Using  * inb, the bit values are read then anded with the bitmask value to  * to determine if the particular input module is on or off. Which  * particular input module is defined by which /proc/trailblazer/ file  * is read.  */ static int proc_read_liftmon(char *page, char **start, off_t off, int count,                              int *eof, void *data) {   unsigned char v;   struct liftmon_snowcon_data_t *liftmon_snowcon_data =                                  (struct liftmon_snowcon_data_t *)data;   outb(OUTPUTENABLE, SPPCONTROLPORT); /* this asserts three items.  * 1. SSPPORTREAD, this configures the bidirectional data port as input  * 2. INPUTENABLE, this enables the input buffer to drive the data bus  * 3. OUTPUTENABLE, enable the output latch, driving the output rack  *                  if you don't assert this, the output modules will  *                  turn off  */   outb(SPPPORTREAD | INPUTENABLE  | OUTPUTENABLE, SPPCONTROLPORT); /* The input buffer is now driving the bus, so do a read */   v = inb(SPPDATAPORT); /* Deassert SPPORTREAD and INPUTENABLE.  * Use OUTPUTENABLE to keep output latch enabled  */   outb(OUTPUTENABLE, SPPCONTROLPORT); /* mask the input value based on the mask. Each mask is different depending  * which /proc/trailblazer file was read.  * Electrical note: returning an inverted value because AC power to an input  * module pulls outputs a low and the input buffer, 74244, doesn't invert  */   if (v & liftmon_snowcon_data->mask)     page[0] = '0';   else     page[0] = '1'; /* return 1 which is the length of page */   return 1; } /* proc_write - proc_write_snowcondata  * proc_write_snowcondata is the callback function that the kernel calls  * when there's a write file operation on these /proc/trailblazer files:  * snowheater1, snowwatervalve1, snowwatervalve2 and snowwatervalve3.  * The file's data pointer is passed in the data parameter. You first  * cast it to the liftmon_snowcon_data_t structure. The buffer parameter  * points to the incoming data. If the incoming data is a 1 or a 0,  * a bit in snowcondata is set or cleared. Which bit is defined by which  * /proc/trailblazer file is written to. snowcondata is then written to  * the output latch.  */ static int proc_write_snowcondata(struct file *file, const char *buffer,                                   unsigned long count, void *data) {   struct liftmon_snowcon_data_t *liftmon_snowcon_data =                                  (struct liftmon_snowcon_data_t *)data; /* check if the user wrote a 1 or a 0 the /proc/trailblazer file.    if so, set or clear a bit in snowcondata */   if (buffer[0] == '1')     snowcondata |= liftmon_snowcon_data->mask;   if (buffer[0] == '0')     snowcondata &= ~liftmon_snowcon_data->mask; /* Use OUTPUTENABLE to keep output latch enabled */   outb(OUTPUTENABLE, SPPCONTROLPORT); /* put snowcondata on the data bus */   outb(snowcondata , SPPDATAPORT); /* assert OUTPUTLATCH, this latches the data bus to the latch's  * outputs, driving the output module rack */   outb(OUTPUTENABLE | OUTPUTLATCH, SPPCONTROLPORT); /* Use OUTPUTENABLE to keep output latch enabled */   outb(OUTPUTENABLE,SPPCONTROLPORT);   return 1; } /* proc_read - proc_read_snowcondata  * proc_read_snowcondata is the callback function that the kernel calls  * when there's a read file operation on these /proc/trailblazer files:  * snowheater1, snowwatervalve1, snowwatervalve2 and snowwatervalve3.  * The file's data pointer is passed in the data parameter. You first  * cast it to the liftmon_snowcon_data_t structure.  Use snowcondata  * anded with the bitmask value to determine if the particular output  * module is on or off. Which particular output module is defined by  * which /proc/trailblazer/ file is read.  */ static int proc_read_snowcondata(char *page, char **start, off_t off,                                  int count, int *eof, void *data) {   struct liftmon_snowcon_data_t *liftmon_snowcon_data =                                 (struct liftmon_snowcon_data_t *)data; /* mask the snowcondata value based on the mask. Each mask is different  * depending which /proc/trailblazer file was read. */   if ( snowcondata & liftmon_snowcon_data->mask )     page[0] = '1';   else     page[0] = '0'; /* return the length */   return 1; } /* init - init_liftmon_snowcon  * init_liftmon_snowcon creates the /proc entry files and obtains  * their pointers. For each file, the fields, data, read_proc,  * write_proc and owner, are filled.  init_liftmon_snowcon  * initializes the output modules in the off state then  * complete by writing an entry to the system log using printk.  */ static int __init init_liftmon_snowcon(void) {   int rv = 0; /* Create the trailblazer /proc entry */   tb_dir = proc_mkdir("trailblazer", NULL);   if(tb_dir == NULL) {     rv = -ENOMEM;     goto out;   }   tb_dir->owner = THIS_MODULE; /* Create liftacmains and make it readable by all - 0444 */   liftacmains_file = create_proc_entry("liftacmains", 0444, tb_dir);   if(liftacmains_file == NULL) {     rv = -ENOMEM;     goto no_liftacmains;   }   liftacmains_data.mask = LIFTACMAINS;   liftacmains_file->data = &liftacmains_data;   liftacmains_file->read_proc = &proc_read_liftmon;   liftacmains_file->write_proc = NULL;   liftacmains_file->owner = THIS_MODULE; /* Create liftmotorcontroller and make it readable by all - 0444 */   liftmotorcontroller_file = create_proc_entry("liftmotorcontroller",                                                 0444, tb_dir);   if(liftmotorcontroller_file == NULL) {     rv = -ENOMEM;     goto no_liftmotorcontroller;   }   liftmotorcontroller_data.mask = LIFTMOTORCONTROLLER;   liftmotorcontroller_file->data = &liftmotorcontroller_data;   liftmotorcontroller_file->read_proc = &proc_read_liftmon;   liftmotorcontroller_file->write_proc = NULL;   liftmotorcontroller_file->owner = THIS_MODULE; /* Create liftslowspeed and make it readable by all - 0444 */   liftslowspeed_file = create_proc_entry("liftslowspeed", 0444, tb_dir);   if(liftslowspeed_file == NULL) {     rv = -ENOMEM;     goto no_liftslowspeed;   }   liftslowspeed_data.mask = LIFTSLOWSPEED;   liftslowspeed_file->data = &liftslowspeed_data;   liftslowspeed_file->read_proc = &proc_read_liftmon;   liftslowspeed_file->write_proc = NULL;   liftslowspeed_file->owner = THIS_MODULE; /* Create lifthighspeed and make it readable by all - 0444 */   lifthighspeed_file = create_proc_entry("lifthighspeed", 0444, tb_dir);   if(lifthighspeed_file == NULL) {     rv = -ENOMEM;     goto no_lifthighspeed;   }   lifthighspeed_data.mask = LIFTHIGHSPEED;   lifthighspeed_file->data = &lifthighspeed_data;   lifthighspeed_file->read_proc = &proc_read_liftmon;   lifthighspeed_file->write_proc = NULL;   lifthighspeed_file->owner = THIS_MODULE; /* Create liftoperatorswitchbase and make it readable by all - 0444 */   liftoperatorswitchbase_file = create_proc_entry("liftoperatorswitchbase",                                                    0444, tb_dir);   if(liftoperatorswitchbase_file == NULL) {     rv = -ENOMEM;     goto no_liftoperatorswitchbase;   }   liftoperatorswitchbase_data.mask = LIFTOPERATORSWITCHBASE;   liftoperatorswitchbase_file->data = &liftoperatorswitchbase_data;   liftoperatorswitchbase_file->read_proc = &proc_read_liftmon;   liftoperatorswitchbase_file->write_proc = NULL;   liftoperatorswitchbase_file->owner = THIS_MODULE; /* Create liftoperatorswitchtop and make it readable by all - 0444 */   liftoperatorswitchtop_file = create_proc_entry("liftoperatorswitchtop",                                                   0444, tb_dir);   if(liftoperatorswitchtop_file == NULL) {     rv = -ENOMEM;     goto no_liftoperatorswitchtop;   }   liftoperatorswitchtop_data.mask = LIFTOPERATORSWITCHTOP;   liftoperatorswitchtop_file->data = &liftoperatorswitchtop_data;   liftoperatorswitchtop_file->read_proc = &proc_read_liftmon;   liftoperatorswitchtop_file->write_proc = NULL;   liftoperatorswitchtop_file->owner = THIS_MODULE; /* Create snowwatervalve1 and make it root writable, readable by all-0644 */   snowwatervalve1_file = create_proc_entry("snowwatervalve1", 0644, tb_dir);   if(snowwatervalve1_file == NULL) {     rv = -ENOMEM;     goto no_snowwatervalve1;   }   snowwatervalve1_data.mask = SNOWWATERVALVE1;   snowwatervalve1_file->data = &snowwatervalve1_data;   snowwatervalve1_file->read_proc = &proc_read_snowcondata;   snowwatervalve1_file->write_proc = &proc_write_snowcondata;   snowwatervalve1_file->owner = THIS_MODULE; /* Create snowwatervalve2 and make it root writable, readable by all-0644 */   snowwatervalve2_file = create_proc_entry("snowwatervalve2", 0644, tb_dir);   if(snowwatervalve2_file == NULL) {     rv = -ENOMEM;     goto no_snowwatervalve2;   }   snowwatervalve2_data.mask = SNOWWATERVALVE2;   snowwatervalve2_file->data = &snowwatervalve2_data;   snowwatervalve2_file->read_proc = &proc_read_snowcondata;   snowwatervalve2_file->write_proc = &proc_write_snowcondata;   snowwatervalve2_file->owner = THIS_MODULE; /* Create snowwatervalve3 and make it root writable, readable by all-0644 */   snowwatervalve3_file = create_proc_entry("snowwatervalve3", 0644, tb_dir);   if(snowwatervalve3_file == NULL) {     rv = -ENOMEM;     goto no_snowwatervalve3;   }   snowwatervalve3_data.mask = SNOWWATERVALVE3;   snowwatervalve3_file->data = &snowwatervalve3_data;   snowwatervalve3_file->read_proc = &proc_read_snowcondata;   snowwatervalve3_file->write_proc = &proc_write_snowcondata;   snowwatervalve3_file->owner = THIS_MODULE; /* Create snowheater1 and make it root writable, readable by all-0644 */   snowheater1_file = create_proc_entry("snowheater1", 0644, tb_dir);   if(snowheater1_file == NULL) {     rv = -ENOMEM;     goto no_snowheater1;   }   snowheater1_data.mask = SNOWHEATER1;   snowheater1_file->data = &snowheater1_data;   snowheater1_file->read_proc = &proc_read_snowcondata;   snowheater1_file->write_proc = &proc_write_snowcondata;   snowheater1_file->owner = THIS_MODULE; /* initialize snowcondata to 0, all output modules off */   snowcondata = 0; /* initialize the control port to know value 0 */   outb(0, SPPCONTROLPORT); /* put snowcondata on the data bus */   outb(snowcondata, SPPDATAPORT); /* latch it first before we turn on the output modules */   outb(OUTPUTLATCH, SPPCONTROLPORT); /* turn on the latch output to drive the output modules */   outb(OUTPUTENABLE,SPPCONTROLPORT); /* everything initialed */   printk(KERN_INFO "%s %s initialized\n", MODULE_NAME, MODULE_VERSION);   return 0; /* this removes /proc entries if we have an error along the way */ no_snowheater1:   remove_proc_entry("snowheater1", tb_dir); no_snowwatervalve3:   remove_proc_entry("snowwatervalve3", tb_dir); no_snowwatervalve2:   remove_proc_entry("snowwatervalve2", tb_dir); no_snowwatervalve1:   remove_proc_entry("snowwatervalve1", tb_dir); no_liftoperatorswitchtop:   remove_proc_entry("liftoperatorswitchtop", tb_dir); no_liftoperatorswitchbase:   remove_proc_entry("liftoperatorswitchbase", tb_dir); no_lifthighspeed:   remove_proc_entry("lifthighspeed", tb_dir); no_liftslowspeed:   remove_proc_entry("liftslowspeed", tb_dir); no_liftmotorcontroller:   remove_proc_entry("liftmotorcontroller", tb_dir); no_liftacmains:   remove_proc_entry("liftacmains", tb_dir); out:         return rv; } /* exit - cleanup_liftmon_snowcon  * cleanup_liftmon_snowcon turns off the output modules and  * deasserts the OUTPUT_ENABLE signal. It removes the /proc entry files  * prints a message to the system log.  */ static void __exit cleanup_liftmon_snowcon(void) { /* this turns off all the output modules */   outb(0, SPPCONTROLPORT);   outb(0, SPPDATAPORT);   outb(OUTPUTLATCH, SPPCONTROLPORT);   outb(0,SPPCONTROLPORT); /* removing the /proc entries */   remove_proc_entry("liftacmains", tb_dir);   remove_proc_entry("liftmotorcontroller", tb_dir);   remove_proc_entry("liftslowspeed", tb_dir);   remove_proc_entry("lifthighspeed", tb_dir);   remove_proc_entry("liftoperatorswitchbase", tb_dir);   remove_proc_entry("liftoperatorswitchtop", tb_dir);   remove_proc_entry("snowwatervalve1", tb_dir);   remove_proc_entry("snowwatervalve2", tb_dir);   remove_proc_entry("snowwatervalve3", tb_dir);   remove_proc_entry("snowheater1", tb_dir);   remove_proc_entry("trailblazer", NULL); /* we're done */   printk(KERN_INFO "%s %s removed\n", MODULE_NAME, MODULE_VERSION); } module_init(init_liftmon_snowcon); module_exit(cleanup_liftmon_snowcon); MODULE_AUTHOR("Craig Hollabaugh"); MODULE_DESCRIPTION("Trailblazer Lift Monitor and Snow-making Control"); EXPORT_NO_SYMBOLS; 

Compiling, Inserting, and Testing liftmon_snowcon on the MZ104

When it is inserted into the kernel, liftmon_snowcon creates the /proc/trailblazer directory and lift-monitoring and snow-making control entries. bash scripts can read from and write to these entries. Here are the steps to compile the liftmon_snowcon module, using tbdev1, and then insert and test the operation of liftmon_snowcon, using tbdevmz, the MZ104:

  1. Compile liftmon_snowcon by using this command:

     root@tbdev1[528]: gcc -O2 -D__KERNEL__ -DMODULE -I/usr/src/linux/include  graphics/ccc.gif-c liftmon_snowcon.c -o /tftpboot/i386-rootfs/liftmon_snowcon.o root@tbdev1[529]: ls -sh /tftpboot/i386-rootfs/liftmon_snowcon.o 8.0k /tftpboot/i386-rootfs/liftmon_snowcon.o 
  2. Boot tbdevmz and gain access to it by using its console. Here's the tbdevmz prompt:

  3. Check for the liftmon_snowcon object file and what modules are loaded:

     bash-2.04# ls / bin   etc                lost+found  tmp boot  lib                proc        usr dev   liftmon_snowcon.o  sbin bash-2.04# cat /proc/modules bash-2.04# 
  4. Insert liftmon_snowcon.o, list the current modules, and then check the /proc directory for a trailblazer directory:

     bash-2.04# insmod liftmon_snowcon.o liftmon_snowcon 1.0 initialized bash-2.04# cat /proc/modules liftmon_snowcon         2106   0 (unused) bash-2.04# ls /proc 1       devices         kcore           pci 14      dma             kmsg            self 2       driver          ksyms           slabinfo 28      execdomains     loadavg         stat 3       filesystems     locks           swaps 4       fs              meminfo         sys 5       ide             misc            sysvipc 6       interrupts      modules         trailblazer bus     iomem           mounts          tty cmdline ioports         net             uptime cpuinfo irq             partitions      version 
  5. Change to the /proc/trailblazer directory and look for the liftmon_snowcon entries:

     bash-2.04# cd /proc/trailblazer/ bash-2.04# ls liftacmains             liftslowspeed lifthighspeed           snowheater1 liftmotorcontroller     snowwatervalve1 liftoperatorswitchbase  snowwatervalve2 liftoperatorswitchtop   snowwatervalve3 

    You have six lift monitoring inputs and four snow-making control outputs.

  6. Connect a voltmeter to the ground and to the parallel port control linefeed signal, pin 14, which is the OUTPUT_ENABLE signal. The voltage should read less than +100mV (this is asserted low). init_liftmon_snowcon asserts the OUTPUT_ENABLE signal.

  7. Turn on the Heater 1 output module:

     bash-2.04# echo 1 > snowheater1 

    The data port changes to 0x08, the OUTPUT_LATCH signal toggles, and the latch drives the output module board with 0xF7. The latch inverts 0x08 to get 0xF7. The Heater 1 output module turns on, as well. This verifies the correct operation of the snow-making control outputs. You can check the control outputs snowwatervalve1, snowwatervalve2, and snowwatervalve3 by echoing a 1 to them.

  8. Check a lift-monitoring input:

     bash-2.04# cat liftacmains 0 bash-2.04# 

    0 means there's no alternating current (AC) applied to the AC Mains input module. Apply AC power to that input module and check again:

     bash-2.04# cat liftoperatorswitchbase 1 bash-2.04# 

    The monitoring of the AC Mains input modules functions correctly. You can verify the correct operation of the remaining lift monitoring inputs.

  9. Remove the module:

     bash-2.04# rmmod liftmon_snowcon liftmon_snowcon: Device or resource busy 

    The device is busy because you are currently in the /proc/trailblazer directory.


    When you are in the /proc/trailblazer directory, its in-use counter increases by 1. You can read this counter by using the command cat /proc/modules. Modules that are in use cannot be removed from the kernel.

  10. Change into another directory, remove the module, and check the /proc/modules file:

     bash-2.04# cd / bash-2.04# rmmod liftmon_snowcon liftmon_snowcon 1.0 removed bash-2.04# cat /proc/modules bash-2.04# bash-2.04# ls /proc 1      cmdline       interrupts    meminfo       stat 14     cpuinfo       iomem         misc          swaps 2      devices       ioports       modules       sys 21     dma           irq           mounts        sysvipc 3      driver        kcore         net           tty 4      execdomains   kmsg          partitions    uptime 5      filesystems   ksyms         pci           version 6      fs            loadavg       self bus    ide           locks         slabinfo 

The heater output module goes off. If you check the OUTPUT_ENABLE signal, you will see that it is not asserted (greater than +3V), so the latch outputs are disabled and the output modules are also off. This result shows that the cleanup_liftmon_snowcon code functions correctly.

When it is loaded, this device driver asserts OUTPUT_ENABLE. It shields software developers from interface logic specifics. It provides bash script access to individual lift monitoring and snow-making equipment through a /proc file interface. Use of this device driver eases system integration using bash scripts.


    Embedded LinuxR. Hardware, Software, and Interfacing
    Embedded LinuxR. Hardware, Software, and Interfacing
    ISBN: N/A
    EAN: N/A
    Year: 2001
    Pages: 103 © 2008-2017.
    If you may any questions please contact us: