Solved

Inb function causing segmentation error in C programming with linux

Posted on 2004-08-26
16
322 Views
Last Modified: 2012-08-13
this is the code segment, where i am getting segmentation error. I am trying to check the staus of all the pins and see where there is a high or a low

switch(pin_to_test)
   {
       case 1: //d0
                printf("case 1 reached\n");
           if (inb(0x378 & 0x01))
           {      printf("Pin %d is high\n", pin_to_test);    
               return( FALSE ); //It is a high
           }
         else
         { printf("Pin %d is low\n", pin_to_test);
          return( TRUE );//It is a low
           }
         break;
           
       case 2: //d1
           if (inb(0x378 & 0x02))
                      return( FALSE ); //It is a high
           else return( TRUE );//It is a low
           break;
  and so on        
}

I cant figure out where the problem is. Can you help me??
0
Comment
Question by:saumathur
  • 10
  • 5
16 Comments
 
LVL 5

Expert Comment

by:lemmeC
ID: 11901264
Replace (inb(0x378 & 0x01)) with (inb(0x378) & 0x01),
(inb(0x378 & 0x02)) with (inb(0x378) & 0x02),
and so on.
0
 
LVL 5

Expert Comment

by:lemmeC
ID: 11901317
Of course, I am guessing that you are testing each pin of the parallel printer port 0x378. Then the above solution will work.
(Replace (inb(0x378 & 0x01)) with (inb(0x378) & 0x01),  (inb(0x378 & 0x02)) with (inb(0x378) & 0x02), and so on.)

inb(0x378 & 0x01) would do a bitwise AND of the address 0x378 with 0x01 and then try to read from the ANDed address (which would not be a valid port address, giving rise to a segmentation violation by the inb command) , whereas what is required is to read from address 0x378 and do a bitwise AND of the read value with 0x01. This can be done as (inb(0x378) & 0x01).
The same holds for (inb(0x378) & 0x02), (inb(0x378) & 0x04), (inb(0x378) & 0x08), etc. which check the status of the second, third, fourth, etc. bits.
0
 

Author Comment

by:saumathur
ID: 11901420
I am still getting the error:

