Thursday, June 24, 2010

Linux i2c

My notes while reading Linux kernel i2c source code and the documentation.

  • implements the character devices for userspace, a generic, "remote controlled" i2c chip driver
  • ioctl to select slave
  • read()/write() for a subset of smbus operations
  • i2c-tools with library functions
i2c adapter

A host bus adapter instance
  • class - allow probing for slave devices in class: HWMON, TV, DDC, SPD
  • nr - 'id' number of instance
  • algo - operations to implement

exported API
  • i2c_transfer() - sequence of low level i2c operations
  • i2c_smbus_transfer() - sequence of high level smbus operations

i2c algorithm

operations to implement a type of host bus adapter: bitbang, philips bus controllers
  • master_xfer() - implement low level i2c transaction segment: operations to read or write bytes to/from i2c device
  • smbus_xfer() - implement high level SMbus access
  • functionality() - query available functionality: SMBUS support, 10bit addressing
master_xfer can be omitted for SMbus only access.
smbus_xfer can be omitted for generic SMbus implementation using low level master_xfer

i2c (chip) drivers

Driver for a type of i2c slave device on an i2c bus.
  • io expanders, power supply supervisors, light sensor, clock
driver operations
  • probe() - gets a client handle and id of device which is supposed to be present.
  • remove()
  • detect() - autodetect which type of device is present: fill in the name in board info.
  • ioctl
  • suspend/resume/shutdown

communicates with the slave device through i2c client API. Prefer using SMbus operations, wider support in bus adapters

i2c client

an instance of a slave device
  • connected to a certain adapter (bus)
  • at a certain address (?)
  • controlled by a driver
exported API
  • i2c_master[send|recv]() - individual low level i2c byte level read/write
  • i2c_smbus_[read|write]_byte_data() - individual high level smbus read/write

i2c board info

declaration of a slave device on a bus. i2c slave devices are not enumerated on the bus, layout must be known.

Alternative methods of setting up i2c slave devices

statically at arch_initcall time for platform
  • build an array to declare types of chips and their addresses
  • i2c_register_board_info()
dynamically at parent device init()
  • i2c_new_device()
  • i2c_new_probed_device() - probe a list of slave addresses if there's a device present
  • i2c_unregister_device()
run time detection from a haystack
  • implement detect() - by reading registers from the device to see if it's really there
  • automatically attempted when bus and driver classes match
  • should be avoided, slow and unsafe


a subset of i2c. "pseudocode" signatures for smbus operations:

void quick_command(u1 cmd)

u8 read_byte()
void write_byte(u8 data)

u8 read_byte_data(u8 addr)
void write_byte_data(u8 addr, u8 data)

u16 read_word_data(u8 addr)
void write_word_data(u8 addr, u16 data)

u8[n] read_block_data(u8 addr, u8 length)
void write_block_data(u8 addr, u8 length, u8 data[n])

smbus i2c extensions with no explicit count byte

u8[n] read_i2c_block_data(u8 addr, int n)
void write_i2c_block_data(u8 addr, u8 data[n], int n)

not implemented

u16 process_call(u8 addr, u16 input)
u8[n] block_process_call(u8 addr, u8 length, u8 data[n])
void host_notify(u8 addr, u16 data)

two comm byte block ops

u8[n] read_block_data(u16 addr, u8 length)
void write_block_data(u16 addr, u8 length, u8 data[n])

Existing slave chip drivers
Scattered around the drivers tree, mostly outside the i2c subdirectory. Search cross reference for i2c_client usage.
  • gpio extender
  • eeprom
  • hardware monitoring chips
  • video related devices
  • real time clocks
  • led dimmer
  • keypad
  • battery power
  • audio codec
  • miscellaneous

Thursday, June 17, 2010

LDD3 notes: Networking

My notes while reading Linux Device Drivers 3rd edition, network drivers.

General and setup

Network devices have no /dev entry point
  • different namespace
  • file operations don't make sense on network interface. Why? I think they could.

alloc_netdev variants alloc_[eth|fc|fddi|tr]dev
  • separate [ltalk|fc|fddi|hippi|tr]_setup
private data not a pointer to driver allocated data, but allocated along with the net_device.
  • supply size to allocate_netdev()
  • use netdev_priv(dev) to access the data
interface flags IFF_*
  • flags & IFF_DEBUG, enable debuggin via ioctl: netifdebug
  • IFF_UP change -> open()/stop()
  • any flag change -> set_multicast_list()
Features, interesting ones

NETIF_F_NO_CSUM - interface needs no checksums
NETIF_F_HW_CSUM - interface hardware does checksums
  • by default all socket buffers are in low memory
Networking device structure
  • jiffy timestamps for last tx/rx, tx watchdog timeout.


functions to control transmission from the networking system
  • netif_start_queue - at open()
  • netif_stop_queue - at stop() or should hard_start_xmit see insufficient buffers left
  • netif_wake_queue() - at tx_completion: same as start, but kicks the networking system back to work
  • netif_tx_disable() - similar to stop, for outside hard_start_xmit

Book suggests that hard_start_xmit() should free the skb at end. with real (dma capable) hardware, probably better free at tx completion to avoid copying.
Book demonstrates extending short packets on the stack - looks like a bad idea for real hardware.


Example deals with skb's allocated at atomic context for received packets. For real hardware it's probably easier and more efficient to preallocate the skb's and run dma right into them.

  • determine protocol, eth_type_trans()
  • mark ip_summed HW/NONE
  • update stats
  • netif_rx()

