MMPTP

Author: Michael Minn <michael@michaelminn.com>

February 18, 2002


MMPTP, a kernel module and command line program for accessing images on PTP digital cameras.

1. Introduction

MMPTP is a Linux kernel module and command line program for accessing images from digital cameras using the PTP standard (Picture Transfer Protocol), formally known as PIMA 15740:2000.

While MMPTP has been coded to support the Kodak DX-3500, DC-4800, DC-240 and all other USB Imaging Class 1.0 PTP cameras, it has only been tested with the DX-3500. It also has only been tested under a standard workstation installation of Red Hat Linux 7.2 (2.4 kernel). The author welcomes contributions from anyone willing to test and/or modify the software with other PTP devices and/or other distributions of Linux.

MMPTP 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.

More information on PTP is available from the PIMA Standards Page and the PIMA PTP page.


2. Version History & Download

Version 2002.02.18: Initial release that compiles under Red Hat 7.2 and supports only the Kodak DX3500 camera.


3. Installation

MMPTP consists of a simple kernel module (mmptp.o) and a simple command line program (mmptp) to download information from the PTP device. Download a tarball from the version list above and AS SUPERUSER decompress the tarball and make install:

	tar -zxvf mmptp.2002.02.07.tar.gz
	cd mmptp
	make install

The make install will place the kernel module in the /lib/.../drivers/usb directory. The exact directory depends on the version of the kernel you are running. It places the command line executable file in /usr/local/bin.

The MMPTP device file (used by the command line program to exchange information with the kernel module) is defined in the Makefile with the constant MMPTP_DEVICE_FILE as /dev/usb/mmptp. Device files (nodes) each have unique "Major Numbers" that distinguish them from other devices and permit multiple files to point to the same device driver by using the same Major Number. MMPTP uses Major Number 181, defined with the constant MMPTP_MAJOR_NUMBER in the Makefile. This number was chosen arbitrarily and might conflict with another device driver on your system. If so, you can make uninstall, change the Makefile MMPTP_MAJOR_NUMBER to another unused major number, and recompile/reinstall.

You will also need to add the following line to the bottom of /etc/modules.conf so the MMPTP module to load when you try to access the device. This file is a cross-reference used by the kernel to determine what module should be loaded to support a given resource - in this case the NOTEMIDI devices you defined earlier with major number 80 which are handled by the NOTEMIDI module.

	alias char-major-181 mmptp

MMPTP can be uninstalled by typing "make uninstall" in the mmptp source code directory you created above. If you modified the /etc/modules.conf as described above, you will need to manually edit the fi


4. Operation

MMPTP is a command line program with a few simple but powerful commands. It is invoked by typing "mmptp" at a console or in a console window with exactly one option.

	mmptp -i | -s | -l | -L | -d

MMPTP will display a syntax message if more than one option or no options are given. Much of the device information is specific to the PTP protocol and not necessarily useful to the casual user. More information on the PTP protocol can be downloaded from the PIMA PTP page. Attempting to run MMPTP with no device connected will simply issue an error message that the host is down.

-i: Prints information about the connected device and can be used to verify that MMPTP is recognizing a device that has been connected properly. Some of this information is self-explanatory and some is PTP specific and not normally useful to the casual user.

-s: Prints information about specific storage media available on a device. With digital cameras, storage media includes the internal memory and any memory cards or sticks that can be connected to or inserted in the device. If a particular storage medium is not connected (e.g. a memory card is not inserted), MMPTP will simply list the medium as not connected. As with device info, some of this information is self-explanatory and some is PTP specific and not normally useful to the casual user.

-l: Lists images currently stored on the device in a short, useful format.

-L: Lists images currently stored on the device in a long, cumbersome format. As with device info, some of this information is self-explanatory and some is PTP specific and not normally useful to the casual user.

-d: Downloads all images from the device into the current working directory. Images are stored with a filename in the format YYYY-MM-DD_HH-MM-SS.jpg which explicitly indicates the date and time when the picture was taken. MMPTP does not use the internal filenames assigned by the device. There is no option for downloading only specific images - all images must be downloaded at once.


5. Implementation Notes

The following information is given for those who are interested in how MMPTP works and for those who are learning about working with the Linux USB subsystem and/or the USB PTP protocol.

Jphoto is another project for working with USB PTP devices. However, it requires Java(tm) and and the JUsb library. Wanting to avoid having to burden my modest laptop with Java and being dependent on libraries that might not exist in the future, I decided to write my own.

The Linux USB subsystem/API and the PTP protocol are both relatively simple but I have found them difficult to program due to limited documentation. This information is therefore provided to help ease the way for others. But, ultimately, the source code is the best explanation for how the software works.

5.1 Linux USB

Kernel modules can be used for a number of purposes, but are perhaps most valuable for device drivers. As such, they are kernel code that is executed when data is written/read from a device file. The best resource for module programming is the book, Linux Device Drivers by Alessandro Rubini and published by O'Reilly.

