nanoBSD Driver Build SUCCESS
Thomas D. Dean
tomdean at speakeasy.org
Wed May 30 00:50:09 UTC 2012
On 05/29/12 17:22, Thomas D. Dean wrote:
It works!.. lots to tune/change, but, the hard part functions
Thanks, phk for naonBSD and elan_mmcr.
Tom Dean
// lcd_socket.c - driver for the TS5700 spi and lcd
// 2012 05 27 tomdean - initial version
// GPL
#include <sys/param.h>
#include <sys/module.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/uio.h>
#include <sys/malloc.h>
#include <sys/ioccom.h>
#include <sys/mman.h> /* mmap */
#include <elan_mmcr.h>
#include <ts5700.h>
#include <lcd_socket.h>
MALLOC_DEFINE(M_LCD_SOCKET, "lcd_socket_buffer", "buffer for
lcd_socket_driver");
// all the work is done in ioctl
static d_read_t lcd_socket_read;
static d_write_t lcd_socket_write;
static d_ioctl_t lcd_socket_ioctl;
static struct cdevsw lcd_socket_cdevsw = {
.d_version = D_VERSION,
.d_read = lcd_socket_read,
.d_write = lcd_socket_write,
.d_ioctl = lcd_socket_ioctl,
.d_name = "lcd_socket"
};
static lcd_socket_t *lcd_socket;
static struct cdev *lcd_socket_dev;
//static FILE *lcd_fd;
//static struct elan_mmcr *lcd_mmcr;
static uint8_t reg, reg_up;
//extern uint16_t *elan_mmcr;
// struct uio {
// struct iovec *uio_iov; /* scatter/gather list */
// int uio_iovcnt; /* length of scatter/gather list */
// off_t uio_offset; /* offset in target object */
// ssize_t uio_resid; /* remaining bytes to copy */
// enum uio_seg uio_segflg; /* address space */
// enum uio_rw uio_rw; /* operation */
// struct thread *uio_td; /* owner */
// };
static int lcd_socket_write(struct cdev *dev, struct uio *uio, int ioflag)
{
int error = 0;
int amount;
int idx;
amount = MIN(uio->uio_resid,
(lcd_socket->buffer_size - 1 - uio->uio_offset > 0) ?
lcd_socket->buffer_size - 1 - uio->uio_offset : 0);
if (amount == 0)
return (error);
error = uiomove(lcd_socket->buffer, amount, uio);
if (error != 0) {
uprintf("Write failed.\n");
return (error);
}
uprintf(lcd_socket->buffer);
// send avr select command
// set lcd_data
outb(0x0072, AVR_SELECT_COMAND);
// lcd_en up
outb(0x0073, reg_up);
// lcd_en down
outb(0x0073, reg);
// assert chip select
// loop
uprintf("lcd socket write %d bytes\n",amount-1);
for (idx=0; idx<amount-1; idx++) {
// set spi data = lcd_socket->buffer[idx];
elan_mmcr->SSIXMIT = lcd_socket->buffer[idx];
// send the byte - wait until not busy then start xmit
while((elan_mmcr->SSISTA & SSI_BUSY) != 0);
elan_mmcr->SSICMD = TX_START|RX_START;
}
// de-assert chip select
return (error);
}
static int lcd_socket_read(struct cdev *dev, struct uio *uio, int ioflag)
{
int error = 0;
int amount;
int idx;
amount = MIN(uio->uio_resid,
(lcd_socket->length - uio->uio_offset > 0) ?
lcd_socket->length - uio->uio_offset : 0);
error = uiomove(lcd_socket->buffer + uio->uio_offset, amount, uio);
if (error != 0)
uprintf("Read failed.\n");
// send avr select datalog
// set lcd_data
outb(0x0072, AVR_SELECT_DATLOG);
// lcd_en up
outb(0x0073, reg_up);
// lcd_en down
outb(0x0073, reg);
// assert chip select
// set spi xmit = 0 - this is a read only
elan_mmcr->SSIXMIT = 0;
// loop
uprintf("lcd socket read %d bytes\n",amount);
for (idx=0; idx<lcd_socket->length; idx++) {
// start the spi transaction
elan_mmcr->SSICMD = TX_START|RX_START;
// wait for spi done
while((elan_mmcr->SSISTA & SSI_BUSY) != 0);
lcd_socket->buffer[idx] = elan_mmcr->SSIRCV;
}
// de-assert chip select
return (error);
}
static int lcd_socket_ioctl(struct cdev *dev,
u_long cmd,
caddr_t data,
int fflag,
struct thread *td)
{
int error = 0;
uint8_t lcd_data;
switch (cmd) {
case LCD_SOCKET_CMD:
lcd_data = *(uint8_t *)data;
// DO NOT ALLOW SETTING EITHER DATLOG OR COMAND POINTERS
if ((lcd_data == AVR_SELECT_DATLOG) | (lcd_data == AVR_SELECT_COMAND)) {
return EINVAL;
}
break;
default:
error = ENOTTY;
break;
}
return (error);
}
static int lcd_socket_modevent(module_t mod __unused, int event, void
*arg __unused)
{
int error = 0;
switch (event) {
case MOD_LOAD:
// make sure the lcd port is in the dio mode
reg = inb(0x007d);
reg &= ~_BV(4);
outb(0x007d, reg);
// set the lcd data bits to ouput
reg = inb(0x0073) | _BV(2) | _BV(3);
outb(0x0073, reg);
// the mmcr pointer is defined in the elan_mmcr driver
// which is built into the kernel
uprintf("elan mmcr %04x %02x\n",elan_mmcr->REVID, elan_mmcr->CPUCTL);
elan_mmcr->SSICTL = PHS_INV | CLK_INV | MSBF_ENB;
lcd_socket = malloc(sizeof(lcd_socket_t), M_LCD_SOCKET, M_WAITOK);
lcd_socket->buffer_size = 256;
lcd_socket->buffer = malloc(lcd_socket->buffer_size,
M_LCD_SOCKET, M_WAITOK);
lcd_socket_dev = make_dev(&lcd_socket_cdevsw, 0, UID_ROOT, GID_WHEEL,
0600, "lcd_socket");
uprintf("Lcd_Socket driver loaded.\n");
break;
case MOD_UNLOAD:
destroy_dev(lcd_socket_dev);
free(lcd_socket->buffer, M_LCD_SOCKET);
free(lcd_socket, M_LCD_SOCKET);
uprintf("Lcd_Socket driver unloaded.\n");
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}
DEV_MODULE(lcd_socket, lcd_socket_modevent, NULL);
More information about the freebsd-drivers
mailing list