/* * Copyright (C) 2006, Intel Corporation * * This file is part of the Linux-ready Firmware Developer Kit * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation;version 2.1 of the License. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../biostest.h" struct usb_dev { char device_name[128]; char link_target[PATH_MAX]; int marker; }; static GList *get_sysfs_list(void) { GList *list = NULL; struct usb_dev *usb; DIR *dir; struct dirent *entry; char path[PATH_MAX]; dir = opendir("/sys/bus/usb/devices"); if (!dir) return NULL; do { entry = readdir(dir); if (!entry) break; /* dotdot and other files we don't want */ if (strlen(entry->d_name)<5) continue; sprintf(path, "/sys/bus/usb/devices/%s/", entry->d_name); usb = malloc(sizeof(struct usb_dev)); assert(usb!=NULL); memset(usb, 0, sizeof(struct usb_dev)); strcpy(usb->device_name, entry->d_name); readlink(path, usb->link_target, PATH_MAX); list = g_list_append(list, usb); } while (1); closedir(dir); return list; } static void free_list(GList *list) { struct usb_dev *usb; GList *item; while (1) { item = g_list_first(list); if (!item) break; usb = (struct usb_dev*) item->data; free(usb); list = g_list_delete_link(list, item); } } static void mark_lists(GList *one, GList *two) { GList *item, *item2; struct usb_dev *usb,*usb2; /* first, mark both lists as unmarked */ item = g_list_first(one); while (item) { usb = (struct usb_dev*)item->data; usb->marker = 0; item = g_list_next(item); } item = g_list_first(two); while (item) { usb = (struct usb_dev*)item->data; usb->marker = 0; item = g_list_next(item); } /* Yes this is O(N^2). I suck. */ /* (or rather I'm too lazy to sort... otoh the list is sorted already anyway */ item = g_list_first(one); while (item) { usb = (struct usb_dev*)item->data; item2 = g_list_first(two); while (item2) { usb2 = (struct usb_dev*)item2->data; if (strcmp(usb->device_name, usb2->device_name)==0) { usb->marker = 1; usb2->marker = 1; break; } item2 = g_list_next(item2); } item = g_list_next(item); } } static void tone(int frequency, int duration) { FILE *file; int fd; uint32_t ioctlvalue; file = fopen("/dev/console", "w"); if (!file) return; fd = fileno(file); if (fd < 0) return; ioctlvalue = (duration << 16) | frequency; ioctl(fd, KDMKTONE, ioctlvalue); fclose(file); usleep(duration*1000); } static void handle_removals(GList *list) { GList *item; struct usb_dev *usb; item = g_list_first(list); while (item) { usb = (struct usb_dev*)item->data; if (!usb->marker) { tone(1000, 400); } item = g_list_next(item); } } static void test_storage(struct usb_dev *usb) { char driver[PATH_MAX]; char path[PATH_MAX]; DIR *dir; struct dirent *entry; FILE *file; /* first check if the driver is usb-storage */ sprintf(path, "/sys/bus/usb/devices/%s/driver", usb->device_name); readlink(path, driver, PATH_MAX); if (!strstr(driver,"usb-storage")) return; /* not usb storage */ /* give the thing and the kernel half a second to settle */ usleep(500000); dir = opendir("/sys/block"); if (!dir) return; do { char path[4096]; char buffer[4096]; entry = readdir(dir); if (!entry) break; if (entry->d_name[0]!='s') continue; if (entry->d_name[1]!='d') continue; sprintf(path,"/sys/block/%s/removable", entry->d_name); file = fopen(path, "r"); if (!file) continue; fgets(path, 4095, file); fclose(file); /* usb disks are removable */ if (path[0]!='1') continue; sprintf(path,"/sys/block/%s/device", entry->d_name); memset(buffer, 0, 4096); readlink(path, buffer, 4096); if (strstr(buffer, usb->device_name)==NULL) continue; sprintf(buffer, "/bin/mount /dev/%s1 /usbkey &> mountlog", entry->d_name); if (system(buffer)) { /* no luck, unpartitioned device */ sprintf(buffer, "/bin/mount /dev/%s /usbkey &> mountlog", entry->d_name); if (system(buffer)) continue; } system("cp /usr/share/LFDK/plugins/usbports.so /usbkey"); system("sync"); system("/bin/umount /usbkey &> /dev/null"); tone(2000, 1000); } while (entry); closedir(dir); } static void handle_additions(GList *list) { GList *item; struct usb_dev *usb; item = g_list_first(list); while (item) { usb = (struct usb_dev*)item->data; if (!usb->marker) { tone(2000, 400); test_storage(usb); } item = g_list_next(item); } } void do_manual_usb_test(void) { GList *existing_list; GList *new_list; int myHelloWin; newtComponent myHelloText, myHelloForm; int W,H; start_test("usbports", "USB ports", "This test is has two components: an interactive component and a non-interactive part. " "The non-interactive part runs during the general test phase of this tool, and runs a " "basic test on any USB storage device it can find. \n\n" "The interactive part of the test allows the tester to put in a USB key in each USB " "connector, one at a time, which then runs a brief test. This should validate connectivity " "and correct operation of all USB ports and bridges."); newtGetScreenSize(&W,&H); myHelloWin = newtOpenWindow(1+(W-55)/2, 1+(H-11)/2, 55, 11, "USB port test"); myHelloForm = newtForm(NULL,NULL,0); myHelloText = newtTextbox(3,2,52,8, 0); newtFormAddComponent(myHelloForm, myHelloText); newtTextboxSetText(myHelloText, "You can now insert and remove USB keys into \n" "all USB ports of this machine, one at a time.\n" "A tone sounds on insert and a different\n" "tone sounds on removal.\n\n" "Press any key to exit this test."); newtDrawForm(myHelloForm); newtRefresh(); existing_list = get_sysfs_list(); do { usleep(500*1000); new_list = get_sysfs_list(); mark_lists(existing_list, new_list); handle_removals(existing_list); handle_additions(new_list); free_list(existing_list); existing_list = new_list; if (SLang_input_pending(0)) break; } while (1); newtClearKeyBuffer(); newtPopWindow(); report_result("usbports", PASS, "USB ports test has been run", NULL, NULL); finish_test("usbports"); } void run_test(void) { /* start_test("usbports", "USB ports", "This test is has two components: an interactive component and a non-interactive part. " "The non-interactive part runs during the general test phase of this tool, and runs a " "basic test on any USB storage device it can find. \n\n" "The interactive part of the test allows the tester to put in a USB key in each USB " "connector, one at a time, which then runs a brief test. This should validate connectivity " "and correct operation of all USB ports and bridges."); finish_test("usbports"); */ register_interactive_test("USB port validation", do_manual_usb_test); }