Tuesday, September 27, 2011

Custom device driver in an RTOS (With Buffered I/O)


Driver functionalities

1. Driver initialization    
    Initialize the actual hardware device
    Initialize the internal data structres

2. Driver control
    Run-time control of hardware device
    e.g.: Change the baud rate of a serial device

3. Driver access
    In applications where multiple threads need simultaneous driver acces - use semaphore

4. Driver input/output
    How input/output is buffered and how threads wait on them

5. Driver interrupts
    Interrupts notify the driver of device input,output, control & error events.

6. Driver status
    Run time status & statistics associated with the drive operation.

7. Driver termination
    If the driver and/or the physical hardware device need to be shut down.


 
Example: Simple serial hardware device with a configuration register, and input register and an output register
Initialization
Two counting semaphores are used to manage the driver's input and output operation.
Input semaphore: Set by input ISR when a character is received by the serial hardware device
         Semaphore is created with an initial value of 0.
Output semaphore: Indicates availability of the serial hardware transmit register
          Semaphore is created with an initial value of 1 to indicate availability.

void sdriver_initialize(void)
{
    /* Initialize the two counting semaphores user to control the simple I/O */
    tx_semaphore_create(&sdriver_input_semaphore,"Sdriver Input Semaphore",0);
    tx_semaphore_create(&sdriver_output_semaphore,"Sdriver Output Semaphore",1);

    /* Setup interrupt vectors for input and output ISRs.
       The initial vector handling should call the ISRs
       defined in this file.*/

    /* Configure serial device hardware for RX/TX interrupt
       generation, baud reate, stop bits, etc. */
}

Simple driver input:
When a serial device interrupt is received, the input semaphore is set.
If one or more threads are waiting for a character from the driver, the
thread waiting the longest is resumed.
Limitations: Dropping input characters
Handled by: Add input character buffer

unsigned char sdriver_input(void)
{
    /*determine if there is a character waiting. If not, suspend */
    tx_semaphore_get(&sdriver_input_semaphore, TX_WAIT_FOREVER);
  
    /* Return character from serial RX hardware register */
    return(*serial_hardware_input_ptr);
}

void sdriver_input_isr(void)
{
    /* See if an input character notification is pending */
    if(!sdriver_input_semaphore.tx_semaphore_count)
    {
        /* If not, notify thread of an input character */
        tx_semaphore_put(&sdriver_input_semaphore);
    }
}

Simple driver output:
Output semaphore is used to signal when the serial device's transmit register is free.

void sdriver_output(unsigned char alpha)
{
    /* Determine if the hardware is ready to transmit a character.
       If not, suspend until the previous output completes. */
    tx_semaphore_get(&sdriver_output_semaphore, TX_WAIT_FOREVER);

    /* Send the character through the hardware */
    *serial_hardware_output_ptr = alpha;
}

void sdriver_output_isr(void)
{
    /* Notify thread last character transmit is complete */
    tx_semaphore_put(&sdriver_output_semaphore);
}

Shortcomings: Illustrates the basic idea of a simple driver.
          Doesn't address data buff
ering or any overhead issues.


 
Advanced driver issues:

1. Logic for Circular input buffer

unsigned char input_buffer[MAX_SIZE];
unsigned char *input_write_ptr;
unsigned char *input_read_ptr;

/* Initialization */
input_write_ptr =  &input_buffer[0];
input_read_ptr  =  &input_buffer[0];

/* Input byte ISR... alpha has character from device */
save_ptr = input_write_ptr;
*input_write_ptr++ = alpha;
if(input_write_ptr > &input_buffer[MAX_SIZE-1])
    input_write_ptr = &input_buffer[0]; /* Wrap */
if(input_write_ptr == input_read_ptr)
    input_write_ptr = save_ptr; /* Buffer full */

/* Retrieve input byte from the buffer */
if(input_read_ptr != input_write_ptr)
{
    alpha = *input_read_ptr++;
    if(input_read_ptr > &input_buffer[MAX_SIZE -1 ])
        input_read_ptr = &input_buffer[0];
}

