There's something weird: the code sample you provided is already a double linked list
as proved by the node definition:

Code:
struct listNode {
  char data;
  struct listNode *nextPtr;
  struct listNode *prevPtr;
}
However the insert/delete and dump routines are using the list as
a single linked list indeed (the whole list is walked each time a value
is inserted, etc.) so the only thing you have to do is to adapt those
routines: instead of walking the whole list, keep a record of the last
node inserted and add/delete each new node from here.

A double linked list is no different of a single linked list for the 'external'
user (the interface is identical) but the insertion/deletion cost are much
less expensive as there is no loop (assuming you simply add and delete
from the end of the list).