printf("inside test_low: THe pin testing at the moment is %d\n", pin_to_test);
   switch(pin_to_test)
   {
       case 1: //d0
                printf("case 1 reached\n");
           if (inb((0x378) & 0x01))
           {      printf("Pin %d is high\n", pin_to_test);    
               return( FALSE ); //It is a high
           }
         else
         { printf("Pin %d is low\n", pin_to_test);
          return( TRUE );//It is a low
           }
         break;
           
       case 2: //d1
           if (inb((0x378) & 0x02))
                      return( FALSE ); //It is a high
           else return( TRUE );//It is a low
           break;

the out put is :
inside test_low: THe pin testing at the moment is  1
case 1 reached
Segmentation fault

so its still not fixed!!! any thing else i can try?
0
 
LVL 5

Expert Comment

by:lemmeC
ID: 11901451
Try this:

printf("inside test_low: THe pin testing at the moment is %d\n", pin_to_test);
   switch(pin_to_test)
   {
       case 1: //d0
               printf("case 1 reached\n");
           if (inb(0x378) & 0x01)                      // <-- Note the syntax
           {     printf("Pin %d is high\n", pin_to_test);    
             return( FALSE ); //It is a high
           }
        else
        { printf("Pin %d is low\n", pin_to_test);
         return( TRUE );//It is a low
           }
        break;
           
       case 2: //d1
           if (inb(0x378) & 0x02)                       // <-- Note the syntax
                      return( FALSE ); //It is a high
           else return( TRUE );//It is a low
           break;

        //Other code
0
 
LVL 5

Expert Comment

by:lemmeC
ID: 11901479
>>so its still not fixed!!!

It didn't work because there is no difference between  inb(0x378 & 0x01)  and  inb((0x378) & 0x01). They both do exactly the same thing.
(inb(0x378) & 0x01)) should be used instead, as mentioned in the program segment above.
0
 

Author Comment

by:saumathur
ID: 11901535
Yes that worked. But my program, which is actually a parallel port pin tester for busy tones is not working properly.!!! I have made it as a state machine, and i cant get past the first state machine. It goes past the first pin, but doesnt go to do the next one. this is the code.  the output i get is that after it goes :

ending state 1, it exits the program and does not go to the second statemachine at all.!! i cant figure out why its doing that..!!! If you could help me, that would be reeeaaaalllly helpful
thanks


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>
#include <unistd.h>
#include <asm/io.h>

 //------------- state machine data and types. -------------------------------
typedef unsigned char bool ;
typedef unsigned char byte ;
#define TRUE  1
#define FALSE 0

#define MAX 10
#define MIN 5


typedef struct
  { byte current_state ;      // state must be this value for driver to
                              //   try the exit test function.
    bool (*exit_test_ptr)() ; // routine to execute, tests if this exit is
                              //   allowed.
    byte next_state ;         // state to adopt if exit allowed.
    void (*exit_action)() ;   // action to take if exit allowed.
  } Tstate_line ;
 
typedef struct
{
    int data_pin_no;
    void (*drive_state_one)(int p);
} Pin;    

int  state ;
int  num_state_entries ;
char char_to_test ;
char test_for_parameter_error;
int  num_before_first_edge ;
int  num_after_first_edge ;
int  num_after_second_edge ;
int  edge_counter;
int  sample_length;
int  pin_to_test;

char result[] = "00000000";

//===================== Test and Action routines ===========================
//
//  PURPOSE - this section contains two types of simple routines-
//             * test routines that only test things and return TRUE or FALSE.
//             * action routines that do a simple job.

void do_check()
{
    int sum_samples;
   
    switch (edge_counter)
    {
        case 0:
            if(num_before_first_edge > MAX)
            {
                result[pin_to_test] = '0';
            }
            if(sample_length == num_before_first_edge)
            {
                result[pin_to_test] = '0';
            }        
            break;
        case 1:
           
            if((num_before_first_edge >= MAX) && (num_after_first_edge >= MAX))
            {
                result[pin_to_test] = '0';
            }    
           
            if(num_after_first_edge > MAX )
             
            {
                result[pin_to_test] = '0';
            }
            if(sample_length == num_before_first_edge + num_after_first_edge)
            {
              result[pin_to_test] = '0';
          }
            break;
        case 2:
           
            if((num_after_first_edge >= MAX) && (num_after_second_edge >= MAX))
            {
                result[pin_to_test] = '0';
          }  
             
            if(
              (num_before_first_edge > (num_after_first_edge + 1)) ||
              (num_after_second_edge > MAX)                        ||
              (num_after_first_edge < MIN)                         ||
              (num_after_second_edge > (num_after_first_edge + 1))
              )
            {
              result[pin_to_test] = '0';
          }
            if(sample_length == num_before_first_edge + num_after_first_edge + num_after_second_edge)
            {
              result[pin_to_test] = '0';
          }    
            break;
        case 3:
           
            if( (num_before_first_edge - num_after_second_edge) > 1)
            {
               result[pin_to_test] = '0';
          }
            if((num_after_first_edge <= MIN) && (num_after_second_edge <= MIN))
            {
                result[pin_to_test] = '0';
          }  
            if(
               (abs(num_after_first_edge - num_after_second_edge) > 1 ) ||
               (num_after_second_edge < MIN)                        
              )
            {
               result[pin_to_test] = '0';
          }
            if(
              (num_after_first_edge <= MAX)&&
              (num_after_second_edge <= MAX)&&
              (num_after_first_edge >= MIN)&&
              (num_after_second_edge >= MIN)&&
              (num_before_first_edge <= MAX )&&
              ((num_before_first_edge <= (num_after_first_edge + 1)))&&
              ((num_before_first_edge <= (num_after_second_edge + 1)))&&
              ((num_after_first_edge <= (num_after_second_edge + 1)))&&
              ((num_after_first_edge >= (num_after_second_edge - 1)))
              )
              {                
      
             result[pin_to_test] = '1';
       
              }
              else
              {
                 result[pin_to_test] = '0';
            }  
            break;
        default:
            break;
           
    }
       
}    
void do_blank()
{
}

void do_incr_sample()
 {
    if(edge_counter == 0)
    {
     num_before_first_edge = num_before_first_edge + 1;  
    }
    if(edge_counter == 1)
    {
     
      num_after_first_edge = num_after_first_edge + 1;  
    }
    if(edge_counter == 2)
    {
   
      num_after_second_edge = num_after_second_edge + 1;  
    }  
    do_check();  
    if(edge_counter == 3)
    {
        result[pin_to_test] = '0';
       
    }
    if(edge_counter > 3)
    {
       
        result[pin_to_test] = '0';
      //exit(0);
    }
   
 }

void do_incr_edge()
 {
    edge_counter = edge_counter + 1;
    if(edge_counter == 1)
    {
      num_after_first_edge = num_after_first_edge + 1;  
    }
    if(edge_counter == 2)
    {
      num_after_second_edge = num_after_second_edge + 1;  
    }
    do_check();  
    if(edge_counter == 3)
    {      
        result[pin_to_test] = '0';
      
    }
    if(edge_counter > 3)
    {
       result[pin_to_test] = '0';
       
    }
   
             
   
 }

bool test_low()
 { printf("inside test_low: THe pin testing at the moment is %d\n", pin_to_test);
   switch(pin_to_test)
   {
       case 1: //d0
                printf("case 1 reached\n");
         if (inb(0x378) & 0x01)
           {      printf("Pin %d is high\n", pin_to_test);    
               return( FALSE ); //It is a high
           }
         else
         { printf("Pin %d is low\n", pin_to_test);
          return( TRUE );//It is a low
           }
         break;
           
       case 2: //d1
           if (inb(0x378) & 0x02)
                      return( FALSE ); //It is a high
           else return( TRUE );//It is a low
           break;
           
       case 3: //d2
           if (inb(0x378) & 0x04)
                      return( FALSE ); //It is a high
           else return( TRUE );//It is a low
           break;
           
       case 4: //d3
           if (inb(0x378) & 0x08)
                      return( FALSE ); //It is a high
           else return( TRUE );//It is a low//It is a low
           break;
           
       case 5: //d4
           if (inb(0x378) & 0x10)
                      return( FALSE ); //It is a high
           else return( TRUE );//It is a low
           break;
           
       case 6: //d5
           if (inb(0x378) & 0x20)
                      return( FALSE ); //It is a high
           else return( TRUE );//It is a low
           break;
           
       case 7: //d6
           if (inb(0x378) & 0x40)
                     return( FALSE ); //It is a high
           else return( TRUE );//It is a low
           break;
           
       case 8: //d7
           if (inb(0x378) & 0x80)
                      return( FALSE ); //It is a high
           else return( TRUE );//It is a low
           break;
   }    
 }

bool test_high()
 {
   printf("inside test_high: THe pin testing at the moment is %d\n", pin_to_test);
   switch(pin_to_test)
   {
          case 1: //d0
             printf("Checkin pin 1\n");
           if (inb(0x378) & 0x01)
                      return( TRUE ); //It is a high
           else return( FALSE );//It is a low
           break;
           
       case 2: //d1
           if (inb(0x378) & 0x02)
                      return( TRUE ); //It is a high
           else return( FALSE );//It is a low
           break;
           
       case 3: //d2
           if (inb(0x378) & 0x04)
                      return( TRUE ); //It is a high
           else return( FALSE );//It is a low
           break;
           
       case 4: //d3
           if (inb(0x378) & 0x08)
                      return( TRUE ); //It is a high
           else return( FALSE );//It is a low
           break;
           
       case 5: //d4
           if (inb(0x378) & 0x10)
                      return( TRUE ); //It is a high
           else return( FALSE );//It is a low
           break;
           
       case 6: //d5
           if (inb(0x378) & 0x20)
                      return( TRUE ); //It is a high
           else return( FALSE );//It is a low
           break;
           
       case 7: //d6
           if (inb(0x378) & 0x40)
                      return( TRUE ); //It is a high
           else return( FALSE );//It is a low
           break;
           
       case 8: //d7
           if (inb(0x378) & 0x80)
                      return( TRUE ); //It is a high
           else return( FALSE );//It is a low
           break;
   }
 }
       
bool test_true()
 { return( TRUE) ;
 }


//===================== state_table =========================================

//--- state names.  low=lower case, high=upper case.
#define start 0
#define low 1
#define high 2

   Tstate_line  state_table[] =
   {//current state   exit test           next state    exit action.
             
               start,   &test_low,             low,        &do_incr_sample
              ,start,   &test_high,            high,       &do_incr_sample
              ,start,   &test_true,            start,      &do_blank
              ,low,     &test_high,            high,       &do_incr_edge
              ,low,     &test_true,            low,        &do_incr_sample
              ,high,    &test_low,             low,        &do_incr_edge
              ,high,    &test_true,            high,       &do_incr_sample
   } ;

//========================= state_reset ====================================
//
//  PURPOSE - reset state machine.
//
void state_reset()
{ state = start ;
  num_state_entries = sizeof(state_table) / sizeof( Tstate_line) ;
  num_before_first_edge = 0;
  num_after_first_edge = 0;
  num_after_second_edge = 0 ;
  edge_counter = 0;
  sample_length = 0;
 
}

//========================== drive_one_step ==================================
//
//  PURPOSE : drive the state machine one step using a simple linear search of
//            the state table.  Faster methods include hashing and indexing.
//
void drive_one_step(int pin)
{//--- data inits.

   int index ;
   Tstate_line *state_line = &state_table[0] ;
   //char_to_test = ch ;
   pin_to_test = pin;
 //--- search through whole table.
   for( index = 0 ; index < num_state_entries ; index++)
    {//--- if the state_line state matches the current state,
     //      and the exit test is true ...
       if (   (   state_line->current_state == state )
           && ( (*state_line->exit_test_ptr)()       )
          )
         {//--- take the action and change the state.
            (*state_line->exit_action)() ;
            state = state_line->next_state ;
            break ; // quit searching through table as got a state change.
         } ;
      ++state_line ; //to next line.
     } ; //endfor.
}

int main(int argc, char *argv[])
{/*--- When no parameters MUST print id string in CSV format, no comma at the end.*/
   if (argc == 1)  // no parameters.
     { printf("2113232R, s2113232@student.rmit.edu.au, Saurabh Mathur\n") ;
       return(0) ;
     }  
   
 /*--- START YOUR CODE HERE.*/
   if (argc > 2)
   {
       printf("error\n");
       return(0);
   }
   
  //--- drive state machine
   state_reset() ;
   
   Pin one;
   Pin two;
   Pin three;
   Pin four;
   Pin five;
   Pin six;
   Pin seven;
   Pin eight;
   
   one.drive_state_one = drive_one_step;
     
   if (argv[1] = "run")
   {
         printf("starting\n");
        one.data_pin_no = 1;
         printf("%d\n", one.data_pin_no);
      two.data_pin_no = 2;
         three.data_pin_no = 3;
         four.data_pin_no = 4;
         five.data_pin_no = 5;
         six.data_pin_no = 6;
         seven.data_pin_no = 7;
         eight.data_pin_no = 8;
      printf("%d\n", eight.data_pin_no);
        
           (one.drive_state_one)(one.data_pin_no);
      printf("Ending first state machine\n");
         
      (two.drive_state_one)(two.data_pin_no);
         printf("Ending second state machine\n");
      
      (three.drive_state_one)(three.data_pin_no);
         printf("Ending third state machine\n");
      
      (four.drive_state_one)(four.data_pin_no);
         printf("Ending fourth state machine\n");
      
      (five.drive_state_one)(five.data_pin_no);
         printf("Ending fifth state machine\n");
      
      (six.drive_state_one)(six.data_pin_no);
         printf("Ending sixth state machine\n");
      
      (seven.drive_state_one)(seven.data_pin_no);
         printf("Ending seventh state machine\n");
      
      (eight.drive_state_one)(eight.data_pin_no);
      
      printf("%c\n", result);
      
         return(0);
   }
   
   else
           printf("error\n");
 
   return(0) ;
}
0
 
LVL 3

Expert Comment

by:passmark
ID: 11901645

LemmeC is correct. Well mostly.

But maybe you'll also some additional problems after fixing that particular problem. In general it is not safe to assume the printer will always be at the I/O address 0x378. It might be at another address on some machines, or if the user has played with the BIOS settings.

I am normally a windows programmer (so call me stupid if I have this wrong), but I would have thought you would need a separate Linux device driver installed into the kernel before you can do low level I/O like this. I would expect the inb instruction to always fail from application level code.

Which leads me to the conclusion that what your initial code was doing, inb (0x01), probably doesn't crash becuase of a bad address, but more likely crashes becuase Linux stops all applications using the inb instruction.

Both Windows and Linux provide virtual address space for applications and prevent them from direct hardware access. This is why you have the kernel and device drivers, to access the hardware for you. This helps to make the machine stable.

Back in the good old DOS days (and Windows 95) this was not a problem, you could just read a byte from the I/O address space directly. But we all know how stable DOS and W95 are :-)