2. Logic for Circular output buffer

unsigned char output_buffer[MAX_SIZE];
unsigned char *output_write_ptr;
unsinged char *output_read_ptr;

/* Initialization */
output_write_ptr = &output_buffer[0];
output_read_ptr  = &output_buffer[0];

/* Transmit complete ISR... Device ready to send */
if(output_read_ptr != output_write_ptr)
{
    *device_reg = *output_read_ptr++;
    if(output_read_ptr > &output_buffer[MAX_SIZE-1])
        output_read_ptr = &output_buffer[0];
}


/* Output drive buffer service. If device busy, buffer! */
save_ptr = output_write_ptr;
*output_write_ptr++ =  alpha;
if(output_write_ptr > &output_buffer[MAX_SIZE -1 ] )
    output_write_ptr = &output_buffer[0]; /* Wrap */
if(outpu_write_ptr == output_read_ptr)
    output_write_ptr = save_ptr; /* Buffer full */

Monday, September 26, 2011

Scheduling - Algorithms


Scheduler Does:
(1) CPU Utilization
    Keeping the CPU as busy as possible
(2) Throughput
    No. of tasks that completed their execution per time unit
(3) Turnaround
    The total time between the submission of a task & its completion.
(4) Waiting Time
    The amount of time a task waits in the ready queue.
(5) Response Time
    The amount of time it takes from when a request was submitted until the first response is produced.
(6) Fairness
    Allocating equal CPU time to each task
Note: In RTOS, the tasks should meet their deadlines


Scheduling Algorithms:
(1) Cyclic Executive/Run to completion
    Iterates through a given set of tasks
    Interrupts are not allowed, only polling
(2) Cooperative multitasking
    Applications run until they yield
(3)Round -Robin scheduling
    Tasks run until they've consumed their timeslice, or until they're blocked
(4) Preemptive priority based multitasking
    Running threads are preempted by threads with higher priorities
    It is not designed to be fair; but to be deterministic
(5) Time partition scheduling
    Guarantees that threads or groups of threads get a predetermined percentage of the CPU.
(6) Deadline scheduling
    Only available in specialized Oss.
    The schedule is dynamically computed such that the applications meet previously specified deadlines.


Interrupts & scheduling

    Interrupts can cause the threads to be rescheduled.
Interrupt Service Routine(ISR): Activities that must be handled at interrupt time(Such as emptying buffers that will quickly overwritten)
Interrupt Service Thread(IST): Activities that can be delayed and handled during normal, priority-driven, thread scheduling(Such as processing data for use by other tasks)


OS can change the priority of a task:
    1. Prevent priority inversion
    2. Deadline scheduler
    3. priority decay scheduling

Priority inversion: Typically occurs when a shared resource is held by a lower-priority thread, thus preventing the higher-priority thread from executing as it should.
Low priority thread requesting a high priority thread to do work on its behalf.
NOTE: Priority inversion could be prevented using mechanims such as priority inheritance or priority ceiling emulation.


Rate Monotonic Analysis
    RMA is the most common method used to analyze and assign priorities for systems with periodic deadlines.But, interrupt processing is not taken care of here.

       
   

Sunday, September 25, 2011

#C_CODE: Binary tree - Morris traversal


#include <stdio.h>
#include <malloc.h>

typedef struct bintree tree;
struct bintree
{
    int data;
    tree *left;
    tree *right;
};

tree *newnode(int num)
{
    tree *r;
    r = (tree *)malloc(sizeof(tree));
    r->data = num;
    r->left = NULL;
    r->right= NULL;
    return (r);
}


void insert(tree **q, int num)
{
    tree *temp = *q;
    if(NULL == temp)
        *q = newnode(num);
    else
    {
        if(num <= temp->data) insert(&(temp->left),num);
        else insert(&(temp->right),num);
    }
}

/* Compute the no. of nodes in the tree */
int size(tree *temp)
{
    if (NULL == temp) return 0;
    else return (size(temp->left) + 1 + size(temp->right));
}

