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

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