1/***************************************************************************
2 ***
3 ***    Copyright 2005  Hon Hai Precision Ind. Co. Ltd.
4 ***    All Rights Reserved.
5 ***    No portions of this material shall be reproduced in any form without the
6 ***    written permission of Hon Hai Precision Ind. Co. Ltd.
7 ***
8 ***    All information contained in this document is Hon Hai Precision Ind.
9 ***    Co. Ltd. company private, proprietary, and trade secret property and
10 ***    are protected by international intellectual property laws and treaties.
11 ***
12 ****************************************************************************
13 ***
14 ***  Filename: hotplug_usb.c
15 ***
16 ***  Description:
17 ***    USB automount function
18 ***
19 ***  HISTORY:
20 ***       - Created Date: 04/24/2009, Water, @USB spec1.7 implement on WNR3500L
21 *******************************************************************************/
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27#include <errno.h>
28#include <dirent.h>
29#include <sys/stat.h>
30#include <sys/mount.h>
31#include <sys/wait.h>
32#include "bcmconfig.h"
33#include "shutils.h"
34#include "bcmnvram.h"
35
36//#define USB_HOTPLUG_DBG//@debug
37#define MNT_DETACH 0x00000002 /* Foxconn add , Jenny Zhao, 04/22/2009 @usb dir */
38
39/***********************************************************************************************************************
40* Environment of hotplug for USB:
41* DEVICE=bus_num, dev_num
42*
43* PRODUCT=Vendor, Product, bcdDevice
44*
45* TYPE= DeviceClass, DeviceSubClass, DeviceProtocol
46*
47* if DeviceClass == 0
48*  -> INTERFACE=interface [0].altsetting [alt].bInterfaceClass, interface [0].altsetting [alt].bInterfaceSubClass,
49*               interface [0].altsetting [alt].bInterfaceProtocol
50*
51***********************************************************************************************************************/
52
53/* Foxconn added start pling 07/13/2009 */
54#include <sys/types.h>
55#include <sys/ipc.h>
56#include <sys/sem.h>
57
58#define LOCK           -1
59#define UNLOCK          1
60#define USB_SEM_KEY     0x5553424B     // "USBK"
61
62int usb_sem_init(void)
63{
64    struct sembuf lockop = { 0, 0, SEM_UNDO } /* sem operation */ ;
65    int semid;
66
67    /* create/init sem */
68    if ((semid = semget (USB_SEM_KEY, 1, IPC_CREAT | IPC_EXCL | 0666)) >= 0)
69    {
70        /* initialize the sem vaule to 1 */
71        if (semctl (semid, 0, SETVAL, 1) < 0)
72        {
73            perror("usb_sem_init");
74            return -1;
75        }
76        return 0;
77    }
78    return -1;
79}
80
81/* static */ int usb_sem_lock(int op)
82{
83    struct sembuf lockop = { 0, 0, SEM_UNDO } /* sem operation */ ;
84    int semid;
85
86    /* sem already created. get the semid */
87    if ((semid = semget (USB_SEM_KEY, 1, 0666)) < 0)
88    {
89        perror("usb_sem_lock");
90        return -1;
91    }
92
93    lockop.sem_op = op;
94    if (semop (semid, &lockop, 1) < 0)
95        return -1;
96
97    return 0;
98}
99
100#define USB_LOCK()      usb_sem_lock(LOCK)
101#define USB_UNLOCK()    usb_sem_lock(UNLOCK)
102/* Foxconn added end pling 07/13/2009 */
103
104/* Foxconn add start pling 02/05/2010*/
105/* USB LED on / off */
106#ifdef INCLUDE_USB_LED
107#include "wps_led.h"
108#include <sys/stat.h>
109#include <fcntl.h>
110
111/* Foxconn added start, Wins, 04/11/2011 */
112#if defined(WNDR4500REV) || defined(R4500)
113#define MAX_BUF_LEN     512
114#define USB_MNT_TABLE   "/tmp/usb_mnt_table"
115#define USB_MNT_TABLE2  "/tmp/usb_mnt_table2"
116#define USB_MNT_PATTERN "PORT=%s,DEVICE=%s,PART=%s"
117
118/* for Time Machine , added start by EricHuang, 12/22/2011 */
119#if defined(INCLUDE_AFP)
120#define USB_MNT_TABLE3  "/tmp/usb_mnt_table3"
121#define USB_MNT_TABLE4  "/tmp/usb_mnt_table4"
122
123int add_into_mnt_src_file(char *target, char *src)
124{
125    FILE *fp = NULL;
126    int rtn_val = 0;
127    char buf[128];
128
129    /* Foxconn added start, Wins, 06/30/2011 */
130    if ((fp = fopen(USB_MNT_TABLE3, "r")) != NULL)
131    {
132        int rec_found = 0;
133        char patt[128];
134        /* Check if record of USB device exists. */
135        while(fgets(buf, sizeof(buf), fp) != NULL)
136        {
137            memset(patt, 0x0, sizeof(patt));
138            sprintf(patt, "%s %s", src, target);
139            strcat(patt, "\n");
140            if (!strcmp(buf, patt))
141            {
142                rec_found = 1;
143                break;  /* Record exists. */
144            }
145        }
146        fclose(fp);
147        if (rec_found)
148            return 1;   /* Not need to add a duplicated record. */
149    }
150    fp = NULL;
151    /* Foxconn added end, Wins, 06/30/2011 */
152
153    if ((fp = fopen(USB_MNT_TABLE3, "a+")) != NULL)
154    {
155        fseek(fp, 0, SEEK_END);
156        sprintf(buf, "%s %s", src, target);
157        strcat(buf, "\n");
158        fputs(buf, fp);
159        fclose(fp);
160        rtn_val = 1;
161    }
162
163    return rtn_val;
164} /* add_into_mnt_src_file() */
165
166int remove_from_mnt_src_file(char *pUsbPort, char *pDevice, char *pPart)
167{
168    FILE *fp = NULL, *fp2 = NULL;
169    int rtn_val = 0;
170    char usb_device[4], usb_part[4];
171    char buf[128];
172    char *strPos1 = NULL, *strPos2 = NULL;
173
174    if ((fp = fopen(USB_MNT_TABLE3, "r+")) != NULL)
175    {
176        char buf[128];
177        sprintf(buf, "cp -f %s %s", USB_MNT_TABLE3, USB_MNT_TABLE4);
178        system(buf);
179        fclose(fp);
180    }
181
182    fp = NULL; fp2 = NULL;
183    if ((fp2 = fopen(USB_MNT_TABLE4, "r+")) != NULL)
184    {
185        char buf[MAX_BUF_LEN];
186        char patt[MAX_BUF_LEN];
187        sprintf(patt, USB_MNT_PATTERN, pUsbPort, pDevice, pPart);
188        if ((fp = fopen(USB_MNT_TABLE3, "w+")) != NULL)
189        {
190            while (fgets(buf, MAX_BUF_LEN, fp2) != NULL)
191            {
192                if ((strPos1 = strstr(buf, patt)) != NULL) {
193                    continue;
194                }
195                else {
196                    fputs(buf, fp);
197                }
198            }
199            fclose(fp);
200            rtn_val = 1;
201        }
202        fclose(fp2);
203
204        sprintf(buf, "rm -f %s", USB_MNT_TABLE4);
205        system(buf);
206    }
207
208    return rtn_val;
209} /* remove_from_mnt_src_file() */
210#endif
211/* for Time Machine , added end by EricHuang, 12/22/2011 */
212
213int get_usb_port(char *pDevPath, char *pUsbPort)
214{
215    int rtn_val = 0;
216    char buf[256];
217    char *strPos1 = NULL, *strPos2 = NULL;
218
219    if ((strPos1 = strstr(pDevPath, "/usb1/1-1/1-1.")) != NULL) {
220        sscanf(strPos1, "/usb1/1-1/1-1.%s", buf);
221        if ((strPos2 = strchr(buf, '/')) != NULL) {
222            memcpy(pUsbPort, buf, (strPos2 - buf));
223            rtn_val = 1;
224        }
225    }
226
227    return rtn_val;
228} /* get_usb_port() */
229
230int parse_target_path(char *pTarget, int *pDevice, int *pPart)
231{
232    int rtn_val = 0;
233    char usb_device[4], usb_part[4];
234    char buf[128];
235    char *strPos1 = NULL, *strPos2 = NULL;
236
237    /* Get USB device & part */
238    memset(usb_device, 0x0, sizeof(usb_device));
239    memset(usb_part, 0x0, sizeof(usb_part));
240    if ((strPos1 = strstr(pTarget, "/tmp/mnt/usb")) != NULL) {
241        sscanf(strPos1, "/tmp/mnt/usb%s", buf);
242        if ((strPos2 = strchr(buf, '/')) != NULL) {
243            memcpy(usb_device, buf, (strPos2-buf));
244            *pDevice = atoi(usb_device);
245            strPos2 = NULL;
246            if ((strPos2 = strstr(buf, "/part")) != NULL) {
247                sscanf(strPos2, "/part%s", usb_part);
248                *pPart = atoi(usb_part);
249                rtn_val = 1;
250            }
251        }
252    }
253
254    return rtn_val;
255} /* parse_target_path() */
256
257int add_into_mnt_file(char *pUsbPort, char *pDevice, char *pPart)
258{
259    FILE *fp = NULL;
260    int rtn_val = 0;
261    char buf[128];
262
263    /* Foxconn added start, Wins, 06/30/2011 */
264    if ((fp = fopen(USB_MNT_TABLE, "r")) != NULL)
265    {
266        int rec_found = 0;
267        char patt[128];
268        /* Check if record of USB device exists. */
269        while(fgets(buf, sizeof(buf), fp) != NULL)
270        {
271            memset(patt, 0x0, sizeof(patt));
272            sprintf(patt, USB_MNT_PATTERN, pUsbPort, pDevice, pPart);
273            strcat(patt, "\n");
274            if (!strcmp(buf, patt))
275            {
276                rec_found = 1;
277                break;  /* Record exists. */
278            }
279        }
280        fclose(fp);
281        if (rec_found)
282            return 1;   /* Not need to add a duplicated record. */
283    }
284    fp = NULL;
285    /* Foxconn added end, Wins, 06/30/2011 */
286
287    if ((fp = fopen(USB_MNT_TABLE, "a+")) != NULL)
288    {
289        fseek(fp, 0, SEEK_END);
290        sprintf(buf, USB_MNT_PATTERN, pUsbPort, pDevice, pPart);
291        strcat(buf, "\n");
292        fputs(buf, fp);
293        fclose(fp);
294        rtn_val = 1;
295    }
296
297    return rtn_val;
298} /* add_into_mnt_file() */
299
300int remove_from_mnt_file(char *pUsbPort, char *pDevice, char *pPart)
301{
302    FILE *fp = NULL, *fp2 = NULL;
303    int rtn_val = 0;
304    char usb_device[4], usb_part[4];
305    char buf[128];
306    char *strPos1 = NULL, *strPos2 = NULL;
307
308    if ((fp = fopen(USB_MNT_TABLE, "r+")) != NULL)
309    {
310        char buf[128];
311        sprintf(buf, "cp -f %s %s", USB_MNT_TABLE, USB_MNT_TABLE2);
312        system(buf);
313        fclose(fp);
314    }
315
316    fp = NULL; fp2 = NULL;
317    if ((fp2 = fopen(USB_MNT_TABLE2, "r+")) != NULL)
318    {
319        char buf[MAX_BUF_LEN];
320        char patt[MAX_BUF_LEN];
321        sprintf(patt, USB_MNT_PATTERN, pUsbPort, pDevice, pPart);
322        if ((fp = fopen(USB_MNT_TABLE, "w+")) != NULL)
323        {
324            while (fgets(buf, MAX_BUF_LEN, fp2) != NULL)
325            {
326                if ((strPos1 = strstr(buf, patt)) != NULL) {
327                    continue;
328                }
329                else {
330                    fputs(buf, fp);
331                }
332            }
333            fclose(fp);
334            rtn_val = 1;
335        }
336        fclose(fp2);
337
338        sprintf(buf, "rm -f %s", USB_MNT_TABLE2);
339        system(buf);
340    }
341
342    return rtn_val;
343} /* remove_from_mnt_file() */
344
345int usb1_led(void)
346{
347    int rtn_val = 0;
348    int has_usb1_dev = 0;
349    int fd;
350    FILE *fp = NULL;
351    char line[250] = "";
352
353    if ((fp = fopen(USB_MNT_TABLE, "r")) != NULL)
354    {
355        rtn_val = 1;
356        while (fgets(line, 200, fp) != NULL) {
357            if (strstr(line, "PORT=1") != NULL) {
358                has_usb1_dev = 1;
359                rtn_val = 2;
360                break;
361            }
362        }
363        fclose(fp);
364    }
365    /* foxconn wklin modified start, 01/19/2011 @ USB LED for WNDR4000 */
366
367    /* Foxconn added start pling 10/05/2012 */
368    /* Before we turn off USB LED 1, check whether we have
369     * a printer connected or not.
370     */
371    if (!has_usb1_dev)
372    {
373        fp = fopen("/proc/NetUSB/0/device", "r");
374        if (fp)
375        {
376            memset(line, 0, sizeof(line));
377            fgets(line, sizeof(line), fp);
378            fclose(fp);
379            if (strlen(line) > 2)
380            {
381                printf("%s: USB LED1 on!\n", __FUNCTION__);
382                has_usb1_dev = 1;
383            }
384        }
385    }
386    /* Foxconn added end pling 10/05/2012 */
387
388#if (defined GPIO_EXT_CTRL) /* WNDR4000 */
389    if (has_usb1_dev)
390        system("gpio usbled 1");
391    else
392        system("gpio usbled 0");
393#else
394    fd = open("/dev/wps_led", O_RDWR);
395    if (fd >= 0) {
396        rtn_val = 3;
397        if (has_usb1_dev)
398        {
399            ioctl(fd, USB_LED_STATE_ON, 1);
400            rtn_val = 4;
401        }
402        else
403        {
404            ioctl(fd, USB_LED_STATE_OFF, 1);
405            rtn_val = 5;
406        }
407        close(fd);
408    }
409#endif /* GPIO_EXT_CTRL */
410    /* foxconn wklin modified end ,01/19/2011 */
411    return rtn_val;
412} /* usb1_led() */
413
414int usb2_led(void)
415{
416    int rtn_val = 0;
417    int has_usb2_dev = 0;
418    int fd;
419    FILE *fp = NULL;
420    char line[250] = "";
421
422    if ((fp = fopen(USB_MNT_TABLE, "r")) != NULL)
423    {
424        rtn_val = 1;
425        while (fgets(line, 200, fp) != NULL) {
426            if (strstr(line, "PORT=2") != NULL) {
427                has_usb2_dev = 1;
428                rtn_val = 2;
429                break;
430            }
431        }
432        fclose(fp);
433    }
434    /* foxconn wklin modified start, 01/19/2011 @ USB LED for WNDR4000 */
435
436    /* Foxconn added start pling 10/05/2012 */
437    /* Before we turn off USB LED 2, check whether we have
438     * a printer connected or not.
439     */
440    if (!has_usb2_dev)
441    {
442        fp = fopen("/proc/NetUSB/1/device", "r");
443        if (fp)
444        {
445            memset(line, 0, sizeof(line));
446            fgets(line, sizeof(line), fp);
447            fclose(fp);
448            if (strlen(line) > 2)
449            {
450                printf("%s: USB LED2 on!\n", __FUNCTION__);
451                has_usb2_dev = 1;
452            }
453        }
454    }
455    /* Foxconn added end pling 10/05/2012 */
456
457#if (defined GPIO_EXT_CTRL) /* WNDR4000 */
458    if (has_usb2_dev)
459        system("gpio usbled 1");
460    else
461        system("gpio usbled 0");
462#else
463    fd = open("/dev/wps_led", O_RDWR);
464    if (fd >= 0) {
465        rtn_val = 3;
466        if (has_usb2_dev)
467        {
468            ioctl(fd, USB2_LED_STATE_ON, 1);
469            rtn_val = 4;
470        }
471        else
472        {
473            ioctl(fd, USB2_LED_STATE_OFF, 1);
474            rtn_val = 5;
475        }
476        close(fd);
477    }
478#endif /* GPIO_EXT_CTRL */
479    /* foxconn wklin modified end ,01/19/2011 */
480    return rtn_val;
481} /* usb2_led() */
482
483int usb_dual_led(void)
484{
485    int rtn_val = 0;
486
487    usb1_led();
488    usb2_led();
489
490    return rtn_val;
491} /* usb_dual_led() */
492#else /* WNDR4500REV */
493
494int usb_led(void)
495{
496    int has_usb_dev = 0;
497    int fd;
498    FILE *fp = NULL;
499    char line[250] = "";
500
501    fp = fopen("/proc/mounts", "r");
502    if (fp != NULL) {
503        while (fgets(line, 200, fp) != NULL) {
504            if (strstr(line, "/tmp/mnt/usb") != NULL) {
505                has_usb_dev = 1;
506                break;
507            }
508        }
509        fclose(fp);
510    }
511    /* foxconn wklin modified start, 01/19/2011 @ USB LED for WNDR4000 */
512#if (defined GPIO_EXT_CTRL) /* WNDR4000 */
513    if (has_usb_dev)
514        system("gpio usbled 1");
515    else
516        system("gpio usbled 0");
517#else
518    fd = open("/dev/wps_led", O_RDWR);
519    if (fd >= 0) {
520        if (has_usb_dev)
521            ioctl(fd, USB_LED_STATE_ON, 1);
522        else
523            ioctl(fd, USB_LED_STATE_OFF, 1);
524        close(fd);
525    }
526#endif /* GPIO_EXT_CTRL */
527    /* foxconn wklin modified end ,01/19/2011 */
528    return 0;
529}
530#endif /* WNDR4500REV */
531/* Foxconn added end, Wins, 04/11/2011 */
532#endif
533/* Foxconn add end pling 02/05/2010*/
534
535int usb_mount(void)
536{
537    char source[128];
538    char target[128];
539    char buf[128];
540    int i;
541    int rval;
542
543    /*foxconn add start, @mount approved devices, water, 05/11/2009*/
544    int index = 0;
545    FILE *fp = NULL;
546    char line[150] = "";
547    char *ptmp = NULL;
548    char vendor[32] = "";
549    char model[32] = "";
550    int  scsi_host_num = -1;
551    int usb_dev_approved[26] = {0};
552    char approved_usb[20][80] = {0};
553    int not_approved_index;
554
555    /* Foxconn added start pling 09/16/2009 */
556    int last_scsi_host_num = -1;
557    /* Foxconn added end pling 09/16/2009 */
558
559    sleep(3);   /* pling added 06/04/2009, add this delay seems to make mount more robust. */
560
561    if (nvram_match("enable_any_usb_dev", "0") )
562    {
563        for (i=0; i<20; i++)
564        {
565            sprintf(line, "approved_usb_%d", i);
566            strcpy(buf, nvram_safe_get(line));
567            if (strlen (buf) != 0)
568            {
569                sscanf(buf, "%*[^+]+%[^+]+%*[^+]", approved_usb[i]);
570            }
571        }
572
573        fp = fopen("/proc/scsi/scsi", "r");
574        if (fp != NULL)
575        {
576            while (fgets(line, 150, fp) != NULL)
577            {
578                if (strncmp(line, "Host: scsi", strlen("Host: scsi")) == 0)
579                {
580                    sscanf(line, "Host: scsi%d %*s", &scsi_host_num);
581
582                    /* Foxconn added start pling 09/16/2009 */
583                    /* Handle multi-lun devices */
584                    if (scsi_host_num == last_scsi_host_num)
585                    {
586                        /* Keep the same "approved"/"not-approved" status
587                         * as the previous LUN
588                         */
589                        usb_dev_approved[index] = usb_dev_approved[index-1];
590                        index++;
591                        continue;
592                    }
593                    /* Foxconn added end pling 09/16/2009 */
594
595                    if ((fgets(line, 150, fp) == NULL))
596                        break;
597
598                    ptmp=strstr(line, "Vendor:");
599                    if ( ptmp != NULL )
600                    {
601                        sscanf(ptmp, "Vendor: %s %*s", vendor);
602                        if (0 == strcmp(vendor, "Model:") )
603                            strcpy(vendor, "");
604                    }
605                    ptmp=strstr(line, "Model:");
606                    if ( ptmp != NULL )
607                    {
608                        sscanf(ptmp, "Model: %s %*s", model);
609                        if (0 == strcmp(vendor, "Rev:") )
610                            strcpy(vendor, "");
611                    }
612                    sprintf(buf, "%s %s", vendor, model);
613
614                    for (i=0; i<20; i++)
615                    {
616                        if (strlen(approved_usb[i]) == 0 )
617                            continue;
618                        if (0 == strcmp(approved_usb[i], buf) )
619                        {/*this usb device was approved*/
620                            /* Foxconn modified start pling 09/16/2009 */
621                            /* Use 'index' to help check multi-LUN device */
622                            //usb_dev_approved[scsi_host_num] = 1;
623                            usb_dev_approved[index] = 1;
624                            /* Foxconn modified end pling 09/16/2009 */
625                            break;
626                        }
627                    }
628                    /* Foxconn added start pling 09/16/2009 */
629                    /* Multi-LUN devices */
630                    index++;
631                    last_scsi_host_num = scsi_host_num;
632                    /* Foxconn added end pling 09/16/2009 */
633                }
634            }
635            fclose(fp);
636        }
637    }
638    else
639    {
640        for (i=0; i<26; i++)
641            usb_dev_approved[i] = 1;
642    }
643    not_approved_index = 0;
644    /*foxconn add end, water, 05/11/2009*/
645
646    index = 0;      // pling added 09/16/2009, reset index for later use
647
648//------------------------------------------------------
649// action: add
650// 1. mount dev with vfat
651// 2. if mount ok, save data to nvram
652// 3. restart smb
653//------------------------------------------------------
654//fixme: no good. zzz@
655/* Foxconn modified start, Jenny Zhao, 04/13/2009 @usb dir */
656    char diskName;
657    int j = 0;
658    int max_partition = atoi(nvram_safe_get("usb_disk_max_part"));
659    for (diskName='a'; diskName<='z'; diskName++)   // try to mount sda->sdz
660    {
661        /*foxconn add start, @mount approved devices, water, 05/11/2009*/
662        if (usb_dev_approved[index++] == 1)/*this device was approved...*/
663            scsi_host_num = 1;
664        else
665            scsi_host_num = 0;
666        /*foxconn add end, water, 05/11/2009*/
667        for (i=0; i<=max_partition; i++)            // try to mount sdx or sdx1, ..., sdx5
668        {
669            //------------------------
670            //set up source
671            //------------------------
672            if (!i)
673                snprintf(source, 128, "/dev/sd%c", diskName);
674            else
675                snprintf(source, 128, "/dev/sd%c%d", diskName,i);
676
677            //------------------------
678            //set up target
679            //------------------------
680            /*foxconn modified start, water, 05/12/2009*/
681            /*some usb device not in approved device list, but the approved device page
682                need to show its info, so it need mount too. */
683            //snprintf(target, 128, "/tmp/mnt/usb%d/part%d", j, i);
684            if (scsi_host_num == 1)
685                snprintf(target, 128, "/tmp/mnt/usb%d/part%d", j, i);
686            else
687                snprintf(target, 128, "/tmp/mnt/not_approved%d", not_approved_index++);
688            /*foxconn modified end, water, 05/12/2009*/
689
690            //------------------------
691            //start mount with sync
692            //------------------------
693            //rval = mount(source, target, "vfat",  0, NULL);
694            rval = mount(source, target, "vfat",0, "iocharset=utf8"); //stanley add,09/14/2009
695            /* pling added start 05/07/2009 */
696            /* Use mlabel to read VFAT volume label after successful mount */
697            if (rval == 0)
698            {
699                /* Foxconn, add-start by MJ., for downsizing WNDR3400v2,
700                 * 2011.02.11. */
701#if (defined WNDR3400v2) || (defined U12H189)
702                snprintf(buf, 128, "/lib/udev/vol_id %s", source);
703#else
704                /* Foxconn, add-end by MJ., for downsizing WNDR3400v2,
705                 * 2011.02.11. */
706                snprintf(buf, 128, "/usr/bin/mlabel -i %s -s ::", source);
707#endif
708                system(buf);
709            }
710            /* pling added end 05/07/2009 */
711
712#ifdef USB_HOTPLUG_DBG//debug
713            snprintf(buf, 128, "echo \"mount %s %s with vfat, rval:%d, errno=%d\">>/tmp/usberr.log",
714                               source, target, rval, errno);
715            system(buf);
716#endif
717
718            /* pling added start 08/24/2009 */
719            /* To speed up mounting:
720             *  if sda is mounted, then don't bother about sda1, sda2...
721             */
722            if (rval == 0 && i == 0)
723                break;
724            /* pling added end 08/24/2009 */
725
726            if (rval<0 && errno == EINVAL)
727            {
728                int ret;
729                /* Use NTFS-3g driver to provide NTFS r/w function */
730                snprintf(buf, 128, "/bin/ntfs-3g -o large_read %s %s 2> /dev/null", source, target);
731                ret = system(buf);
732
733#ifdef USB_HOTPLUG_DBG//debug
734                snprintf(buf, 128, "echo \"try to mount %s @ %s with ntfs-3g\">>/tmp/usberr.log", source, target);
735                system(buf);
736#endif
737
738                /* Foxconn added pling 08/24/2009 */
739                /* To speed up mounting:
740                 *  if sda is mounted, then don't bother about sda1, sda2...
741                 */
742                if (WIFEXITED(ret))
743                {
744                    int status = WEXITSTATUS(ret);
745                    if (status == 0 && i == 0)
746                        break;
747                }
748                /* Foxconn added pling 08/24/2009 */
749            }
750        } //end of for
751        j++;
752    }//end of for(diskName = 'a';diskName < 'd';diskName++)
753    /* Foxconn modified end, Jenny Zhao, 04/13/2009 */
754    //nvram_set("usb_dev_no_change", "0");
755    /* send signal to httpd ,create link ,2009/05/07, jenny*/
756    //nvram_set("usb_mount_signal", "1");
757    system("killall -SIGUSR2 httpd");
758    /* USB LED on / off */
759#ifdef INCLUDE_USB_LED
760    /* Foxconn modified start, Wins, 04/11/2011 */
761#if defined(WNDR4500REV) || defined(R4500)
762    usb_dual_led();
763#else /* WNDR4500REV */
764    usb_led();
765#endif /* WNDR4500REV */
766    /* Foxconn modified end, Wins, 04/11/2011 */
767#endif
768
769    //sleep(5);   // Foxconn added pling 07/13/2009, wait for httpd to complete mount/umount processes
770    //nvram_set("usb_mount_signal", "0");
771    //acosNvramConfig_save();
772    return 0;
773}
774
775int usb_umount(void)
776{
777    int i, j;
778    int rval;
779    char path[128];
780    char buf[128];
781    //------------------------------------------------------
782    // action: remove
783    // remount devices
784    //------------------------------------------------------
785    //fixme: no good. zzz@
786    /* Foxconn modify start, Jenny Zhao, 04/13/2009 @usb dir */
787    char diskName;
788
789    /*foxconn add start, water, 05/12/2009*/
790    /*some usb device not in approved device list, but the approved device
791     page need to show its info, so it need mount too. */
792    for (j=0; j<20; j++)
793    {
794        snprintf(path, 128, "/tmp/mnt/not_approved%d", j);
795        umount2(path, MNT_DETACH);
796    }
797    /*foxconn add end, water, 05/12/2009*/
798
799    for (diskName='a', i=0; diskName<='z'; diskName++,i++)
800    {
801        snprintf(path, 128, "/tmp/mnt/usb%d/part0", i);
802
803        rval = umount2(path, MNT_DETACH);
804
805        for (j=0; j<16; j++)
806        {
807            snprintf(path, 128, "/tmp/mnt/usb%d/part%d", i, j);
808
809            rval = umount2(path, MNT_DETACH);
810            /* pling added start 05/07/2009 */
811            /* remove volume name file under /tmp after a successful umount */
812            if (rval == 0)
813            {
814                char filename[64];
815                if (j == 0)
816                    sprintf(filename, "/tmp/usb_vol_name/sd%c", diskName);
817                else
818                    sprintf(filename, "/tmp/usb_vol_name/sd%c%d", diskName, j);
819                unlink(filename);
820            }
821            /* pling added end 05/07/2009 */
822
823#ifdef USB_HOTPLUG_DBG//debug
824            snprintf(buf, 128, "echo \"umount %s, rval:%d \">>/tmp/usberr.log", path, rval);
825            system(buf);
826#endif
827        }
828    }
829    /* Foxconn modify end, Jenny Zhao, 04/13/2009 */
830    nvram_set("usb_dev_no_change", "0");
831    //acosNvramConfig_save();
832
833    usb_mount();
834    return 0;
835}
836int usb_hotplug(void)
837{
838    char *device, *interface;
839    char *action, *product;
840    char *type, *devfs;
841    int class, subclass, protocol;
842    char cmd[512];
843
844    /*foxconn add start, water, 05/11/2009*/
845    if (nvram_match("restart_usb", "1") )
846    {
847        usb_umount();
848        nvram_unset("restart_usb");
849        //eval("/usr/bin/setsmbftpconf");
850    }
851    /*foxconn add end, water, 05/11/2009*/
852
853    if (!(action = getenv("ACTION")) ||
854        !(type = getenv("TYPE")) ||
855        !(device = getenv("DEVICE")) ||
856        !(devfs = getenv("DEVFS")) ||
857        !(interface = getenv("INTERFACE")) ||
858        !(product = getenv("PRODUCT")))
859    {
860#ifdef USB_HOTPLUG_DBG//debug
861        sprintf(cmd, "echo \"return EINVAL;\" >> /tmp/hotAct\n");
862        system(cmd);
863#endif
864        return EINVAL;
865    }
866
867#ifdef USB_HOTPLUG_DBG//debug
868        sprintf(cmd, "echo \"ACTION=%s, TYPE=%s, DEVICE=%s, DEVFS=%s, INTERFACE=%s, PRODUCT=%s\" >> /tmp/hotAct\n",
869                action, type, device, devfs, interface, product);
870        system(cmd);
871#endif
872
873    sscanf(type, "%d/%d/%d", &class, &subclass, &protocol);
874    if (class == 0)
875    {
876        sscanf(interface, "%d/%d/%d", &class, &subclass, &protocol);
877    }
878    //set LED
879    //set_usb_led();/*No usb led in WNR3500U board, need further check.*/
880
881    //check Mass Storage for add action
882    /* Foxconn modified start pling 11/11/2009 */
883    /* We should mount all subclasses of Mass Storage class (8),
884     *  not just subclass 6 (Transparent SCSI).
885     */
886    //if (class == 8 && subclass == 6  && !strcmp(action, "add"))
887    if (class == 8 && !strcmp(action, "add"))
888    /* Foxconn modified end pling 11/11/2009 */
889    {
890        /*
891        sometimes usb_umount() not execute when unplug usb.
892        so before mount, we do umount firstly.
893        not sure, I think it need further test.
894        */
895        //usb_mount();
896        USB_LOCK();     // Foxconn added pling 07/13/2009
897        usb_umount();/*water, 11/06/2008*/
898        USB_UNLOCK();   // Foxconn added pling 07/13/2009
899    }
900    //check Mass Storage for remove action
901    /* Foxconn modified start pling 11/11/2009 */
902    /* We should un-mount all subclasses of Mass Storage class (8),
903     *  not just subclass 6 (Transparent SCSI).
904     */
905    //else if (class == 8 && subclass == 6  && !strcmp(action, "remove"))
906    else if (class == 8 && !strcmp(action, "remove"))
907    /* Foxconn modified end pling 11/11/2009 */
908    {
909        USB_LOCK();     // Foxconn added pling 07/13/2009
910        usb_umount();
911        USB_UNLOCK();   // Foxconn added pling 07/13/2009
912    }
913
914    //eval("/usr/bin/setsmbftpconf");
915#ifdef USB_HOTPLUG_DBG//debug
916    system("echo \"/usr/bin/setsmbftpconf\">>/tmp/usberr.log");
917#endif
918    return 0;
919}
920