root/modules/eyefi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. clear_eyefi_buf
  2. atoh
  3. convert_ascii_to_hex
  4. hex_only
  5. make_network_key
  6. eyefi_filename
  7. eyefi_writeFile
  8. eyefi_readFile
  9. eyefi_sendCommandParam
  10. eyefi_networkAction
  11. eyefi_deleteNetwork
  12. eyefi_testNetwork
  13. eyefi_addNetwork
  14. eyefi_enableWlan
  15. eyefi_statusName
  16. eyefi_exit
  17. eyefi_wlan_state
  18. confirm_delete_network_cb
  19. select_configured_network_cb
  20. eyefi_configured_networks
  21. confirm_add_network_cb
  22. password_cb
  23. select_available_network_cb
  24. eyefi_available_networks
  25. eyefi_wlan_off
  26. eyefi_wlan_on
  27. _module_can_unload
  28. _run
  29. _module_exit_alt

   1 /*
   2 * Based on work by Dave Hansen <dave@sr71.net>
   3 * original licensing:
   4 * This software may be redistributed and/or modified under the terms of
   5  * the GNU General Public License ("GPL") version 2 as published by the
   6  * Free Software Foundation.
   7  */
   8 #include <gui.h>
   9 #include <string.h>
  10 #include "gui_lang.h"
  11 #include "gui_mbox.h"
  12 #include "gui_tbox.h"
  13 #include "gui_mpopup.h"
  14 #include "gui_menu.h"
  15 #include "eyefi.h"
  16 
  17 //-------------------------------------------------------------------
  18 
  19 #define EINVAL              1000
  20 #define EYEFI_BUF_SIZE      16384
  21 #define ESSID_LEN           32
  22 
  23 // Standard size for various wifi key types
  24 #define WPA_KEY_BYTES       32
  25 #define WEP_KEY_BYTES       13
  26 #define WEP_40_KEY_BYTES    5
  27 
  28 // Status values while testing network
  29 enum test_status
  30 {
  31     EYEFI_NOT_SCANNING,
  32     EYEFI_LOCATING_NETWORK,
  33     EYEFI_VERIFYING_NETWORK_KEY,
  34     EYEFI_WAITING_FOR_DHCP,
  35     EYEFI_TESTING_CONN_TO_SERVER,
  36     EYEFI_SUCCESS
  37 };
  38 
  39 /*
  40  * The 'o' command has several sub-commands:
  41  */
  42 enum card_info_subcommand
  43 {
  44     EYEFI_MAC_ADDRESS   = 1,
  45     EYEFI_FIRMWARE_INFO = 2,
  46     EYEFI_CARD_KEY      = 3,
  47     EYEFI_API_URL       = 4,
  48     EYEFI_UNKNOWN_5     = 5, // Chris says these are
  49     EYEFI_UNKNOWN_6     = 6, // checksums
  50     EYEFI_LOG_LEN       = 7,
  51     EYEFI_WLAN_DISABLE  = 10, // 1=disable 0=enable, write is 1 byte, read is var_byte
  52     EYEFI_UPLOAD_PENDING= 11, // {0x1, STATE}
  53     EYEFI_HOTSPOT_ENABLE= 12, // {0x1, STATE}
  54     EYEFI_CONNECTED_TO  = 13, // Currently connected Wifi network
  55     EYEFI_UPLOAD_STATUS = 14, // current uploading file info
  56     EYEFI_UNKNOWN_15    = 15, // always returns {0x01, 0x1d} as far as I've seen
  57     EYEFI_TRANSFER_MODE = 17,
  58     EYEFI_ENDLESS       = 27, // 0x1b
  59     EYEFI_DIRECT_WAIT_FOR_CONNECTION = 0x24, // 0 == "direct mode off"
  60     EYEFI_DIRECT_WAIT_AFTER_TRANSFER = 0x25, // set to 60 when direct mode off
  61     EYEFI_UNKNOWN_ff    = 0xff, // The D90 does this, and it looks to
  62                   // return a 1-byte response length
  63                   // followed by a number of 8-byte responses
  64                   // But I've only ever seen a single response
  65                   // [000]: 01 04 1d 00 18 56 aa d5 42 00 00 00 00 00 00 00
  66                   // It could be a consolidates info command like "info for
  67                   // everything" so the camera makes fewer calls.
  68 };
  69 
  70 // Wifi key structure sent to card
  71 struct network_key
  72 {
  73     u8  len;
  74     u8  key[WPA_KEY_BYTES];     // Large enough for longest key
  75 } __attribute__((packed));
  76 
  77 // Structures that map to data sent and received from card
  78 
  79 // network info returned from scan
  80 typedef struct
  81 {
  82     char            essid[ESSID_LEN];
  83     signed char     strength;
  84     u8              type;
  85 } __attribute__((packed)) scanned_net;
  86 
  87 // network configured on card
  88 typedef struct
  89 {
  90     char            essid[ESSID_LEN];
  91 } __attribute__((packed)) configured_net;
  92 
  93 // set of networks scanned
  94 typedef struct
  95 {
  96     u8              count;
  97     scanned_net     nets[32];
  98 } __attribute__((packed)) scanned_nets;
  99 
 100 // set of configured networks
 101 typedef struct
 102 {
 103     u8              count;
 104     configured_net  nets[32];
 105 } __attribute__((packed)) configured_nets;
 106 
 107 // command parameters
 108 typedef struct
 109 {
 110     union {
 111         struct {
 112             unsigned char subcommand;
 113             unsigned char bytes;
 114             unsigned char args[32];
 115         } __attribute__((packed)) config;
 116         struct {
 117             unsigned char length;
 118             char SSID[32];
 119             struct network_key key;
 120         } __attribute__((packed)) network;
 121     };
 122 } __attribute__((packed)) eyefi_param;
 123 
 124 // command sent to card
 125 typedef struct
 126 {
 127     u8              cmd;
 128     eyefi_param     param;
 129 } __attribute__((packed)) eyefi_command;
 130 
 131 //-------------------------------------------------------------------
 132 
 133 // map various communication structures to the memory buffer read/written to card
 134 typedef struct
 135 {
 136     union
 137     {
 138         u8              status;     // network testing status
 139         unsigned int    seq;        // command sequence number
 140         scanned_nets    a;          // list of available networks
 141         configured_nets c;          // list of configured networks
 142         eyefi_command   ec;         // command
 143         unsigned char   buf[EYEFI_BUF_SIZE];    // raw buffer data
 144     };
 145 } __attribute__((packed)) _eyefi_interface;
 146 
 147 static int running = 0;     // module status
 148 static _eyefi_interface eyefi_buf;
 149 
 150 static void clear_eyefi_buf()
 151 {
 152     memset(eyefi_buf.buf, 0, EYEFI_BUF_SIZE);
 153 }
 154 
 155 static u8 atoh(char c)
 156 {
 157     char lc = tolower(c);
 158     if ((c >= '0') && (c <= '9'))
 159         return c - '0';
 160     else if ((lc >= 'a') && (lc <= 'z'))
 161         return (lc - 'a') + 10;
 162     return 0;
 163 }
 164 
 165 /*
 166  * Take a string like "0ab1" and make it
 167  * a series of bytes: { 0x0a, 0xb1 }
 168  *
 169  * @len is the strlen() of the ascii
 170  */
 171 static u8 *convert_ascii_to_hex(char *ascii)
 172 {
 173     int i;
 174     static u8 hex[32];
 175     int len = strlen(ascii);
 176 
 177     memset(hex, 0, 32);
 178 
 179     for (i = 0; i < len; i += 2)
 180     {
 181         u8 high = atoh(ascii[i]);
 182         u8 low  = atoh(ascii[i+1]);
 183         hex[i/2] = (high<<4) | low;
 184     }
 185 
 186     return hex;
 187 }
 188 
 189 static int hex_only(char *str)
 190 {
 191     int i;
 192 
 193     for (i = 0; i < strlen(str); i++) {
 194         if (((str[i] >= 'a') && str[i] <= 'f') ||
 195             ((str[i] >= 'A') && str[i] <= 'F') ||
 196             ((str[i] >= '0') && str[i] <= '9')) {
 197             continue;
 198         }
 199         return 0;
 200     }
 201     return 1;
 202 }
 203 
 204 // Convert user input to a network key - tries to guess key type based on length of input
 205 // ToDo: should probably look at the network type returned from the list of available networks instead
 206 static int make_network_key(struct network_key *key, char *essid, char *pass)
 207 {
 208     u8 *hex_pass;
 209     int pass_len = strlen(pass);
 210     memset(key, 0, sizeof(*key));
 211 
 212     switch (pass_len) {
 213         case WPA_KEY_BYTES*2:
 214         case WEP_KEY_BYTES*2:
 215         case WEP_40_KEY_BYTES*2:
 216             if (hex_only(pass))
 217             {
 218                 hex_pass = convert_ascii_to_hex(pass);
 219                 if (!hex_pass)
 220                     return -EINVAL;
 221                 key->len = pass_len/2;
 222                 memcpy(&key->key[0], hex_pass, key->len);
 223                 break;
 224             }
 225         // Fall through to default case
 226         default:
 227             key->len = WPA_KEY_BYTES;
 228             pbkdf2_sha1(pass, essid, strlen(essid), 4096, &key->key[0], WPA_KEY_BYTES);
 229             break;
 230     }
 231     return 0;
 232 }
 233 
 234 // Full path to EyeFi command/control file
 235 static char *eyefi_filename(const char *nm)
 236 {
 237     static char path[16];
 238 
 239     strcpy(path, "A/EyeFi/");
 240     strcat(path, nm);
 241 
 242     return path;
 243 }
 244 
 245 // Write a 16K command/control file to the card. Data is written from the eyefi_buf array.
 246 // Returns true (1) is successful, false (0) otherwise
 247 static int eyefi_writeFile(const char *filename)
 248 {
 249     int fd = open(eyefi_filename(filename), O_RDWR|O_CREAT, 0600);
 250 
 251     if (fd < 0)
 252         return 0;
 253 
 254     int bytesWritten = write(fd, eyefi_buf.buf, EYEFI_BUF_SIZE);
 255     close(fd);
 256 
 257     return bytesWritten == EYEFI_BUF_SIZE;
 258 }
 259 
 260 // Read a 16K command/control file to the card. Data is placed in eyefi_buf array.
 261 // Returns true (1) is successful, false (0) otherwise
 262 static int eyefi_readFile(const char *filename)
 263 {
 264     clear_eyefi_buf();
 265 
 266     int fd = open(eyefi_filename(filename), O_RDONLY, 0777);
 267 
 268     if (fd < 0)
 269         return 0;
 270 
 271     int bytesRead = read(fd, eyefi_buf.buf, EYEFI_BUF_SIZE);
 272     close(fd);
 273 
 274     return bytesRead == EYEFI_BUF_SIZE;
 275 }
 276 
 277 // Send a command with optional parameters to the card
 278 // Basic flow:
 279 //      - get current sequence number from RSPC file
 280 //      - write command and parameters to REQM file
 281 //      - write new sequence number to REQC file
 282 //      - wait for sequence number to update in RSPC file
 283 //      - read command results from RSPM file
 284 static int eyefi_sendCommandParam(unsigned char cmd, eyefi_param *param)
 285 {
 286     int i;
 287 
 288     if (!eyefi_readFile("RSPC")) return 0;
 289     unsigned int cur_seq = eyefi_buf.seq;
 290 
 291     clear_eyefi_buf();
 292     eyefi_buf.ec.cmd = cmd;
 293 
 294     if (param)
 295         memcpy(&eyefi_buf.ec.param, param, sizeof(eyefi_param));
 296 
 297     if (!eyefi_writeFile("REQM")) return -1;
 298 
 299     clear_eyefi_buf();
 300     eyefi_buf.seq = ++cur_seq;
 301     if (!eyefi_writeFile("REQC")) return -2;
 302 
 303     for (i=0; i<20; i++)
 304     {
 305         if (!eyefi_readFile("RSPC")) return -3;
 306         if (eyefi_buf.seq == cur_seq)
 307         {
 308             if (!eyefi_readFile("RSPM")) return -5;
 309             return 1;
 310         }
 311         msleep(250);
 312     }
 313 
 314     return -4;
 315 }
 316 
 317 #define eyefi_sendCommand(cmd)          eyefi_sendCommandParam(cmd, NULL)
 318 #define eyefi_getAvailableNetworks()    eyefi_sendCommand('g')
 319 #define eyefi_getConfiguredNetworks()   eyefi_sendCommand('l')
 320 #define eyefi_getNetworkStatus()        eyefi_sendCommand('s')
 321 
 322 // Send a network action command (command with SSID & optional password)
 323 int eyefi_networkAction(unsigned char cmd, char *SSID, char *pwd)
 324 {
 325     eyefi_param param;
 326     memset(&param, 0, sizeof(eyefi_param));
 327     param.network.length = (unsigned char)strlen(SSID);
 328     strcpy(param.network.SSID, SSID);
 329     if (pwd)
 330     {
 331         make_network_key(&param.network.key, SSID, pwd);
 332     }
 333     return eyefi_sendCommandParam(cmd, &param);
 334 }
 335 
 336 int eyefi_deleteNetwork(char *SSID)
 337 {
 338     return eyefi_networkAction('d', SSID, NULL);
 339 }
 340 
 341 int eyefi_testNetwork(char *SSID,char *pwd)
 342 {
 343     return eyefi_networkAction('t', SSID, pwd);
 344 }
 345 
 346 int eyefi_addNetwork(char *SSID,char *pwd)
 347 {
 348     return eyefi_networkAction('a', SSID, pwd);
 349 }
 350 
 351 // Turn WiFi on or off.
 352 int eyefi_enableWlan(int enable)
 353 {
 354     eyefi_param param;
 355     memset(&param, 0, sizeof(eyefi_param));
 356     param.config.subcommand = EYEFI_WLAN_DISABLE;
 357     param.config.bytes = 1;
 358     param.config.args[0] = (unsigned char)enable;
 359     return eyefi_sendCommandParam('O', &param);
 360 }
 361 
 362 //int eyefi_wlanEnabled(int *pEnabled) {
 363 //  eyefi_param param;
 364 //    memset(&param,0,sizeof(param));
 365 //  param.config.subcommand=EYEFI_WLAN_DISABLE;
 366 //  param.config.bytes=0;
 367 //  eyefi_sendCommandParam('o',&param);
 368 //  *pEnabled=eyefi_buf.buf[1];
 369 //  return 1;
 370 //}
 371 
 372 // Test mode status strings
 373 char *eyefi_statusName(int n)
 374 {
 375     static char *eyefi_status[] =
 376     {
 377         "not scanning",
 378         "locating network",
 379         "verifying network_key",
 380         "waiting for DHCP",
 381         "testing conn. to server",
 382         "success"
 383     };
 384 
 385     if (n<0 || n>=sizeof(eyefi_status)/sizeof(*eyefi_status))
 386         return "?";
 387 
 388     return eyefi_status[n];
 389 }
 390 
 391 //-----------------------------------------------------------------------------
 392 // GUI.c interface
 393 
 394 #define MAX_NETWORK 9           // Limit of popup menu
 395 #define PWD_LEN     32          // Max password length
 396 
 397 static struct mpopup_item popup_eyefi[MAX_NETWORK+1];   // list of entries for popup menu (+1 for Cancel)
 398 static char eyefi_selectedNetwork[ESSID_LEN+1];
 399 static char eyefi_password[PWD_LEN+1];
 400 
 401 // Exit module
 402 static void eyefi_exit(unsigned int button)
 403 {
 404     running = 0;
 405     gui_set_need_restore();
 406 }
 407 
 408 static void eyefi_wlan_state(int on_off)
 409 {
 410     running = 1;
 411 
 412     int n = eyefi_enableWlan(on_off);
 413 
 414     if (n <= 0)
 415         gui_mbox_init(LANG_ERROR_INITIALIZING_EYEFI,LANG_NO_EYEFI_CARD_FOUND,MBOX_BTN_OK,eyefi_exit);
 416     else
 417         gui_mbox_init(LANG_SUCCESS,(on_off)?LANG_EYEFI_WLAN_TURNED_ON:LANG_EYEFI_WLAN_TURNED_OFF,MBOX_BTN_OK,eyefi_exit);
 418 }
 419 
 420 static void confirm_delete_network_cb(unsigned int btn)
 421 {
 422     if (btn == MBOX_BTN_YES)
 423     {
 424         int n = eyefi_deleteNetwork(eyefi_selectedNetwork);
 425         gui_mbox_init(LANG_SUCCESS,n<=0?LANG_CANNOT_DELETE_NETWORK:LANG_NETWORK_DELETED,MBOX_BTN_OK,eyefi_exit);
 426     }
 427     eyefi_exit(0);
 428 }
 429 
 430 static void select_configured_network_cb(unsigned nSelected)
 431 {
 432     unsigned flag=1;
 433     int i, n;
 434 
 435     if (nSelected == MPOPUP_CANCEL)
 436     {
 437         eyefi_exit(0);
 438         return;
 439     }
 440 
 441     n = eyefi_buf.c.count;
 442     for (i=0; i<n && i<MAX_NETWORK; i++)
 443     {
 444         if (nSelected == flag) break;
 445         flag <<= 1;
 446     }
 447 
 448     if (nSelected != flag)
 449     {
 450         gui_mbox_init(LANG_POPUP_DELETE,LANG_CANNOT_FIND_NETWORK,MBOX_BTN_OK,eyefi_exit);
 451         return;
 452     }
 453 
 454     strcpy(eyefi_selectedNetwork, eyefi_buf.c.nets[i].essid);
 455 
 456     static char s[80];
 457     sprintf(s,"Delete \"%s\"?",eyefi_selectedNetwork);
 458     gui_mbox_init(LANG_POPUP_DELETE,(int)s/*LANG_ARE_YOU_SURE*/,MBOX_BTN_YES_NO|MBOX_DEF_BTN2,confirm_delete_network_cb);
 459 }
 460 
 461 static void eyefi_configured_networks()
 462 {
 463     unsigned flag=1,flags=0;
 464     int i,n;
 465 
 466     running = 1;
 467 
 468     if (eyefi_getConfiguredNetworks() <= 0)
 469     {
 470         gui_mbox_init(LANG_ERROR_INITIALIZING_EYEFI,LANG_NO_EYEFI_CARD_FOUND,MBOX_BTN_OK,eyefi_exit);
 471     }
 472     else
 473     {
 474         memset(eyefi_selectedNetwork, 0, sizeof(eyefi_selectedNetwork));
 475         n = eyefi_buf.c.count;
 476         for (i=0; i<n && i<MAX_NETWORK; i++)
 477         {
 478             popup_eyefi[i].text = (int)(eyefi_buf.c.nets[i].essid);
 479             popup_eyefi[i].flag = flag;
 480             flags |= flag;
 481             flag <<= 1;
 482         }
 483         popup_eyefi[i].text = (int)"Cancel";
 484         popup_eyefi[i].flag = MPOPUP_CANCEL;
 485 
 486         libmpopup->show_popup(popup_eyefi, flags, select_configured_network_cb);
 487     }
 488 }
 489 
 490 static void confirm_add_network_cb(unsigned int btn)
 491 {
 492     int n,i;
 493 
 494     if (btn==MBOX_BTN_YES)
 495     {
 496         n = eyefi_testNetwork(eyefi_selectedNetwork, eyefi_password);
 497         gui_browser_progress_show("testing network",5);
 498         for (i=0; i<50; i++)
 499         {
 500             msleep(10);
 501             n = eyefi_getNetworkStatus();
 502             if (eyefi_buf.status == 0)
 503             {
 504                 gui_mbox_init(LANG_FAILED,LANG_WRONG_PASSWORD,MBOX_BTN_OK,eyefi_exit);
 505                 return;
 506             }
 507             if (eyefi_buf.status <= EYEFI_SUCCESS)
 508             {
 509                 gui_browser_progress_show(eyefi_statusName(eyefi_buf.status),(eyefi_buf.status*100)/(EYEFI_SUCCESS+1));
 510                 if (eyefi_buf.status == EYEFI_SUCCESS)
 511                     break;
 512             }
 513             else
 514                 gui_browser_progress_show("????",50);
 515         }
 516 
 517         if (eyefi_buf.status != EYEFI_SUCCESS)
 518         {
 519             gui_mbox_init(LANG_FAILED,LANG_WRONG_PASSWORD,MBOX_BTN_OK,eyefi_exit);
 520             return;
 521         }
 522     }
 523 
 524     gui_browser_progress_show("adding network", 95);
 525     n = eyefi_addNetwork(eyefi_selectedNetwork, eyefi_password);
 526     if (n > 0)
 527         gui_mbox_init(LANG_SUCCESS,LANG_NETWORK_ADDED,MBOX_BTN_OK,eyefi_exit);
 528     else
 529         gui_mbox_init(LANG_FAILED,LANG_PROBLEM_ADDING_NETWORK,MBOX_BTN_OK,eyefi_exit);
 530 }
 531 
 532 static void password_cb(const char *str)
 533 {
 534     if (str == NULL)
 535     {
 536         eyefi_exit(0);
 537     }
 538     else
 539     {
 540         strncpy(eyefi_password, str, sizeof(eyefi_password)-1);
 541         gui_mbox_init(LANG_ADD_NETWORK,LANG_TEST_NETWORK,MBOX_BTN_YES_NO|MBOX_DEF_BTN1,confirm_add_network_cb);
 542     }
 543 }
 544 
 545 static void select_available_network_cb(unsigned nSelected)
 546 {
 547     unsigned flag=1;
 548     int i,n;
 549 
 550     if (nSelected == MPOPUP_CANCEL)
 551     {
 552         eyefi_exit(0);
 553         return;
 554     }
 555 
 556     n = eyefi_buf.a.count;
 557     for (i=0; i<n && i<MAX_NETWORK; i++)
 558     {
 559         if (nSelected == flag) break;
 560         flag <<= 1;
 561     }
 562 
 563     if (nSelected != flag)
 564     {
 565         gui_mbox_init(LANG_ADD_NETWORK,LANG_CANNOT_FIND_NETWORK,MBOX_BTN_OK,eyefi_exit);
 566         return;
 567     }
 568 
 569     strcpy(eyefi_selectedNetwork,eyefi_buf.a.nets[i].essid);
 570     libtextbox->textbox_init((int)eyefi_selectedNetwork, LANG_PASSWORD, eyefi_password, PWD_LEN, password_cb, NULL);
 571 }
 572 
 573 static void eyefi_available_networks()
 574 {
 575     unsigned flag=1,flags=0;
 576     int i,n;
 577 
 578     running = 1;
 579 
 580     if (eyefi_getAvailableNetworks() <= 0)
 581     {
 582         gui_mbox_init(LANG_ERROR_INITIALIZING_EYEFI,LANG_NO_EYEFI_CARD_FOUND,MBOX_BTN_OK,eyefi_exit);
 583     }
 584     else
 585     {
 586         memset(eyefi_selectedNetwork,0,sizeof(eyefi_selectedNetwork));
 587         n = eyefi_buf.a.count;
 588 
 589         if (n == 0)
 590         {
 591             gui_mbox_init(LANG_ADD_NETWORK,LANG_CANNOT_FIND_NETWORK,MBOX_BTN_OK,eyefi_exit);
 592         }
 593         else
 594         {
 595             for (i=0; i<n && i<MAX_NETWORK; i++)
 596             {
 597                 popup_eyefi[i].text = (int)&(eyefi_buf.a.nets[i].essid);
 598                 popup_eyefi[i].flag = flag;
 599                 flags |= flag;
 600                 flag <<= 1;
 601             }
 602             popup_eyefi[i].text = (int)"Cancel";
 603             popup_eyefi[i].flag = MPOPUP_CANCEL;
 604 
 605             libmpopup->show_popup(popup_eyefi,flags,select_available_network_cb);
 606         }
 607     }
 608 }
 609 
 610 //-----------------------------------------------------------------------------
 611 static void eyefi_wlan_off()
 612 {
 613     eyefi_wlan_state(0);
 614 }
 615 
 616 static void eyefi_wlan_on()
 617 {
 618     eyefi_wlan_state(1);
 619 }
 620 
 621 static CMenuItem eyefi_submenu_items[] = {
 622     MENU_ITEM   (0x5c,LANG_MENU_EYEFI_AVAILABLE_NETWORKS,   MENUITEM_PROC,          eyefi_available_networks,  0 ),
 623     MENU_ITEM   (0x5c,LANG_MENU_EYEFI_CONFIGURED_NETWORKS,  MENUITEM_PROC,          eyefi_configured_networks, 0 ),
 624     MENU_ITEM   (0x5c,LANG_FORCE_EYEFI_WLAN_OFF,            MENUITEM_PROC,          eyefi_wlan_off,            0 ),
 625     MENU_ITEM   (0x5c,LANG_FORCE_EYEFI_WLAN_ON,             MENUITEM_PROC,          eyefi_wlan_on,             0 ),
 626     MENU_ITEM   (0x51,LANG_MENU_BACK,                       MENUITEM_UP,            0,                         0 ),
 627     {0}
 628 };
 629 
 630 static CMenu eyefi_submenu = {0x21,LANG_MENU_EYEFI_TITLE, eyefi_submenu_items };
 631 
 632 //-----------------------------------------------------------------------------
 633 int _module_can_unload()
 634 {
 635     return (running == 0) || (get_curr_menu() != &eyefi_submenu);
 636 }
 637 
 638 int _run()
 639 {
 640     running = 1;
 641     gui_activate_sub_menu(&eyefi_submenu);
 642     return 0;
 643 }
 644 
 645 int _module_exit_alt()
 646 {
 647     running = 0;
 648     return 0;
 649 }
 650 
 651 #include "simple_module.h"
 652 
 653 // =========  MODULE INIT =================
 654 
 655 libsimple_sym _libeyefi =
 656 {
 657     {
 658          0, 0, _module_can_unload, _module_exit_alt, _run
 659     },
 660 };
 661 
 662 ModuleInfo _module_info =
 663 {
 664     MODULEINFO_V1_MAGICNUM,
 665     sizeof(ModuleInfo),
 666     SIMPLE_MODULE_VERSION,      // Module version
 667 
 668     ANY_CHDK_BRANCH, 0, OPT_ARCHITECTURE,         // Requirements of CHDK version
 669     ANY_PLATFORM_ALLOWED,       // Specify platform dependency
 670 
 671     -LANG_EYEFI,
 672     MTYPE_TOOL|MTYPE_SUBMENU_TOOL,  //Handle Eyefi SD cards
 673 
 674     &_libeyefi.base,
 675 
 676     ANY_VERSION,                // CONF version
 677     ANY_VERSION,                // CAM SCREEN version
 678     ANY_VERSION,                // CAM SENSOR version
 679     ANY_VERSION,                // CAM INFO version
 680 };

/* [<][>][^][v][top][bottom][index][help] */