Reverse Engineering a Samsung Scanner Button, page 7

Pages: 1 2 3 4 5 6 7 8

Step 7: Write the code, part1

To recap what we need to do, let's look at the request and response and from them, derive the endpoint that we must send our command to, the command and the buffer size.

ffff88007a52b9c03115373453 S Ci:1:003:0 s c1 9a 0000 0100 0008 8 <
ffff88007a52b9c03115373605 C Ci:1:003:0 0 8 = 1b9a0100 00000000

The command is a submission 'S' , and it goes to device 3 on bus 1, endpoint 0. It's URB status is 's' so it is a setup URB.

The command itself is: 'c1 9a 0000 0100' , and it is sending an 8 byte (or 8 character) buffer '0008 8' along with the command.

The device sends a callback 'C' , with an URB status of '0' (acknowledged) and it returns the 8 byte buffer that was sent with an 'answer' inside of it. The answer of interest is of course '1b 9a 01 00 00 00 00 00'.

The response that will be returned in our buffer, and that our code must act upon will end up in an integer array:

1b = 27
9a = 154
01 = 01

and the other four bytes are all zeros: 00 00 00 00 00

The reason that we will be dealing with integer values instead of the original hexadecimal values is because libusb 1.0 requires this.

I am extremely greatful to the people who produced libusb 1.0. Without it, this could have been a nightmare.

We are approaching the finish line and now it's time to construct our code. Here is the first of two pieces of code (sbuttond.c). Keep in mind that this is all written in C and it is procedural. It is a rather short piece of code.

I build this at the command line and it is included as a comment in the code:

g++ -g -Wall sbuttond.c -o sbuttond -lusb-1.0



#include <iostream>
#include </usr/local/include/libusb-1.0/libusb.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <vector>
#include <errno.h>
#include <sstream>
#include <time.h>

using namespace std;

// globals
int debug = 1;
libusb_device **devs;             //pointer to pointer of device, used to retrieve a list of devices
libusb_device_handle *dev_handle; //a device handle
libusb_context *ctx = NULL;       //a libusb session

// BUILD COMMAND ***
// g++ -g -Wall sbuttond.c -o sbuttond -lusb-1.0

int initialize()
{
    if(libusb_init(&ctx) < 0)
    {
      if(debug == 1)
      {
         printf("\n");
         printf("Error code 2: could not initialize libusb object!!!\n");
      }
         return 2;
    }

    return 0;
}

int getDeviceList()
{
    ssize_t c;                               //number of devices in list

    libusb_set_debug(ctx, 3);                //set verbosity level to 3, as suggested in the documentation
    c = libusb_get_device_list(ctx, &devs);  //get the list of devices

    if(c < 0)
    {
       if(debug == 1) printf("Error code 3: could not get device list!!!\n");
       return 3;
    }	

    if(debug == 1)
    {
      for(int i=0; i < c; i++) // show the list of devices
      {
         libusb_device *device = devs[i];
         struct libusb_device_descriptor desc = {0};

         libusb_get_device_descriptor(device, &desc);
         printf("Device %d = %04x:%04x\n", i, desc.idVendor, desc.idProduct);
      }

      printf("\n");
    }    

    return 0;
}

int openDevice()
{
    // #################### CONNECTION HANDLE TO TARGET DEVICE SET HERE ######################
    dev_handle = libusb_open_device_with_vid_pid(ctx, 0x04e8, 0x344f);   //these are vendorID and productID

    if(dev_handle == NULL)
    {
        if(debug == 1) printf("Error code 4: could not open device!!!\n");
        return 4;
    }
    else
    {
        if(debug == 1) printf("Device opened.\n");
    }

    libusb_free_device_list(devs, 1);    
    return 0;
}

int detachKernel()
{
    // is the kernel driver attached?
    if(libusb_kernel_driver_active(dev_handle, 0) == 1)
    {
        if(debug == 1) printf("Kernel driver active\n");

        if(libusb_detach_kernel_driver(dev_handle, 0) == 1) // failed to detach it
        {
            if(debug == 1) printf("Error code 5: could not detach kernel driver!!!\n");
            return 5;
        }
        else
        {
            if(debug == 1) printf("Detached kernel driver\n");
        }
    }

    return 0;
}

int claimInterface()
{
    if(libusb_claim_interface(dev_handle, 0) < 0)
    {
        if(debug == 1) printf("Error code 6: could not claim interface!!!\n");
        return 6;
    }
    else
    {
        if(debug == 1) printf("Claimed Interface\n\n");
    }

    return 0;
}

int query()
{
    int scan = 0;
    int return_size = 8;
    unsigned char *buffer = new unsigned char[8]; // answer buffer

    /*
    ############# HERE IS THE QUERY THAT ASKS ABOUT THE STATUS OF THE BUTTON REGISTER ######################
    #                                                                                                      #
    # libusb_control_transfer(DEVICE-HANDLE, REQUEST-TYPE, REQUEST, VALUE, INDEX, BUFFER, LENGTH, TIMEOUT) #
    #                                                                                                      #
    # req type                                     req   val   index   buff    buff length                 #
    # propper URB structure to ask this question:  c1    9a    0000    0100    0008    8                   #
    #                                                                                                      #
    ########################################################################################################
    */
	
    int r = libusb_control_transfer(dev_handle, 0xc1, 0x9a, 0x00, 0x100, buffer, sizeof(buffer), 200);

    if(r!=8 && r!=0) // if we can't succeed with the control transfer to that endpoint
    {
        if(debug == 1) printf("Error code 7: could not read from the endpoint!!!");
        return 7;
    }
    else // process the buffer contents returned from the control transfer request to the device
    {
        if(debug == 1 )
        {
            for(int j=0;j < return_size;j++)
            {
                printf("buffer[%d] = 0x%d\n", j, buffer[j]);
                printf("\n");
            }
	
        }	
		
        /*
        ##########################################################
        #                                                        #
        # if the scan button was pressed, buffer[2] will equal 1 #
        # buffer[0] == 27 (0x1b)                                 #
        # buffer[1] == 154 (0x9a)                                #
        #                                                        #
        ##########################################################
        */
		
        if((unsigned)buffer[2]  == 01)
            scan=1;
        else
            scan = 0;

        if(debug == 1)
        {
            if(scan == 1) printf("Time to scan.\n" );
            else printf("Not time to scan.\n" );	
        }

        delete[] buffer;

    }// end buffer processing

    return scan;
}

void dispose()
{
    libusb_release_interface(dev_handle, 0); // release the claimed interface
    libusb_close(dev_handle);                // close the device we opened
    libusb_exit(ctx);                        // needs to be called to end
	
    if(debug==1) printf("Released Interface\n");
}

int main()
{
    int r = initialize();     // returns 0 on success
    if( r == 2) { return r; } // error code

    r = getDeviceList();
    if( r == 3) { return r; }

    r = openDevice();
    if( r == 4) { return r; }

    r = detachKernel();
    if( r == 5) { return r; }

    // from here on out we must call the dispose function
    r = claimInterface();
    if( r == 6)
    {
        dispose();
        return r;
    }   

    r = query();              // returns 0 for no scan, 1 for scan
    dispose();
    if( r == 7) { return r; } // error code

    if(r == 1) return 1;      // 1 = tell the calling script (sbuttond.sh) to scan       

    return 0;
}

Next page