1
votes

My question is going to be rather vague but I will try to explain as detailed as I can what I am trying to resolve.

Trying to learn Linux kernel USB stack I have started to think of making a simple USB driver for my Atmel evaluation board based on ARM M0+ MCU to run away from Windows tools (Visual Studio plugin).

I have spent few days learning kernel's USB API and come to conclusion of how to make this. My driver aims to make my board connected to PC through USB cable act like a simple USB flash drive. Making that I then can easily program it with a new version of firmware written by me.

I have found that I need to find out specific interface (I am talking about interface in terms of USB specification, not interface we used to use as a code abstraction) that holds an endpoint (pipe) responsible for interaction with flash memory. And then I can map it to character device and interact with it using standard I/O operations that are described in struct file_operations structure.

Simply using cat on /proc/* file descriptor that was created by USB Core subsystem I have investigated that interface responsible for interaction with flash memory holds bulk endpoint (likewise, this terms come from USB specification, CMIIAW) that act as a "descriptor". Linux kernel USB Core subsystem gives neat interfaces to talk to different kind of endpoints whether it control, interrupt, bulk or asynchronous endpoint.

Now I have come closer to my very question.

Also the main transfer unit in communication between two USB devices is abstraction called urb - you allocate it, you fill it, you send it to USB Core subsystem, you read it if it was IN type of urb and, finally, you free it. What is confusing for me and tightly related to my question is the next API include/linux/usb.h:

static inline void usb_fill_bulk_urb(struct urb *urb,
                                     struct usb_device *dev,
                                     unsigned int pipe,
                                     void *transfer_buffer,
                                     int buffer_length,
                                     usb_complete_t complete_fn,
                                     void *context)

Assume I have obtained an information from board's datasheet about where to write a program code. Let's say, we have 0x00100 - 0x10000 memory region. I will compile my code, obtain a binary and then using standard Linux tools or writing a simple user-space wrapper application I will use lseek to set file's offset to 0x00100 and write system call provided with a buffer (binary compiled previously) and it's length.

In kernel space, I will have to allocate urb in write system call handler, fill it with a buffer sent from user space and submit this urb to USB Core.

BUT I can not find a way how to specify an OFFSET set earlier by lseek. Do I miss something? Maybe I missed some concepts or, perhaps, I am watching in a wrong way?

2
The device has to be running some code (a bootloader), to handle the incoming request blocks. Atmel microcontrollers typically have SAM-BA. They already have free Linux tools to do what you describe, so I am unsure whether there is any documentation on the protocol used to talk to SAM-BA; I think that's what you'd need to find (or, observe by USB sniffing), to complete your driver.Nominal Animal
@NominalAnimal Yes, you are right. Write this as an answer and I will bump it and comment explaining what I found following your suggestion about SAM-BA.mesmerizingr
It is perfectly okay to answer and accept your own question, and in this case, I think it is quite warranted too. You should describe what you initially missed, and what your findings were. (I care about facts and helping, not about reputation or social stuff.) Keep in mind that future readers may find your question via a web search, trying to solve a similar problem, and if you can provide them with enough information that helps them solve theirs, that is surely worth a bit of effort on your part?Nominal Animal
@NominalAnimal Of course. I will make an answer later this evening.mesmerizingr
There's little reason to do this in the kernel. If it's really a USB Mass Storage device then the kernel's driver should handle it. Otherwise, talk to it in userspace using libusb or directly the userspace USB APIs. And if it's a broken mass storage device (for example like the first generation ST discovery boards), you might still want to talk to it in userspace after telling the kernel mass storage driver to ignore it.Chris Stratton

2 Answers

0
votes

When your embedded Linux device acts as a USB mass storage device, the flash as a peripheral on Linux device is unmounted, and the gadget driver is loaded. Linux then loses control to the flash, and now the PC connected to your Linux device fully controls the flash. This is because a flash as a USB device can only has one USb host.

The gadget driver works purely in kernel space. It does not receive or transmit data from/to user space. It calls vfs_read() and vfs_write() to access the files on the flash, with an field offset. The offset is got from the USB commands sent from your host - Windows PC.

0
votes

There is no way to specify offset using USB subsystem's API. I misunderstood whole conception of USB as communication protocol, unwise me. You must first learn underlying protocol your device uses to communicate with others.

If your device acts as a USB HID device then learning specification of how to exchange data with USB HID device is the way to go. If there is something proprietary then you can do nothing but reverse engineer it (listening USB packets with a sniffer on system where a driver for your device exists).

As for my board it has embedded debugger that serves as a communication module besides being debugger itself. Specifically, my device is equipped with EDBG and here is a link on description of protocol it uses for communication.