Device files are also called nodes, they are created with the mknod command and they are kept in the /dev directory. While device files are distinguished to normal users with text names (i.e. /dev/lp1) they are distinguished in the kernal by MAJOR NUMBER. Each kernel module handles all device files that have a specific major number. One kernel module can handle multiple major numbers, but different device files with the same major number must all be handled by a single kernel module.

There are two functions that must be provided in each kernel module: init_module(void), which is run when the module is loaded; and cleanup_module(void), which is run when the module is unloaded. In MMPTP, init_module() registers itself with the Linux file system and specifies the file operation functions that are called when the user accesses the device. init_module() also registers itself with the USB subsystem so that it's probe functions will be called whenever a new device is connected to determine whether it will serve that device. cleanup_module() deregisters itself from the file system and the USB subsystem.

When a new device is connected to the USB port, it identifies itself with a device descriptor that specifies numeric codes for the manufacturer and the specific device. The Linux USB subsystem then calls the probe functions for all registered USB device drivers to determine which (if any) of the loaded modules serves the newly connected device. If no driver is found, the device information is simply stored and no user interaction can take place with the device. Also, if a driver module is loaded later, the module's probe function is called for each currently connected (but unsupported) USB device. This permits the driver to be loaded either before or after the USB device is connected. There is also a disconnect function that is called when a USB device is disconnected. The probe and disconnect functions are specified when the driver is registered with the USB subsystem.

MMPTP's probe function is mmptp_probe() and its disconnect function is mmptp_disconnect(). mmptp_probe() is passed a device information structure when it is called by the USB subsystem. It checks the vendor code and product code against hard-coded values for the devices it supports. If a match is found, mmptp_probe() sets global variables with the information needed to communicate with the device while it is connected. mmptp_disconnect() then NULLs those global variables so no further communication can occur.

Communication with Linux USB block devices (like PTP cameras) is done with a block of data called a URB (universal resource block) through endpoints. Endpoints are similar to file descriptors in that data is either read from or written to endpoints. There are separate endpoints for output or input - they are never bidirectional.

When data is sent to a USB device, it is copied into a URB and the usb_submit_urb() function is called with a output endpoint. MMPTP then waits on a wait queue for a response. A callback function specified in the URB wakes up MMPTP and a status byte in the URB indicates whether the information was successfully sent to the device. Similarly, when reading, MMPTP submits a URB to an input endpoint and waits for a response that contains data sent from the device.

5.2 PTP Protocol

As with Linux USB, the formal documentation for the PTP Protocol is rather difficult to read for a novice. As a generalized and exhaustive standard, it proved difficult to determine exactly the specific USB PTP protocol for simple operations. It turns out to be relatively simple.

Information is exchanged in containers that may be sent across one or more URB's. If the contents of the container is too large for a single URB, it is sent in multiple successive URB's. The rule is that if a URB is received with it's maximum amount of data, a successive URB must be read to continue receiving data for a container. The final URB will either have less than the maximum amount of data or no data at all.

Containers are exchanged with a USB PTP device in transactions. A transaction consists of the write of a command (operation) container and read of a data container and a response code container or just a response code container. PTP transactions are always initiated by the computer and responded to by the USB device.

The MMPTP container structure is mmptp_container. A container consists of 12 bytes of header information followed by a variable length "payload". The header indicates the size of the container, the type of container (whether it is a command, a container of data or a container with a response), a code specifying the command or response status and a transaction ID.

Containers must be exchanged with the device within a session. MMPTP opens a session when it is invoked and closes the session when it completes execution. Sessions must have unique numeric identifiers and MMPTP uses the Linux time() integer to identify sessions. Containers sent between the computer and the USB device are given sequential numeric transaction ID's that start with 1 at the beginning of each session.

A PTP device will have one or more storage mediums which are accessed by numeric storage handles. On each storage medium, there will be zero or more image objects that are referenced by numeric object handles. Requests can be made to the device to return arrays of storage or object handles.

When an error occurrs (such as attempting to get information on an unconnected memory card), the PTP device will "stall" the endpoint. While there is a specific procedure for clearing the stall, I couldn't figure out how to make it work under Linux. usb_clear_halt() didn't work.

The Linux USB subsystem can only be accessed from kernel modules. There are existing libraries that provide indirect user access to the USB subsystem, but they are not currently part of standard Linux distributions. As such, MMPTP provides a simple kernel module for reading/writing containers from/to PTP devices. The MMPTP executable handles the formatting and manipulation of the container contents.

For example, to download images from the device, MMPTP uses the following procedure:

  1. Invoke a transaction to open a session.
  2. Invoke a transaction to get an array of storage ID's.
  3. For each connected storage ID, invoke a transaction to get the handles of the objects on that storage medium
  4. For each object handle, invoke a transaction to get the object information and a transaction to get the object data.
  5. Write the object data to individual files.