void display(tree *temp)
{
    tree *cur, *pre;
    if(NULL == temp) return;
    cur = temp;

    while(NULL != cur)
    {
        if(NULL == cur->left)
        {
            printf("%d ",cur->data);
            cur = cur->right; 
        }
        else
        {
            pre = cur->left;
            while(pre->right != NULL && pre->right != cur)
                pre = pre->right;
            if(pre->right == NULL)
            {
                pre->right = cur;
                cur = cur->left;
            }
            else
            {
                pre->right = NULL;
                printf("%d ",cur->data);
                cur = cur->right;
            }
        }
    }
}

void inorder(tree *temp)
{
   if(temp != NULL)
   {
       inorder(temp->left);
       printf("%d ",temp->data);
       inorder(temp->right);
   }
}

void preorder(tree *temp)
{
    if(temp != NULL)
    {
        printf("%d ",temp->data);
        preorder(temp->left);
        preorder(temp->right);
    }
}

void postorder(tree *temp)
{
    if(temp != NULL)
    {
        postorder(temp->left);
        postorder(temp->right);
        printf("%d ",temp->data);
    }
}
int numarr[10] = {7,4,1,3,0,5,2,8,6,9};
int main()
{
    tree *root = NULL;
    int i;

    for(i=0; i<10; i++)
        insert(&root,numarr[i]);

    printf("\nThe no. of nodes in the tree: %d\n",size(root));    

    printf("\ninorder: ");
    inorder(root);
    
    printf("\npreorder: ");
    preorder(root);

    printf("\npostorder: ");
    postorder(root);

    printf("\nMorris traversal: ");
    display(root); 
    return 0;
}

Monday, September 19, 2011

#C_CODE: Single Linked List


#include <stdio.h>
#include <malloc.h>


typedef struct singlelink node;
struct singlelink
{
    int data;
    node *next;
};

void append(node **q, int num)
{
    node *temp = *q, *r = NULL;
  
    r = (node *)malloc(sizeof(node));
    r->data = num;
    r->next = NULL;
    if(NULL == temp)
    {
        *q = r;
    }    
    else
    {
        while(NULL != temp->next)
            temp = temp->next;
        temp->next = r;
    }
}

void display(node *temp)
{
    printf("\nThe list: ");
    while(temp)
    {
        printf("%d ",temp->data);
        temp = temp->next;
    }

}

void reverse(node **q)
{
    node *temp1 = *q, *temp2 = NULL, *temp3 = NULL;
  
    while(temp1)
    {
       temp2 = temp1->next; // Save the next pointer
       temp1->next = temp3; // Update the next
       temp3 = temp1; // Update the previous
       temp1 = temp2;
    }

    if(temp3)
        *q = temp3;
}


void delete(node **q, int val)
{
    node *temp = *q, *old = NULL;

    while(temp)
    {
        if(temp->data == val)
        {
           if(temp == *q)
              *q = temp->next;       
           else
                old->next = temp->next;
            free(temp);
        }
        else
        {
            old = temp;
            temp = temp->next;
        }
    }
}

int main()
{
    node *head = NULL;
    unsigned int i;

    for(i=0; i<10; i++)
        append(&head,i);
    display(head);
 
    reverse(&head);
    display(head);

    delete(&head,5);
    display(head);

    return 0;
}

#C_CODE: Base calculator


#include <stdio.h>

char * basecalc(int num,int base)
{
    static char buff[32];
    char *s = &buff[31];
    *s  = '\0';
    while(num)
    {
        *(--s) = "0123456789ABCDEF"[num%base];
        num /= base;
    }
    return s;
}

int main()
{
    int num,base;
    fputs("Enter the num: ",stdout);
    scanf("%d",&num);
    fputs("Enter the base: ",stdout);
    scanf("%d",&base);
    printf("The num %d in base %d is: %s\n",num,base,basecalc(num,base));
    return 0;
}

#C_CODE: Palindrome

#include <stdio.h>
#include <string.h>


