/*
* ModemKicker - ZTE 626 USB GSM modem tool.
*
* Copyright (C) 2008 Mikhail Gusarov <dottedmag@dottedmag.net>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <usb.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#define ZTE_VENDOR 0x19d2
#define ZTE_PRODUCT_MF626 0x0031
#define ZTE_MF626_CONTROL_INTERFACE 0x01
#define ZTE_MF626_CONTROL_INTERFACE_SETTING 0x01
#define ZTE_MF626_CONTROL_ENDPOINT 0x02
#define MAGIC_STRING "AT+ZOPERTE=\"beeline\"\r\n"
#define MAGIC_STRING_INTERVAL 50
#define USB_TIMEOUT 200
int usb_bulk_pwrite(usb_dev_handle* dev, int ep, char* bytes, int size, int timeout)
{
int towrite = size;
while(towrite)
{
int written = usb_bulk_write(dev, ep, bytes, towrite, timeout);
if(written < 0)
return written;
bytes += written;
towrite -= written;
}
return size;
}
int main(void)
{
struct usb_bus* bus;
struct usb_device* device;
usb_dev_handle* dev = NULL;
usb_init();
usb_find_busses();
usb_find_devices();
for(bus = usb_busses; bus; bus = bus->next)
for(device = bus->devices; device; device = device->next)
if(device->descriptor.idVendor == ZTE_VENDOR
&& device->descriptor.idProduct == ZTE_PRODUCT_MF626)
{
dev = usb_open(device);
if(!dev)
{
perror("usb_open");
return 1;
}
break;
}
if(!dev)
{
fprintf(stderr, "Unable to find modem.\n");
return 2;
}
if(usb_claim_interface(dev, ZTE_MF626_CONTROL_INTERFACE) < 0)
{
if(errno == EBUSY)
{
char driver[256];
if(usb_get_driver_np(dev, ZTE_MF626_CONTROL_INTERFACE,
driver, sizeof(driver)) < 0)
{
perror("usb_get_driver_np");
return 1;
}
if(strcmp(driver, "onda") && strcmp(driver, "option"))
{
fprintf(stderr, "Unknown driver claimed the interface: %s\n",
driver);
return 1;
}
if(usb_detach_kernel_driver_np(dev, ZTE_MF626_CONTROL_INTERFACE) < 0)
{
perror("usb_detach_kernel_driver_np");
return 1;
}
if(usb_claim_interface(dev, ZTE_MF626_CONTROL_INTERFACE) < 0)
{
perror("usb_claim_interface");
return 1;
}
}
else
{
perror("usb_claim_interface");
return 1;
}
}
if(usb_set_altinterface(dev, ZTE_MF626_CONTROL_INTERFACE_SETTING) < 0)
{
perror("usb_set_altinterface");
return 1;
}
if(usb_clear_halt(dev, ZTE_MF626_CONTROL_ENDPOINT) < 0)
{
perror("usb_clear_halt");
return 1;
}
for(;;)
{
if(usb_bulk_pwrite(dev, ZTE_MF626_CONTROL_ENDPOINT,
MAGIC_STRING, strlen(MAGIC_STRING),
USB_TIMEOUT) < 0)
{
if(errno == ENODEV)
{
fprintf(stderr, "Modem was disconnected. Exiting.\n");
usb_close(dev);
return 0;
}
else if(errno == EAGAIN)
continue;
else
{
perror("usb_bulk_write");
usb_close(dev);
return 1;
}
}
sleep(MAGIC_STRING_INTERVAL);
}
}