Temporary polling mode for high throughput. Bypass interrupt overheads.

  • hardware packet buffering
  • capability to disable only rx interrupt
at rx interrupt
  • disable further rx interrupts
  • netif_rx_schedule()
at poll()
  • loop receiving packets
  • don't exceed CPU packet budget, device packet quota
  • netif_receive_skb() instead of netif_rx()
  • netif_rx_complete() and return 0 if no more packets left
  • return 1 if there were packets left
Bypassess input_pkt_queue?

Link state
  • netif_carrier_[on|off|ok]()

  • networking layer by default reserves headroom it needs, at least 32 octets
  • drivers should reserve headroom to have IP header on aligned address (NET_IP_ALIGN)

head data tail end

| head | | tail |
| room | | room |

-----> ---->
pull put


-----> reserve ---->

Hardware address resolution

  • details of the physical layer header are to be encapsulated in the driver
  • ethernet-specific header has a common implementation via ether_setup()
  • neighbour -mechanism used to implement arp, not described in the book?

  • ioctl on a socket invokes protocol specific ioctl()
  • protocol delegates unknown ioctls to device, based on ifreq.ifrn_name
  • do_ioctl() with ifreq in kernel-space, cmd

MII support
book describes an obsolete interface. write an overview of the current code?

  • not to be confused with the NAPI polling interface
  • bootloader-like interruptless operation adapted through polling into software simulated interrupts

Net namespaces
not describe in the book, run across while reading vlan code
per namespace 'global' variables
[un]register_pernet_gen_device() to have a 'global variable' pointer identified by 'id'
net_assign_generic() to set pointer
net_generic() to get pointer

Saturday, June 12, 2010

Free UML tools

Excellent summary of freely available UML tools, with screenshots.

But it's missing the one I'm using the most:

Thursday, June 10, 2010

LDD3 notes: TTY

My notes while reading Linux Device Drivers 3rd edition, TTY drivers.

TTY drivers are a generic implementation of a serial port interface with loose coupling of hardware access and data formatting.

It is a char device composed of
  • tty core for user space char device interface
  • line discipline for data formatting
  • tty driver for hardware access

  • can be called from interrupt context.
  • must succeed for single byte write
write buffer treatment
  • put_char, flush_chars - start sending them, return right away
  • wait_until_sent - start sending, wait until done or timeout
  • flush_buffer - discard write buffered chars.


tty_insert_flip_char() for each char

  • whenever count reaches size
  • at the end of sequence

  • 38400,8n1 -style serial settings
  • handshake mechanism selection

  • access control lines
  • tty driver first, except break
  • fallback to inherit core functionality with -ENOICTLCMD
  • Get Line Status Register LSR: data, overrun, parity, framing, break...
  • Wait on MSR: change in CTS,DSR, ring, carrier..

  • rx flow control

  • tx enable/disable
write_wait queue - tty driver wakes up

tty open/close count example? what happens to tty filps on fork?

Tuesday, June 8, 2010

iMovie event library on a network drive, NAS

I was shocked to find that iMovie '09 would not allow storing event libraries on networked disks. The AFP volume would show up, but remain non-functional with a yellow exclamation sign.

There are plenty of instructions for hacking around the limitation with clumsy symbolic links. I discovered a much simpler approach, using an undocumented (?) setting built right into iMovie:"Allow Network Volumes".

Use at your own risk, try the following command in Terminal

defaults write -app iMovie allowNV -bool true

Mac Time Machine with Linux server

Finally, an easy way to have Time Machine accept a Linux server as a backup disk.

  • Upgrade to Ubuntu 10.4.
  • Install netatalk
  • Add option "tm" to a share in AppleVolumes.default config file.
No need to mess with
  • Manually created sparsebundles
  • Shoehorn settings like TMShowUnsupportedNetworkVolumes
The key is to have netatalk version 2.0.5 or above.

Thursday, June 3, 2010

LDD3 notes: DMA

My notes while reading Linux Device Drivers 3rd edition, Memory mapping and DMA.

Kernel addressing
  • Physical address
  • Logical Address
  • Virtual address
  • Bus address (physical address as understood by the DMA peripheral)
__pa() , __va() for low memory only


PFN - page frame number. (virtual or physical) address / page size

struct page
  • 'handle' to a page of memory.
  • page_address() macro to get virtual address, if mapped
  • kmap() kernel virtual address for any page in the system
  • may sleep, but has an atomic version

VMA - virtual memory area. a contiguous, homogeneous region of process virtual address space.
  • visible in /proc/pid/maps
  • nopage() - process accessed a missing page, go get it
  • vm_pgoff, offset in pages into the backing file
mm_struct - a list of virtual memory areas for a single process. threads may share one.

implementing mmap
  • remap_pfn_range(), once and for all ( io_remap_page_range() )
  • - reserved pages only: locked in memory, outside of memory management
  • implement vm_ops->nopage() and map page at a time to fill the holes
  • - can map regular ram pages
generic dma layer
  • encapsulates cache coherency, bus addressing and implements bounce buffering as a fallback
  • device.dma_set_mask() - how many address bits the device sees
  • cache (in)coherency: cpu won't see dma ram writes, dma ram reads won't see cpu writes
  • buffer allocation and bus addressing: dma_addr_t
  • "one shot" operation streaming mappings - preferred
  • dma_[un]map_single()
  • long standing coherent mappings
  • dma_{alloc|free}_coherent()
  • dma_pool_{create|alloc|free|destroy}()

scullp_vma_open, mapping count non-atomic?
vsyscall page?