int pali(char *s)
{
    char *s2 = s + strlen(s) - 1;

    if(!*s) return 0;

    while(*(s2--) == *(s++) && *s);
    return (!*s && *(++s2) == *(--s));
}

int main()
{  
    char buff[32];
    fputs("Enter the string: ",stdout);
    fgets(buff,sizeof(buff),stdin);  
    *(buff + strlen(buff) - 1)  = '\0';
    printf("Is the string \"%s\" palindrome?%s\n",  

    buff,pali(buff)?"YES":"NO");
    return 0;
}

Tuesday, September 13, 2011

Linux commands

who am i
who
w - extended who command
who -b
fuser /dev/ttyS0
ps proc_id
fuser -k /dev/ttyS0
vmstat - virtual memory status
find
file
wc - count lines,words,characters in a file
df - filesystem statistics
netstat
iostat
diff
sdiff
lshalb  - dynamic database of connected hardware devices

RENAME exe to exe1
find . -name "*.exe" | while read i;
  do
	mv "$i" "${i%.exe}.exe1";
  done

Sunday, September 11, 2011

Find the process that is currently using the serial port


Run as root


$ fuser /dev/ttyUSB0 [or /dev/ttyS0]
> /dev/ttyUSB0:         1761


$ ps 1761
>  PID TTY      STAT   TIME COMMAND
   1761 pts/0    S+     0:00 minicom


This process can also be killed directly with fuser as root
$ fuser -k /dev/ttyUSB0


To quickly connect to board using GNU screen:
$ screen /dev/ttyUSB0 115200

Wednesday, September 7, 2011

CACHE Memory

CACHE (pronounced "CASH")

Cache is used by the processor to reduce the average time to access main memory.
Cache is a smaller, faster memory which stores copies of the data from the most frequently used main memory locations.
When the processor needs to read from or write to a location in main memory, it first checks whether a copy of that data is in the cache.If so, the processor immediately reads from or writes to the cache, which is much faster than reading from or writing to the main memory.

Most CPU's have at least 3 independent caches:
     1. Instruction cache - Speed up executable instructin fetch
     2. Data cache - Speed up data fetch and store
     3. Translation lookaside buffer(TLB) - Speed up virtual-to-physical address translation for both executable instructions and data.

     NOTE: Data cache is organized as a hierarchy of more cache levels - L1,L2 etc.
     NOTE: Cache built into CPU itself is referred to as Level 1(L1) cache.Cache that resides on a separate chip next to the CPU is called Level 2(L2) cache. Some CPUs                 have both L1 & L2 cache built-in and designate the separate cache chip as Level 3(L3) cache.
     NOTE: Cache coherence
                The data in main memory being cached may be changed by other entities (e.g: peripherals usind DMA or multi-core processor), in which case the copy in                     the cache may become out-of-date or stale. 
                Cache coherence protocols should be used for this.

cache hit and cache miss:
      These are just simple terms for the accuracy of what goes into the CPU's cache. If the CPU accesses its cache looking for data it will either find it or it won't. If the CPU finds what's its after that's called a cache hit. If it has to go to main memory to find it then it is called a cache miss. The percentage of hits from the overall cache requests is called the hit rate.

TLB & MMU
    Most CPUs implement some form of virtual memory.
    Each program running on the machine sees its own simplified address space, which contains code and data for that program only. Each program uses this virtual address space without regard for where it exists in physical memory.
    Virtual memory requires the processor to translate virtual addresses generated by the program into physical addresses in main memory. The portin of the processor that does this translation is known as the memory management unit(MMU). The fast path through the MMU can perform those translations stored in the translation lookaside buffer(TLB), which is a cache of mappings from the operating system's page table.

Freescale - i.Mx
Marvel - XScale
Nvidia - Tegra
ST-Ericsson - Nova & NovaThor
Qualcomm - Snapdragon
TI - OMAP
Samsung - Hummingbird
Apple - A4,A5

#ifdef MY_DBG_EN
    #define MY_DBG printf
#else
    #define MY_DBG(fmt, ...) do {} while(0)

Sunday, September 4, 2011

