Sunday, December 10, 2006

usb gadget

GadgetFS ... since not every developer wants to program in the kernel,
or rely specifically on the Linux kernel APIs, a user mode API is
available. An example user mode driver is usb.c. (It also needs
usbstring.c and usbstring.h.) Notice how the device is initialized by
writing its configuration and device descriptors to a file (such
as /dev/gadget/$CHIP), and how the endpoints are initialized in similar
ways (writing descriptors to /dev/gadget/$ENDPOINT). After initializing
them, just read or write to the files to transfer data; or to handle
events including control requests to retrieve string descriptors,
configure alternate settings, and implement class or vendor requests. On
Linux 2.6 AIO (Async I/O) support is available, helping user mode
drivers avoid i/o latencies and letting them stream data as quickly as
in-kernel drivers can stream it. Note that user mode gadget drivers do
not necesarily need to be licensed according to the GPL.

1. Build kernel with GadgetFS support
2. Build kernel with USB client chip, e.g net2272
3. root:/> mount -t gadgetfs gadgetfs /dev/gadget

Will create user space device node: /dev/gadget/net2272.

Thursday, December 07, 2006

SPI on Blackfin - 3

Data Structures
==================

------------------------------------------------
spi_device.control_datqa = spi_adc_chip_info;
spi_device.control_state = chip_data;
------------------------------------------------

include/linux/spi/spi.h:
------------------------
struct spi_device {
struct device dev;
struct spi_master *master;
u32 max_speed_hz;
u8 chip_select;
u8 mode;
#define SPI_CPHA 0x01 /* clock phase */
#define SPI_CPOL 0x02 /* clock polarity */
#define SPI_MODE_0 (0|0) /* (original MicroWire)
*/
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04 /* chipselect active
high? */
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire
*/
u8 bits_per_word;
int irq;
void *controller_state;
void *controller_data;
const char *modalias;
}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++

arch/blackfin/mach-bf537/boards/stamp.c
---------------------------------------

/* SPI ADC chip */
static struct bfin5xx_spi_chip spi_adc_chip_info = {
.ctl_reg = 0x1000,
.enable_dma = 1, /* use dma transfer with this chip*/
.bits_per_word = 16,
};

include/asm-blackfin/bfin5xx_spi.h:
-----------------------------------
/* spi_board_info.controller_data for SPI slave devices,
* copied to spi_device.platform_data ... mostly for dma tuning
*/
struct bfin5xx_spi_chip {
u16 ctl_reg;
u8 enable_dma;
u8 bits_per_word;
u8 cs_change_per_word;
u8 cs_chg_udelay;
};

+++++++++++++++++++++++++++++++++++++++++++++++++++++

arch/blackfin/mach-bf537/boards/stamp.c
----------------------------------------
static struct spi_board_info bfin_spi_board_info[] = {

{
.modalias = "bfin_spi_adc", /* Name of spi_driver for
this device */
.max_speed_hz = 8, /* actual baudrate is
SCLK/(2xspeed_hz) */
.bus_num = 1, /* Framework bus number */
.chip_select = 1, /* Framework chip select. */
.platform_data = NULL, /* No spi_driver specific config
*/
.controller_data = &spi_adc_chip_info,
},
}

include/linux/spi/spi.h
---------------------------

/* board-specific information about each SPI device */
struct spi_board_info {
/* the device name and module name are coupled, like
platform_bus;
* "modalias" is normally the driver name.
*
* platform_data goes to spi_device.dev.platform_data,
* controller_data goes to spi_device.controller_data,
* irq is copied too
*/
char modalias[KOBJ_NAME_LEN];
const void *platform_data;
void *controller_data;
int irq;

/* slower signaling on noisy or low voltage boards */
u32 max_speed_hz;

/* bus_num is board specific and matches the bus_num of some
* spi_master that will probably be registered later.
*
* chip_select reflects how this chip is wired to that master;
* it's less than num_chipselect.
*/
u16 bus_num;
u16 chip_select;

/* mode becomes spi_device.mode, and is essential for chips
* where the default of SPI_CS_HIGH = 0 is wrong.
*/
u8 mode;

/* ... may need additional spi_device chip config data here.
* avoid stuff protocol drivers can set; but include stuff
* needed to behave without being bound to a driver:
* - quirks like clock rate mattering when not selected
*/
};

++++++++++++++++++++++++++++++++++++++++++++++++++++++++

drivers/spi/spi.c
------------------
spi_register_master() -> scan_boardinfo() -> spi_new_device()

struct spi_device *__init_or_module
spi_new_device(struct spi_master *master, struct spi_board_info *chip)
{
struct spi_device *proxy;
struct device *dev = master->cdev.dev;
int status;

/* NOTE: caller did any chip->bus_num checks necessary */

if (!spi_master_get(master))
return NULL;

proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
if (!proxy) {
dev_err(dev, "can't alloc dev for cs%d\n",
chip->chip_select);
goto fail;
}
proxy->master = master;

<snip>
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
<snip>
/* drivers may modify this default i/o setup */
status = master->setup(proxy);
status = device_register(&proxy->dev);

<snip>

}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++

drivers/spi/spi_bfin5xx.c

struct chip_data {
u16 ctl_reg;
u16 baud;
u16 flag;

u8 chip_select_num;
u8 n_bytes;
u32 width; /* 0 or 1 */
u8 enable_dma;
u8 bits_per_word; /* 8 or 16 */
u8 cs_change_per_word;
u8 cs_chg_udelay;
void (*write) (struct driver_data *);
void (*read) (struct driver_data *);
void (*duplex) (struct driver_data *);
};

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

static inline void setup()
{

<snip>
/* Only alloc (or use chip_info) on first setup */
chip = spi_get_ctldata(spi);
if (chip == NULL) {
chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip)
return -ENOMEM;

chip->enable_dma = 0;
chip_info = spi->controller_data;
}

/* chip_info isn't always needed */
if (chip_info) {
chip->enable_dma = chip_info->enable_dma != 0
&&
drv_data->master_info->enable_dma;
chip->ctl_reg = chip_info->ctl_reg;
chip->bits_per_word = chip_info->bits_per_word;
chip->cs_change_per_word =
chip_info->cs_change_per_word;
chip->cs_chg_udelay = chip_info->cs_chg_udelay;
}
<snip>

<snip>
spi_set_ctldata(spi, chip);
<snip>
}

include/linux/spi/spi.h:
------------------------

static inline void spi_set_ctldata(struct spi_device *spi, void *state)
{
spi->controller_state = state;
}

Blog Archive