Home · All Namespaces · All Classes · Grouped Classes · Modules · Functions |
Qt Extended includes an API that applications can use to control the USB gadget feature of a device. The default implementation that is provided utilizes the Linux USB gadget stack available in 2.6 kernel. There is a need to support alternative USB gadget stacks, either 3rd party stacks or older incompatible gadget stacks.
This tutorial walks you through the steps of implementing USB gadget provider classes for the USB gadget stack found on the Greenphone. The gadget stack on the Greenphone is a deprecated stack found in some versions of the 2.4 series Linux kernel.
In this tutorial we will override the default gadget provider classes by
The source code for this tutorial can be found in the server directory of the Greenphone device profile.
Qt Extended includes an API for accessing Ethernet, Storage and Serial USB gadgets. The Greenphone USB gadget stack provides support for Ethernet and Serial gadgets. In this tutorial we will demonstrate how to implement the provider class for the Ethernet gadget.
To implement an Ethernet provider class, subclass QUsbEthernetGadget and reimplement all of the virtual functions. The class declaration:
#include <QUsbEthernetGadget> class QUsbManager; class GreenphoneEthernetGadgetProvider : public QUsbEthernetGadget { Q_OBJECT public: GreenphoneEthernetGadgetProvider(const QString &group = QString(), QObject *parent = 0); ~GreenphoneEthernetGadgetProvider(); public slots: void setVendorId(const quint16 id); void setProductId(const quint16 id); void setVendor(const QByteArray &vendor); void setProduct(const QByteArray &product); void saveConfig(); void activate(); void deactivate(); void setRemoteMac(const QByteArray &mac); void setLocalMac(const QByteArray &mac); private: QUsbManager *m_manager; QByteArray m_defaultLocalMac; QByteArray m_defaultRemoteMac; void initFromConfig(); private slots: void loadModule(); void abort(); };
In the constructor we check whether the Ethernet gadget is active by parsing /proc/usbd, stored in the PeripheralController/Path setting. Because the Greenphone USB gadget stack does not provide a method of retrieving the configuration of the activated gadget, we always initialize the gadget from the configuration settings stored in the Usb.conf settings file.
GreenphoneEthernetGadgetProvider::GreenphoneEthernetGadgetProvider(const QString &group, QObject *parent) : QUsbEthernetGadget(group, parent, Server), m_manager(0) { QSettings settings("Trolltech", "Usb"); QString function = settings.value("PeripheralController/Path").toString(); setValue("gadget", QByteArray(GADGET_NAME)); QProcess tat; tat.start("tat", QStringList() << "remotemac"); tat.waitForFinished(-1); m_defaultRemoteMac = tat.readAllStandardOutput().trimmed(); tat.start("tat", QStringList() << "localmac"); tat.waitForFinished(-1); m_defaultLocalMac = tat.readAllStandardOutput().trimmed(); QFile file(function); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { initFromConfig(); setValue("active", false); return; } foreach (QByteArray line, file.readAll().split('\n')) { if (line.startsWith("Function: ")) { initFromConfig(); if (line.mid(10) == "Generic Network") setValue("active", true); else setValue("active", false); } } }
The Greenphone Ethernet gadget supports setting the USB vendor and product ids. Reimplement setVendorId() and setProductId() to store the new values in the Value Space.
void GreenphoneEthernetGadgetProvider::setVendorId(const quint16 id) { setValue("vendorId", id); } void GreenphoneEthernetGadgetProvider::setProductId(const quint16 id) { setValue("productId", id); }
Setting the USB vendor and product strings is not supported. Reimplement setVendor() and setProduct() to do nothing.
void GreenphoneEthernetGadgetProvider::setVendor(const QByteArray &) { } void GreenphoneEthernetGadgetProvider::setProduct(const QByteArray &) { }
Setting the local and remote MAC addresses is supported. Reimplement setRemoteMac() and setLocalMac() to store the new values in the Value Space.
void GreenphoneEthernetGadgetProvider::setRemoteMac(const QByteArray &mac) { setValue("remoteMac", mac); } void GreenphoneEthernetGadgetProvider::setLocalMac(const QByteArray &mac) { setValue("localMac", mac); }
The saveConfig() slot saves all of the configuration settings to the Usb.conf configuration file.
void GreenphoneEthernetGadgetProvider::saveConfig() { QSettings settings("Trolltech", "Usb"); settings.beginGroup(GADGET_NAME); QVariant v = value("productId"); if (v.isValid()) settings.setValue("ProductId", v.toUInt()); v = value("vendorId"); if (v.isValid()) settings.setValue("VendorId", v.toUInt()); v = value("localMac"); if (v.isValid() && v.toByteArray() != m_defaultLocalMac) settings.setValue("LocalMac", v.toString()); v = value("remoteMac"); if (v.isValid() && v.toByteArray() != m_defaultRemoteMac) settings.setValue("RemoteMac", v.toString()); settings.endGroup(); }
Before activating the Ethernet gadget we must ensure that no other gadget is active, deactivating it if there is an gadget already active. Because the call to QUsbGadget::deactivate() is asynchronous we do the actual activation of the Ethernet gadget upon receipt of the QUsbManager::deactivateCompleted() signal, or abort the activation if QUsbManager::deactivateAborted() is received.
void GreenphoneEthernetGadgetProvider::activate() { if (!value("active", false).toBool()) { if (!m_manager) m_manager = new QUsbManager; if (m_manager->canActivate(GADGET_NAME)) { loadModule(); } else { connect(m_manager, SIGNAL(deactivateCompleted()), this, SLOT(loadModule())); connect(m_manager, SIGNAL(deactivateAborted()), this, SLOT(abort())); m_manager->deactivateGadgets(); } } }
The loadModule() private slot activates the Ethernet gadget by loading the required kernel modules.
void GreenphoneEthernetGadgetProvider::loadModule() { QStringList args; args << "net_fd"; QVariant v = value("productId"); if (v.isValid()) args << "product_id=0x" + QString::number(v.toInt(), 16); v = value("vendorId"); if (v.isValid()) args << "vendor_id=0x" + QString::number(v.toInt(), 16); v = value("localMac"); if (v.isValid()) args << "local_mac_address=" + v.toString().remove(':'); v = value("remoteMac"); if (v.isValid()) args << "remote_mac_address=" + v.toString().remove(':'); qLog(USB) << "loading module" << args; if (QProcess::execute("/sbin/insmod", args) != 0) { abort(); return; } args.clear(); args << "bvd_bi"; qLog(USB) << "loading module" << args; if (QProcess::execute("/sbin/insmod", args) != 0) { qLog(USB) << "unloading module net_fd"; QProcess::execute("/sbin/rmmod net_fd"); abort(); } else { setValue("interface", "eth0"); setValue("active", true); qLog(USB) << "ethernet gadget activated"; QTimer::singleShot(500, this, SIGNAL(activated())); } }
The abort() private slot handles failed gadget activation.
void GreenphoneEthernetGadgetProvider::abort() { removeValue("interface"); qLog(USB) << "ethernet gadget activate failed"; emit activateFailed(); }
Reimplement the deactivate() slot to unload the Ethernet gadget modules.
void GreenphoneEthernetGadgetProvider::deactivate() { if (value("active", false).toBool()) { qLog(USB) << "unloading modules bvd_bi net_fd"; if (QProcess::execute("/sbin/rmmod bvd_bi net_fd") == 0) { setValue("active", false); removeValue("interface"); qLog(USB) << "ethernet gadget deactivated"; emit deactivated(); } else { qLog(USB) << "ethernet gadget deactivate failed"; emit deactivateFailed(); } } }
Helper function to load the Ethernet gadget configuration of the Usb.conf settings file.
void GreenphoneEthernetGadgetProvider::initFromConfig() { QSettings settings("Trolltech", "Usb"); settings.beginGroup(GADGET_NAME); QVariant v = settings.value("VendorId"); if (v.isValid()) setVendorId(v.toUInt()); else removeValue("vendorId"); v = settings.value("ProductId"); if (v.isValid()) setProductId(v.toUInt()); else removeValue("productId"); v = settings.value("RemoteMac"); if (v.isValid()) setRemoteMac(v.toByteArray()); else setRemoteMac(m_defaultRemoteMac); v = settings.value("LocalMac"); if (v.isValid()) setLocalMac(v.toByteArray()); else setLocalMac(m_defaultLocalMac); settings.endGroup(); }
The source code for the Greenphone Ethernet gadget provider is located in devices/greenphone/server/greenphoneethernetgadget.{cpp,h}.
The next step is to create a new Server Task that will instantiate each gadget provider. As the server task has no other function apart from instantiating the gadget providers we will use a static task.
class GreenphoneUsbGadgetTask { public: static void loadProviders(); };
The single member function loads all of the support gadget providers that it understands, and activates the default gadget if one is specified.
void GreenphoneUsbGadgetTask::loadProviders()
{
QSettings settings("Trolltech", "Usb");
settings.beginGroup("PeripheralController");
QList<QByteArray> supportedGadgets = settings.value("SupportedGadgets").toByteArray().split(',');
QByteArray defaultGadget = settings.value("DefaultGadget").toByteArray();
foreach (QByteArray gadget, supportedGadgets) {
if (gadget == "GreenphoneEthernet") {
GreenphoneEthernetGadgetProvider *gp = new GreenphoneEthernetGadgetProvider("Greenphone");
if (gadget == defaultGadget)
gp->activate();
/* } else if (gadget == "GreenphoneStorage") {
GreenphoneStorageGadgetProvider *gp = new GreenphoneStorageGadgetProvider("Greenphone");
if (gadget == defaultGadget)
gp->activate(); */
} else if (gadget == "GreenphoneSerial") {
GreenphoneSerialGadgetProvider *gp = new GreenphoneSerialGadgetProvider("Greenphone");
if (gadget == defaultGadget)
gp->activate();
}
}
}
Finally we register our task with the task system.
QTOPIA_STATIC_TASK(GreenphoneUsbGadget, GreenphoneUsbGadgetTask::loadProviders());
We need modify the Usb.conf settings file to disable the standard gadget providers and activate our alternative providers. This is done by removing the standard gadget providers from the SupportedGadgets setting and replacing them with the alternate implementation GreenphoneEthernet and GreenphoneSerial.
[PeripheralController] Path=/proc/usbd SupportedGadgets="GreenphoneEthernet,GreenphoneSerial" DefaultGadget=GreenphoneEthernet [GreenphoneEthernet] ProductId=2 VendorId=26214 RemoteMac=00:11:22:33:44:55 LocalMac=00:66:77:88:99:AA [GreenphoneSerial] ProductId=1 VendorId=26214
Copyright © 2009 Nokia | Trademarks | Qt Extended 4.4.3 |