So I am I a stupid Windows programmer or what?

David
0
 
LVL 5

Expert Comment

by:lemmeC
ID: 11901765
>> ending state 1, it exits the program and does not go to the second statemachine at all

Its hard to read through hundreds of lines of code.
Could you atleast give the debug log you are getting .i.e. the output of the printfs included in your program.
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 5

Accepted Solution

by:
lemmeC earned 500 total points
ID: 11901835
The function pointer for the Pin one is being set in the statement:
>> one.drive_state_one = drive_one_step;
The same thing has to be done for the other pins as well.

two.drive_state_one = drive_one_step;
three.drive_state_one = drive_one_step;
four.drive_state_one = drive_one_step;
five.drive_state_one = drive_one_step;
six.drive_state_one = drive_one_step;
seven.drive_state_one = drive_one_step;
eight.drive_state_one = drive_one_step;
0
 

Author Comment

by:saumathur
ID: 11902007
aa yeah..i did that, but its not going through all the states..!! it shud go thru test_low for all states, but its not..!!! its not printing that all the time!!!

sorry no debug log..its in gcc in linux
0
 
LVL 5

Expert Comment

by:lemmeC
ID: 11902053
>>its not printing that all the time!!!

Can you paste here the printed statements?
0
 

Author Comment

by:saumathur
ID: 11902156
inside test_low: the pin tesing at the moment is 1
case 1 reached
pin 1 is low
Endinf first state_machine
inside test_high: The pin testing at the moment is 2
checkin pin 2
ending second state machine
inside test_high: The pin testing at the moment is 3
checkin pin 3
ending third state machine
inside test_low: The pin testing at the moment is 4
checkin pin 4
ending fourth state machine
inside test_high: The pin testing at the moment is 5
checkin pin 5
ending fifth state machine
inside test_high: The pin testing at the moment is 6
checkin pin 6
ending sixth state machine
inside test_high: The pin testing at the moment is 7
checkin pin 7
ending seventh state machine
inside test_high: The pin testing at the moment is 8
checkin pin 8
ending eighth state machine
00000000
0
 
