On Mi, 2011-01-19 at 01:46 +0000, Tony wrote: > I am excited about hearing the good news. > Could you show me when and where i can get the published code?
The code is public now. We decided to publish the whole development history of it instead of just the final state. The history contains useful information about why things were done and some code which did not end up in the final revision, but might still be useful in the future. Because of the number of patches, please get the code from: http://meego.gitorious.org/~pohly/meego-middleware/pohlys-buteo-mtp The "gadgetfs" branch was rebased against current "master". I verified that the tip of the branch compiles and passes some simple sanity checks (see below), but intermediate versions do not necessarily compile. Therefore I squashed all patches into one commit on the "master" branch of the repo above and suggest the following steps to update the official repo - if you agree with the changes, of course: 1. git checkout master 2. git remote add gadgetfs git://gitorious.org/~pohly/meego-middleware/pohlys-buteo-mtp.git 3. git fetch gadgetfs 4. git merge gadgetfs/master 5. git push origin master gadgetfs/gadgetfs Paul has written an extensive documentation for his work, see mts/transport/gadgetfs/README (also attached). There's obviously quite a bit of work still left to do, but it takes Buteo MTP to the level of "almost works in MeeGo", and therefore I suggest merging it right away. I've replicated Paul's setup with "mtp_test" running as root in a MeeGo chroot, talking via dummy_hcd to a normal Linux host (in my case, Debian Testing with a recompiled kernel for gadgetfs/dummy_hcd). gphoto and Nautilus detect the virtual MeeGo device and I was able to view a photo via MTP. However, there was a long delay between "click on photo in nautilus" and "mtp_test starts sending data", with debug output of mtp_test pointing towards some kind of communication problem during that delay. Paul also mentions running mtp-detect and that he was seeing failures; I haven't tried that myself yet. Does mtp-detect work in the setup that Nokia is using to test? Are there known failures? Here are some possible next steps (not necessarily in this order): 1. get the code merged 2. clean up debug logging: replace printf with Qt mechanism 3. change the gadgetfs transport code to always send ZLP (see discussion between Deepak and Paul) 4. make fsstorageplugin more configurable, or at least adapt to MeeGo paths 5. decide about kernel config: enable gadgetfs and dummy_hcd by default in MeeGo so that development can be done in MeeGo? 6. get mtp-detect working with mtp_test 7. fix permission problems when running as normal user inside msyncd A word of caution: I'll continue to work on this in the background, but like Paul I also got other things to do which are considered more important. If someone has spare cycles (inside our outside of Nokia +Intel), then this would be a good opportunity to get involved. -- Best Regards Patrick Ohly Senior Software Engineer Intel GmbH Open Source Technology Center Pützstr. 5 Phone: +49-228-2493652 53129 Bonn Germany
Gadgetfs-based USB transport for buteo-mtp: ----------------------------------------------------------------------- Description: These files comprise a (new) subclass of the MTPTransporter super-class. The new subclass is named "MTPTransporterGadgetfs". It implements the "device" end of USB transport completely in user-space by taking advantage of the "gadgetfs" interface supplied by the linux kernel (with suitable configuration option(s) selected). Briefly, gadgetfs makes an interface to the (singleton) USB device-controller chip driver appear as a name in a pseudo filesystem. Opening this device and writing suitable descriptor records causes bulk and interrupt endpoints to appear and become configured. Opening some of these and writing some more descriptors prepares these for I/O as USB logical pipes. The original opened usb-controller device remains used as "endpoint 0" for various overall control and status operations. All subsequent I/O operations and their meanings are subject to the protocol definition of whatever USB device class is being portrayed. Although a strong effort has been made to make these files readily re-usable for different USB device classes, these files are _not_ generic for just any old device class. They are specific to Media Transfer Protocol (MTP), which is a compatible extension of Picture Transfer Protocol (PTP). Class specific details show up in several ways: () A PTP/MTP specific constellation of endpoints is configured and opened when the device becomes connected: a bulk-out, a bulk-in, and an interrupt-in endpoint. The PTP/MTP protocol is defined to operate over these endpoints. This code simply forwards requests, responses, and events back and forth between the USB endpoints and higher software layers that interpret the PTP/MTP protocol. () PTP/MTP also defines several class-specific operations over the "control" endpoint (endpoint 0). The code interprets these directly. Adapting this code for a different USB device class would be a matter of opening and configuring a different constellation of bulk and interrupt endpoints as defined by that device class, and replacing with control-endpoint class-specific operation handler procedure with one appropriate for your new device class. Of course, you would also need to embed the class in a higher-level framework that implements your protocol over the bulk and interrupt endpoints. ----------------------------------------------------------------------- Design Notes: The QT-based high-level MTP framework in which this is embedded uses an "application event-loop" model to drive all its actions: the application consists of a single main thread that normally sits idly waiting for an event. When one comes along (from any of a variety of sources), it wakes up, handles it, and goes back to goes back to the central idle/wait point. This application event loop has to be triggered to wake up and handle USB packets when they arrive. Ordinarily the QT framework would provide convenient support for this. A QSocketNotifier could be created and applied to a file-descriptor such as a socket or one of the file-descriptors embodying the USB endpoints. Then two things (are supposed to) happen: () QSocketNotifier internally runs something like select(), poll(), or epoll() at its idle/wait point and dispatch the event-loop thread to a callback of your choice when I/O becomes available, and () Your file-descriptor is set to non-blocking (O_NONBLOCK) so that you can do a read or write without risk of blocking and hanging up the single event-loop process. However, as of kernel version 2.6.36, the file-descriptors handed out by the gadgetfs pseudo-filesystem for endpoints do _not_ handle select() or O_NONBLOCK properly (not really a bug, just a not-implemented-yet). Select() fires immediately and continuously regardless of the actual I/O readiness state, and a read() or write() will merrily block regardless of the setting of O_NONBLOCK. So QSocketNotifier doesn't work here. Accordingly, the MTPTransporterGadgetfs uses asynchronous I/O (which _is_ supported by gadgetfs) to implement non-blocking I/O and notifications. This is currently done only for "read" operations, since "write" operations are all expected to be responses that will be delivered promptly. The design is as follows: () When any endpoint is opened for reading, MTPTransporterGadgetfs posts one or more asynchronous IO control blocks with "read" opcodes at the file descriptor. () MTPTransporterGadgetfs uses one of the available asynchronous I/O interface mechanisms to get notified whenever an asynchronous I/O control block reaches the "completed" state. This happens independently of the main event-loop thread. When notified, the control-block is enqueued at a queue of completed reads for that endpoint and the main event-loop thread is triggered to activate a "ReadReady" callback. This activation happens through the signal/slot connection mechanism using the "QueuedConnection" type of connection, which can cross thread boundaries for later delivery. See the QObject::connect()-->Qt::ConnectionType documentation for details. () When the "ReadReady" callback is invoked in the normal event-loop thread, it dequeues the completed asynchronous I/O control block just as if it were doing a normal read and handles the read data as usual. When done with the data, and before returning to the main-loop, it re-posts the asynchronous IO control block again for another read just as at the beginning of time. There are two asynchronous I/O interface families as candidates for the underlying asynchronous I/O (both are ultimately built on the same underlying Linux syscall operations). Linux-native Asynchronous I/O (libaio.h and -laio) is very close to the underlying kernel interfaces, and would have been a better choice due to its more robust, efficient, scalable notification mechanism. However, libaio was not available in the mainstream MeeGo release at the time. The fall-back that is used as of 12-30-2010 is Posix Asynchronous I/O (aio.h and lrt). Posting asynchronous I/O blocks is straightforward as described, but notification posed some problems. As of this time, one of three mechanisms can be selected in the code by the setting of an enumeration variable (initialized at compile-time to COMPLETION_SUSPEND, the best of the three). The methods and their evaluation is as follows: () COMPLETION_SUSPEND: A thread is created when an endpoint is opened for "read". It normally sits in "aio_suspend()" waiting for the oldest asynch I/O block to complete. When it gets it, it enqueues it, causes the trigger to the main-loop thread, and waits on the next-oldest asynch I/O block. This works reliably, and costs on the order of a thread-context-switch for each delivered read. I have not had any problem with dropped/missed notifications. Some complexity is involved in bookkeeping the list of I/O blocks that are pending and cleaning up the thread and objects it will touch when it is time to stop/close endpoints. () COMPLETION_CALLBACK: The Asynch I/O control blocks are marked to have a particular callback function called in an independent thread context when the indicated I/O completes. This is completely reliable and is the simplest to implement and use. However, the underlying implementation spawns an entirely new thread for _every_ callback. This is a huge and undesirable amount of thread creation and destruction. It also raises the possibility that depending on scheduling, notifications all the way to the main-loop thread could be delivered out of order. This may or may not be possible or problematic depending on the protocol. () COMPLETION_SIGNAL: The Async I/O control blocks are marked to send a user-configurable Linux signal when the indicated I/O completes. Signals are handled by a callback in some unspecified thread context. The cost is on the order of a thread-context-switch for each delivered notification. There are some limits to what you can do in the "special" signal-handler thread context. Triggering the main-loop thread is ok. Blocking is not a good idea, nor is taking a long time. Unfortunately this method has a couple of big problems. Signals tend to interrupt system calls, especially reads. Interruption can be detected and the read retried, but this adds complexity and it would have to be done throughout the software layers. The worse problem is that signals have an intrinsic queue-depth limit in their implementation. When the limit is hit, signals are dropped (signals do not guarantee delivery). In practice this happens quite often since signal-generating events tend to cascade together. Using this method led to chronic hangs due to lost signals and missing I/O completion notification. ----------------------------------------------------------------------- Running/Testing it: The kernel you use should be built with "gadgetfs" enabled (this does _not_ seem to be the usual default). In addition, it is very helpful at least initially to select the "dummy_hcd" host-controller driver instead of a driver for a "real" USB device-controller. The "dummy_hcd" driver presents itself as both a host-controller interface and a device-controller interface. Internally these are looped back and forth to each other. This lets you test entirely on a single system without even any (rare) device-controller hardware present. Subsequent instructions assume dummy_hcd, although only small changes are needed to use something else. Although not required, the "libmtp" family of packages is useful for testing. I had to modify these (as described below) to know about the "idVendor" and "idProduct" values in its list of MTP devices it knows about. Include the following packages (currently available in MeeGo:1.1:Core): libmtp libmtp-debuginfo (not strictly required) libmtp-devel libmtp-examples (important, contains all the test programs) The "buteo-mtp" family of packages (with MTPTransporterGadgetfs integrated) can be built into a MeeGo image or uploaded and installed separately. Include the following: buteo-mtp buteo-mtp-debuginfo buteo-mtp-devel buteo-mtp-tests (important, contains mtp_test: the MTP responder) One-time preparation of the system after installing buteo-mtp rpms: () mkdir /home/user () cp /usr/share/mtp/deviceinfo.xml /home/user/.mtpdeviceinfo.xml () mkdir /home/user/MyDocs () cp /usr/lib/mtp/libfsstorage.so /usr/share/mtp The need for that last is probably a packaging bug (? library installed/expected in different places), but it's outside the scope of this MTP/USB/gadgetfs transport project. By the way, MyDocs is where your MTP content lives. Then each time you boot the system and want to run an mtp responder: () mkdir /dev/gadget () mount -t gadgetfs none /dev/gadget () /usr/bin/mtp_test By this time MTPTransporterGadgetfs is rugged enough that it usually does not leave endpoints "in-use" so it can be run again without a re-boot after crash or killing it. Do "ls /dev/gadget" to check. If you see just "dummy_hcd" (or your chosen driver) you're probably ready to re-run. If not, try "killall mtp_test". If all else fails, reboot and start over from "mkdir /dev/gadget". Depending on what you included in your system build, there are a couple of daemons that will recognize your new "device" when you run mtp_test and grab it to interact with it. These can be helpful or an annoyance. If you want to keep these out of the way, do "ps aux" and then "killall <prog>" where <prog> is anything that looks like gvfsd or gvfs-gphoto2-<something>. The "Banshee" media player seems to recognize MTP and try to interact with it. The best quick-and-dirty go/no-go test is as follows: () mtp_test in another window: () lsusb You should see a device with the fake device ID I picked: "dead:f00d". () lsusb -v The mtp_test window should print a bunch of lines reporting string retrieval. The output of the command should show an expanded listing for this device ID, with strings such as "iManufacturer" filled in with text ("Linux Community" in this case). A much more extensive test: () mtp_test in another window: () mtp-detect The mtp_test window shows a huge amount of activity about zillions of commands executed. The mtp-detect window shows reams and reams of information about what options are supported. Note that this reports some problems, some of which I believe to be in buteo-mtp, some of which I believe to be in mtp-detect. Note that libmtp uses two semi-bogus strategies to recognize MTP devices: () They have an idVendor:idProduct pair that's in its list, or () One of the property strings retrieved matches a (patented?) pattern that Microsoft was using for MTP before MTP got granted its own class identifier by the USB standards body. They are _not_ using what should be a reliable test: () Make sure the device class is PTP () Make sure the "vendor extension ID" is FFFFFFFF, as defined for the MTP extension. Moreover, as of now the buteo-mtp MTP responder uses "6" as the vendor extension ID, so this wouldn't work anyway. The result of all this is that the easiest way to get libmtp's tests (such as mtp-detect) to work with this for now was to patch it to know about our fake idVendor:idProduct pair. Briefly, the relevant part of this patch is: >From 66f35645c27df84fa8ed9122012b1a5577cfb2d8 Mon Sep 17 00:00:00 2001 From: Paul Drews <paul.dr...@intel.com> Date: Tue, 28 Dec 2010 11:24:16 -0800 Subject: [PATCH] Add experimental buteo-mtp stack diff --git a/src/music-players.h b/src/music-players.h index ce5c4de..3ea0596 100644 --- a/src/music-players.h +++ b/src/music-players.h @@ -805,3 +805,8 @@ * Other strange stuff. */ { "Isabella", 0x0b20, "Her Prototype", 0xddee, DEVICE_FLAG_NONE } + + /* + * Experimental USB MTP stack for buteo-mtp + */ + { "Intel", 0xdead, "Buteo-MTP stack", 0xf00d, DEVICE_FLAG_NONE } >From 5c7c097b5dd1a65555fb268a64c03df404326383 Mon Sep 17 00:00:00 2001 From: Paul Drews <paul.dr...@intel.com> Date: Tue, 28 Dec 2010 11:27:27 -0800 Subject: [PATCH] Fix comma separaters in list diff --git a/src/music-players.h b/src/music-players.h index 3ea0596..7caa8fb 100644 --- a/src/music-players.h +++ b/src/music-players.h @@ -804,9 +804,9 @@ /* * Other strange stuff. */ - { "Isabella", 0x0b20, "Her Prototype", 0xddee, DEVICE_FLAG_NONE } + { "Isabella", 0x0b20, "Her Prototype", 0xddee, DEVICE_FLAG_NONE }, /* * Experimental USB MTP stack for buteo-mtp */ - { "Intel", 0xdead, "Buteo-MTP stack", 0xf00d, DEVICE_FLAG_NONE } + { "Intel", 0xdead, "Buteo-MTP stack", 0xf00d, DEVICE_FLAG_NONE }, WARNING: DO NOT use this idVendor:idProduct pair. You have to get real ones assigned by the USB compliance testing process. ----------------------------------------------------------------------- Status: () Working with MeeGo:1.1:Core->buteo-mtp version 0.0.37 as of 12-30-2010 () Not heavily tested but seems rugged enough, alpha-ish quality. () Not pushed in to build.meego.com at all anywhere yet. I need to run it past the open-source committee and legal first. ----------------------------------------------------------------------- Known Issues: () It makes zillions of printfs, both from the MTPTransporterGadgetfs and higher layers. Most of the ones in this layer are hard-coded in and can't simply be turned off. () idVendor:idProduct is something I made up. A real one needs to get assigned through the USB compliance community. () Need to get this through open-source release process and push it upstream. () According to my reading of the MTP spec, "Vendor Extension ID" should be FFFFFFFF to be flagged as an MTP extension of PTP (currently 6). MTPResponder issue. () GetObjectHandles with handle=ffffffff, depth=0 implementation wrong (?) should reply with root handle, not ffffffff. MTPResponder issue. Also a libmtp issue, they should ask for depth=ffffffff if they want all-depth. () Sending events (e.g., create file in /home/user/MyDocs) caused a hang in earlier tests, needs to be re-tested with more-robust async IO completion. () mtp_test gets a segfault on control-C late in destructor chain, within malloc somewhere, probably lurking stack-corruption problem from earlier. mtp_test catches SIGINT and tries to shutdown gracefully. () Responder doesn't support retrieval of device certificate. This is optional, but mtp-detect warns about it. () All three asynch io completion options are still in the code. Could clean out the bad ones. () Native linux libaio would be better than (currently used) Posix aio. Also, this would be cleaner to factor into a separate class that wraps around a file descriptor. () Mount location of "/dev/gadget" is hardcoded several places, should be factored and configurable. () Currently only tested with "dummy_hcd" device-controller driver. Several others are included, but untested, and many more were not included for expediency. Need to know the device-controller chip of the real hardware and put in support for that, top priority, also retrofit all other known device-controllers, bottom priority. () sendData() semantics of "isLastPacket" need to get clarified and documented. Probably this means that, if true, the function should not return until all data is delivered, even if doing buffering otherwise. () sendData() and possibly others, need to establish and meet a design-rule regarding handling of zero-length packets. Preferred: caller must know if a ZLP is required and must call sendData() with 0 bytes, and sendData() must really call the underlying write(). () sendDeviceOk(), sendDeviceBusy(), and sendDeviceTxCancelled() are called at times that have nothing to do with the protocol, and seriously break stuff if allowed to do any I/O. I turned these into no-ops. Need at least clarification of documentation of what these are for. () I can't find anywhere in the specifications that says how you choose endpoint address numbers. As far as I can tell, you just make them up (except for endpoint 0, which gets 0). () The definition of cancelTransaction in the MTPTransporter superclass is basically flawed since it doesn't carry the cancellation data: () 2-byte identifier for cancellation () 4-byte PIMA 15740 TransactionID The MTPResponder can't possibly cancel the transaction properly without this information. () Why are we doing 64Kb reads from bulk-out endpoint? Is anything ever going to be bigger than a packet?
_______________________________________________ MeeGo-dev mailing list MeeGo-dev@meego.com http://lists.meego.com/listinfo/meego-dev