Linux Device Driver

Reference
[Anil Kumar Pugalia]

A device driver is a piece of software that drives a device.

Device - Device Controller - Bus - CPU
Devices are connected to device controller.
Device controllers are typically connected to the CPU through their respectively named buses (IDE, PCI, USB, SPI, I2C...).

Two types of drivers:
        1. Device driver
        2. Bus driver

1. Device Driver
Fig: Linux device driver partition
A device driver has two parts:
    1. Device specific  [Understand & decode device datasheet]
    2. Operating System(OS) specific [Tightly coupled with the OS mechanisms of user interface]

A device driver provides a 'systemcall', interface to the user; this is called the boundary line between the so called kernel space and user space of Linux.

In Linux a driver is broadly classified into three verticals:
Fig: Device Driver Classification
Network Vertical
     1. Network protocol stack
     2. Network interface card device drivers

Storage Vertical
  1. File System drivers   [ To decode various formats on different partitions]
  2. Block device drivers.[ For various h/w storage protocols like IDE,SCSI,MTD]

2. Bus Driver

In Linux, Bus drivers (or the horizontals) are often split into two parts:
          1. A device controller specific
          2. An abstraction layer over that for the verticals to interface, commonly
              called cores.
              [e.g.:   1. USB controller drivers - ohci, ehci etc,
                         2. USB abstraction - usbcore 
              ]


Dynamic Loading in Linux
In Linux, we can load or unload a driver on the fly, and it is active for use instantly after loading. Also it is instantly, disabled when unloaded. This is called dynamic loading and unloading of drivers in Linux.

* Linux kernel is an object oriented implementation in C.

Commands: insmod, lsmod, rmmod, modprobe, modinfo

Simple kernel module/driver
/* simple driver code
 * Author: Vinod Sasidharan
 */

#include
#include
#include

static int __init hello_init(void)
{
    printk(KERN_INFO "Hai: Hello connected");
    return 0;
}