LVL 5

Expert Comment

by:lemmeC
ID: 11902443
Change this: printf("%c\n", result);
to this: printf("%s\n", result);

>> it shud go thru test_low for all states
Infact, it should not. If the current state is start or high, test_low is called. Otherwise test_high is called. Since the first pin is low, the state changes from start to low. Then test_high is called for pin 2, which is again low; thus calling test_high again for pin 3, and so on.
To confirm this, put printfs in all cases of test_high and test_low.
Your output seems to be correct.
0
 

Author Comment

by:saumathur
ID: 11902468
oh ok cool..>!!

how would one get a 50ms time delay with nanosleep???
specify the structs as tv_sec = 0; and tv_nanosec = 5000; ?
0
 
LVL 5

Expert Comment

by:lemmeC
ID: 11902601
tv_sec = 0;
tv_nanosec = 50000;  //Not 5000.


I am leaving now. I guess your problem has been solved. Bye.
0
 
LVL 5

Expert Comment

by:lemmeC
ID: 11962442
Saurabh,
        If your problem has been solved, please close this question.
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

This article is meant to give a basic understanding of how to use R Sweave as a way to merge LaTeX and R code seamlessly into one presentable document.
Entering a date in Microsoft Access can be tricky. A typo can cause month and day to be shuffled, entering the day only causes an error, as does entering, say, day 31 in June. This article shows how an inputmask supported by code can help the user a…
An introduction to basic programming syntax in Java by creating a simple program. Viewers can follow the tutorial as they create their first class in Java. Definitions and explanations about each element are given to help prepare viewers for future …
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now