blob: b35520404ed2ed03fb755e83cd340b944c5c41d8 [file] [log] [blame]
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Small test for gobi modem handles. Avoids many dependencies.
// Code liberally cribbed from gobi-modem-reset.c
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
#include "gobi/GobiConnectionMgmtAPI.h"
static void log(const char *format, ...) {
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
fputc('\n', stderr);
fflush(stderr);
vsyslog(LOG_INFO, format, args);
va_end(args);
}
/* Returns true if the supplied devid string is valid. Valid devid strings are
* of the form: [0-9]+ '-' [0-9]+ */
static bool isdevid(const char *devid)
{
const char *d = devid;
/* Check the part before the dash... */
if (!d || !isdigit(*d++))
return false;
while (*d && isdigit(*d))
d++;
/* ... the dash itself ... */
if (*d++ != '-')
return false;
/* ... and the part after the dash. */
if (!isdigit(*d++))
return false;
while (*d && isdigit(*d))
d++;
return *d == '\0';
}
static int reset(const char *dev)
{
char path[PATH_MAX];
int fd = -1;
int to_return = 1;
if (snprintf(path, sizeof(path), "%s/authorized", dev) == sizeof(path)) {
log("Could not build path");
goto done;
}
fd = open(path, O_WRONLY | O_TRUNC | O_NOFOLLOW);
if (fd < 0) {
log("Could not open authorized file: %s", path);
goto done;
}
log("deauthorizing: %s", path);
if (write(fd, "0", 1) != 1) {
log("write(0) failed: %d", errno);
goto done;
}
log("sleeping for 1 second");
sleep(1);
log("reauthorizing: %s", path);
if (write(fd, "1", 1) != 1) {
log("write(1) failed: %d", errno);
goto done;
}
to_return = 0;
done:
if (fd >= 0) {
close(fd);
}
return to_return;
}
static void usage(const char *progname)
{
fprintf(stderr, "Usage: %s <file | api> <usb-dev-id> <qcqmi-dev>\n",
progname);
fprintf(stderr, "\tExample: %s api 1-2 /dev/qcqmi0\n", progname);
fprintf(stderr, "To determine the usb dev id, run \n");
fprintf(stderr, "\tls -d /sys/bus/usb/drivers/{QCUSBNet2k,gobi}/*-*\n");
fprintf(stderr, "and use the string before the :\n");
}
struct DEVICE_ELEMENT {
char deviceNode[256];
char deviceKey[16];
};
// Connect to first modem present. Returns 0 on success.
int connect_modem()
{
const int MAX_MODEMS = 16;
ULONG rc;
DEVICE_ELEMENT devices[MAX_MODEMS];
BYTE num_devices = MAX_MODEMS;
rc = QCWWANEnumerateDevices(&num_devices,
(BYTE *) devices);
if (rc != 0) {
log("Could not enumerate: %d", rc);
return -1;
}
if (num_devices == 0) {
log("No devices found");
return -1;
}
rc = QCWWANConnect(devices[0].deviceNode, devices[0].deviceKey);
if (rc !=0) {
log("Could not QCWWANConnect to modem: %d", rc);
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
char usb_path[PATH_MAX];
bool use_qcwwan = 1;
openlog("gobi_handle_tester", LOG_PID, LOG_USER);
if (argc != 4) {
usage(argv[0]);
return 1;
}
if (getuid() != 0) {
fprintf(stderr, "This program must be run as root\n");
return 1;
}
int argument = 1;
const char *operation = argv[argument++];
const char *usb_device_id = argv[argument++];
const char *qmi_device_path = argv[argument++];
if (!isdevid(usb_device_id)) {
fprintf(stderr, "Could not parse device id %s\n", usb_device_id);
usage(argv[0]);
return 1;
}
if (strcmp(operation, "file") == 0) {
// Just open /dev/qcqmi0 as a file
use_qcwwan = 0;
} else if (strcmp(operation, "api") == 0) {
// Use QCWWANConnect to open a connection to the device
use_qcwwan = 1;
} else {
fprintf(stderr, "Could not understand operation: %s\n", operation);
usage(argv[0]);
return 1;
}
snprintf(usb_path,
sizeof(usb_path),
"/sys/bus/usb/devices/%s", usb_device_id);
log("operation: %s use_qcwwan: %d", operation, use_qcwwan);
log("USB path: %s", usb_path);
log("device path: %s", qmi_device_path);
int fd;
ULONG rc;
if (use_qcwwan) {
if (connect_modem() != 0) {
log("Failure connecting to modem");
return 4;
}
} else {
fd = open(qmi_device_path, O_RDWR);
if (fd < 0) {
fprintf(stderr, "Could not open device %s\n", qmi_device_path);
return 3;
}
}
if (reset(usb_path) != 0) {
log("Reset failed. Exiting");
return 6;
}
log("sleeping while waiting for kernel handles to expire");
for (int i = 0 ; i < 45; ++i) {
sleep(1);
fprintf(stderr, ".");
}
fputc('\n', stderr);
log("closing");
if (use_qcwwan) {
rc = QCWWANDisconnect();
if (rc != 0) {
log("Failed on disconnect: %d", rc);
}
} else {
rc = close(fd);
if (rc != 0) {
log("Failed on close: %d", rc);
}
}
log("exiting");
return 0;
}