static void __exit hello_exit(void)
{
    printk(KERN_INFO "Bye: Hello disconnected");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vinod Sasidharan");
MODULE_DESCRIPTION("Simple kernel module");

Makefile [Use this for all kernel modules; do change the name(hello.o)]

obj-m+=hello.o
all:
    make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
install:
    make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules_install
Commands
$ sudo su
$ make
$ insmod hello.ko
$ lsmod | grep hello
$ dmesg | tail -10
$ rmmod hello
$ dmesg | tail -10
$ objdump -d hello.ko
$ nm hello.ko

Tested on: Ubuntu 11.04 - the Natty Narwhal



 printk n kernel c
  • Floating point is not supported in Linux kernel.
  • When programming for the kernel, we don't bother about the float formats %f, %lf.
  • All printk calls put their output into the (log) ring buffer of the kernel. Then the syslog daemon running in the user-space picks them up for final processing and re-direction to various devices as configure in the configuration file /etc/syslog.conf [Ubuntu: /etc/sysctl.conf]
  • Typical destination: /var/log/messages
  • A user space utility 'dmesg' is provided to directly parse the kernel ring buffer, and dump it to standard output.
  • Kernel C is just standard C with some additional extensions from the C compiler.
  • All functions with __init are supposed to be executed only once during boot up. So after their execution, kernel frees up RAM by removing them.
  • Functions in the exit section are supposed to be called during system shut down.

Character Drivers

Fig: Character driver

If we write drivers for byte-oriented operations (or character oriented operations) then we refer to them as character drivers.

4 entities
  1.     Application
  2.     Character device file
  3.     Character device driver
  4.     Character device
  • Character driver usage is done by the user space application through the character device file linked to it through the virtual file system (VFS).
  • An application does the usual file operations on the character device file.
  • Those operations are translated to the corresponding functions in the linked character device driver by the VFS.
  • Those functions then do the final low-level access to the actual device to achieve the desired results.












OS Functions

1. Process Management
2. Memory Management
3. Device Management
4. Storage Management
5. Network Management

Root File System (RFS) in Linux


File system: Place to store data in form of files


The root file system refers to the file system mounted at the base of the file system hierarchy 
designated simply as /.

A minimal RFS should contain the following:

        Binaries (/bin,/sbin)
        Libraries (/lib)
        Devices (/dev)
        Configurations (/etc)
        Virtual File Systems (/proc, /sys)
        Applicaiton temporary file (/tmp)
        variable data from daemons & utilities (/var)
        user data (/root, /home) - Optional
        Mount points (/mnt, /media) - optional
        Additional software (/usr,/opt) - optional
        Bootloader files (/boot) - optional


bin - Binary executables, used by all users on the system
dev - Device nodes
etc - local system configuration files
home - user account files
lib - system libraries such as the  C library and many others.
sbin - binary executables usually reserved for superuser accounts on the system.
tmp -temporary files
usr - a secondary file system hierarchy for application programs, usually read-only.
var - contains variable files, such as system logs and temporary configuration files.
proc - a special file system containing system information
mnt - a placeholder for user-mounted devices and file systems.

Links:
1. http://libraryopt.sourceforge.net/
2. http://www.openembedded.org/wiki/Main_Page
3. http://buildroot.uclibc.org/

Thursday, September 1, 2011

Custom Linux in BeagleBoard-xM

The golden reference:
    [labbookpages website]
    [Angstrom Linux - BeagleBoardXm]

Step1: Build the toolchain
    Use crosstool-ng
    [crosstool website]
    My version - crosstool-ng-1.9.3 [180 directories, 1227 files]
    Takes nearly 1 hour to build completely.
    At the end a set of executables viz. "arm-unknown-linux-gnueabi-gcc"
    etc. could be seen in the "x-tools/bin" directory.

Step2: Build the U-Boot
    Bootloader boots the system by copying the kernel &
    root file system to memory.
    [U-Boot website]
    [U-Boot Source Code]
    $ cd u-boot-2011.06/
    $ export CROSS_COMPILE=arm-unknown-linux-gnueabi-
    $ export PATH="/files/beagle/x-tools/bin:$PATH"
    $ make distclean [May have to be root]
    $ make omap3_beagle_config
    $ make
    "u-boot.bin" would be obtained in the same folder 'u-boot-2011.06'

Step3: Build the Xloader (MLO)
      [Xloader reference1] [Xloader reference2]

     Why xloader?
          The SRAM size in DM3730 is 64K.
          u-boot binary size is more than this.(~300K)
          x-loader binary size is lesser (~24K)
          Hence Xloader is required as the main loader
          in SRAM, which would download the u-boot image
          to main MDDR SDRAM.(512MB).
    $ git clone git://gitorious.org/x-load-omap3/mainline.git
    $ cd mainline
    $ make distclean
    $ make omap3530beagle_config
          (NOTE: config file updated in mainline
          tree for DM3730 in BeagleBoardXm)
    $ make
      The output would be "x-loader.bin"; which is in
      raw executable format.
      The size and address should be added at the
      image's first 16-bytes for non-XIP devices.
    Use signGP script [signGP Source Code]
    $ ./signGP x-load.bin
    "x-load.bin.ift" file would be created.
    $ mv x-load.bin.ift MLO

Step4: Build the Linux Kernel
    

Step5: Build the root file system


Step6: Create the boot script



Step7: Prepare the microSdCard
    5 files need to be stored in the uSd Card.
          1. MLO (Xloader)
          [ NOTE: This should be copied first to ensure that it is at the
          start of the card. After copying unmount & then re-mount  
          the card. ]
          2. u-boot.bin
          3. boot.scr (Boot script)
          4. uImage (Linux Kernel image)
          5. rootfs.ext2 (Root file system)

    Two partitions are created.
    The first is used to store the boot loader, kernel and root filing system. 
    The second partition can be used for general file storage.

    7.1 Delete existing partitions
     Remove the existing partition tables:

             root@neolappy:/files/beagle/vinchk#
             dd if=/dev/zero of=/dev/mmcblk0 bs=1024 count=1024


    7.2 Create primary partition
       
       root@neolappy:/files/beagle/vinchk# fdisk /dev/mmcblk0
    Device contains neither a valid DOS partition table, nor Sun, 
    SGI or OSF disklabel
    Building a new DOS disklabel with disk identifier 0x58bad9f5.
    Changes will remain in memory only, until you decide to write them.
    After that, of course, the previous content won't be recoverable.

    Warning: invalid flag 0x0000 of partition table 4 will be corrected 
    by w(rite)

    WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
             switch off the mode (command 'c') and change display units to
             sectors (command 'u').

    Command (m for help): n
    Command action
       e   extended
       p   primary partition (1-4)
    p
    Partition number (1-4): 1
    First cylinder (1-122784, default 1): (Press Enter)
    Using default value 1
    Last cylinder, +cylinders or +size{K,M,G} (1-122784, default 122784): +64M

    Command (m for help): t
    Selected partition 1
    Hex code (type L to list codes): c
    Changed system type of partition 1 to c (W95 FAT32 (LBA))

    Command (m for help): a
    Partition number (1-4): 1

    
7.2 Create the 2nd partition
    Command (m for help): n
    Command action
       e   extended
       p   primary partition (1-4)
    p
    Partition number (1-4): 2
    First cylinder (2050-122784, default 2050): (Press Enter)
    Using default value 2050
    Last cylinder, +cylinders or +size{K,M,G} (2050-122784,
    default 122784): (Press Enter)
    Using default value 122784

    Command (m for help): t
    Partition number (1-4): 2
    Hex code (type L to list codes): 83

    Command (m for help):

7.3 Check created partitions & write
    Command (m for help): p

    Disk /dev/mmcblk0: 4023 MB, 4023386112 bytes
    4 heads, 16 sectors/track, 122784 cylinders
    Units = cylinders of 64 * 512 = 32768 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disk identifier: 0x58bad9f5

   Device          Boot   Start    End       Blocks   Id     System
   /dev/mmcblk0p1   *     1        2049      65560    c      W95 FAT32 (LBA)
   /dev/mmcblk0p2         2050     122784    3863520  83     Linux

    Command (m for help): w
    The partition table has been altered!

   Calling ioctl() to re-read partition table.

   WARNING: Re-reading the partition table failed with error 16:
   Device or    resource busy.
   The kernel still uses the old table. The new table will be used at
   the next reboot or after you run partprobe(8) or kpartx(8)

   WARNING: If you have created or modified any DOS 6.x
   partitions, please see the fdisk manual page for additional
   information.
   Syncing disks.

Partitions: mmcblk0
                            1. mmcblk0p1
                            2. mmcblk0p2

7.4 Create the file systems in the partitions

    Partition1: mkfs.vfat -F 32 -n "boot" /dev/mmcblk0p1
    Partition2: mke2fs -L "files" /dev/mmcblk0p2 
 
    root@neolappy:/files/beagle/vinchk# mkfs.vfat -F 32 -n "boot" /dev/mmcblk0p1
    mkfs.vfat 3.0.9 (31 Jan 2010)
 
    root@neolappy:/files/beagle/vinchk# mke2fs -L "files" /dev/mmcblk0p2 
    mke2fs 1.41.14 (22-Dec-2010)
    Filesystem label=files
    OS type: Linux
    Block size=4096 (log=2)
    Fragment size=4096 (log=2)
    Stride=0 blocks, Stripe width=0 blocks
    241920 inodes, 965880 blocks
    48294 blocks (5.00%) reserved for the super user
    First data block=0
    Maximum filesystem blocks=989855744
    30 block groups
    32768 blocks per group, 32768 fragments per group
    8064 inodes per group
    Superblock backups stored on blocks: 
        	32768, 98304, 163840, 229376, 294912, 819200, 884736

    Writing inode tables: done                            
    Writing superblocks and filesystem accounting information: done

    This filesystem will be automatically checked every 32 mounts or
    180 days, whichever comes first.  Use tune2fs -c or -i to override.