Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
28
drivers/l3/Kconfig
Normal file
28
drivers/l3/Kconfig
Normal file
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# L3 bus configuration
|
||||
#
|
||||
|
||||
menu "L3 support"
|
||||
|
||||
config L3
|
||||
tristate "L3 support"
|
||||
|
||||
config L3_ALGOBIT
|
||||
boolean "L3 bit-banging interfaces"
|
||||
depends on L3
|
||||
|
||||
config L3_BIT_SA1100_GPIO
|
||||
boolean "SA11x0 GPIO adapter"
|
||||
depends on L3_ALGOBIT && ARCH_SA1100
|
||||
|
||||
# i2c must come before this
|
||||
config BIT_SA1100_GPIO
|
||||
boolean
|
||||
depends on L3_BIT_SA1100_GPIO || I2C_BIT_SA1100_GPIO=y
|
||||
default y
|
||||
|
||||
config L3_BIT_S3C_GPIO
|
||||
boolean "S3C GPIO adapter"
|
||||
depends on L3_ALGOBIT && ARCH_S3C2410
|
||||
|
||||
endmenu
|
||||
9
drivers/l3/Makefile
Normal file
9
drivers/l3/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Makefile for the L3 bus driver.
|
||||
# Link order:
|
||||
# (core, adapters, algorithms, drivers) then clients
|
||||
|
||||
l3-$(CONFIG_L3_ALGOBIT) += l3-algo-bit.o
|
||||
l3-$(CONFIG_BIT_SA1100_GPIO) += l3-bit-sa1100.o
|
||||
l3-$(CONFIG_L3_BIT_S3C_GPIO) += l3-bit-s3c.o
|
||||
obj-$(CONFIG_L3) += l3-core.o $(l3-y) $(l3-drv-y)
|
||||
175
drivers/l3/l3-algo-bit.c
Normal file
175
drivers/l3/l3-algo-bit.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* L3 bus algorithm module.
|
||||
*
|
||||
* Copyright (C) 2001 Russell King, All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note that L3 buses can share the same pins as I2C buses, so we must
|
||||
* _not_ generate an I2C start condition. An I2C start condition is
|
||||
* defined as a high-to-low transition of the data line while the clock
|
||||
* is high. Therefore, we must only change the data line while the
|
||||
* clock is low.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/l3/l3.h>
|
||||
#include <linux/l3/algo-bit.h>
|
||||
|
||||
#define setdat(adap,val) adap->setdat(adap->data, val)
|
||||
#define setclk(adap,val) adap->setclk(adap->data, val)
|
||||
#define setmode(adap,val) adap->setmode(adap->data, val)
|
||||
#define setdatin(adap) adap->setdir(adap->data, 1)
|
||||
#define setdatout(adap) adap->setdir(adap->data, 0)
|
||||
#define getdat(adap) adap->getdat(adap->data)
|
||||
|
||||
/*
|
||||
* Send one byte of data to the chip. Data is latched into the chip on
|
||||
* the rising edge of the clock.
|
||||
*/
|
||||
static void sendbyte(struct l3_algo_bit_data *adap, unsigned int byte)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
setclk(adap, 0);
|
||||
udelay(adap->data_hold);
|
||||
setdat(adap, byte & 1);
|
||||
udelay(adap->data_setup);
|
||||
setclk(adap, 1);
|
||||
udelay(adap->clock_high);
|
||||
byte >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a set of bytes to the chip. We need to pulse the MODE line
|
||||
* between each byte, but never at the start nor at the end of the
|
||||
* transfer.
|
||||
*/
|
||||
static void sendbytes(struct l3_algo_bit_data *adap, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i) {
|
||||
udelay(adap->mode_hold);
|
||||
setmode(adap, 0);
|
||||
udelay(adap->mode);
|
||||
}
|
||||
setmode(adap, 1);
|
||||
udelay(adap->mode_setup);
|
||||
sendbyte(adap, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read one byte of data from the chip. Data is latched into the chip on
|
||||
* the rising edge of the clock.
|
||||
*/
|
||||
static unsigned int readbyte(struct l3_algo_bit_data *adap)
|
||||
{
|
||||
unsigned int byte = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
setclk(adap, 0);
|
||||
udelay(adap->data_hold + adap->data_setup);
|
||||
setclk(adap, 1);
|
||||
if (getdat(adap))
|
||||
byte |= 1 << i;
|
||||
udelay(adap->clock_high);
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a set of bytes from the chip. We need to pulse the MODE line
|
||||
* between each byte, but never at the start nor at the end of the
|
||||
* transfer.
|
||||
*/
|
||||
static void readbytes(struct l3_algo_bit_data *adap, char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i) {
|
||||
udelay(adap->mode_hold);
|
||||
setmode(adap, 0);
|
||||
}
|
||||
setmode(adap, 1);
|
||||
udelay(adap->mode_setup);
|
||||
buf[i] = readbyte(adap);
|
||||
}
|
||||
}
|
||||
|
||||
static int l3_xfer(struct l3_adapter *l3_adap, struct l3_msg msgs[], int num)
|
||||
{
|
||||
struct l3_algo_bit_data *adap = l3_adap->algo_data;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* If we share an I2C bus, ensure that it is in STOP mode
|
||||
*/
|
||||
setclk(adap, 1);
|
||||
setdat(adap, 1);
|
||||
setmode(adap, 1);
|
||||
setdatout(adap);
|
||||
udelay(adap->mode);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct l3_msg *pmsg = &msgs[i];
|
||||
|
||||
if (!(pmsg->flags & L3_M_NOADDR)) {
|
||||
setmode(adap, 0);
|
||||
udelay(adap->mode_setup);
|
||||
sendbyte(adap, pmsg->addr);
|
||||
udelay(adap->mode_hold);
|
||||
}
|
||||
|
||||
if (pmsg->flags & L3_M_RD) {
|
||||
setdatin(adap);
|
||||
readbytes(adap, pmsg->buf, pmsg->len);
|
||||
} else {
|
||||
setdatout(adap);
|
||||
sendbytes(adap, pmsg->buf, pmsg->len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that we leave the bus in I2C stop mode.
|
||||
*/
|
||||
setclk(adap, 1);
|
||||
setdat(adap, 1);
|
||||
setmode(adap, 0);
|
||||
setdatin(adap);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static struct l3_algorithm l3_bit_algo = {
|
||||
name: "L3 bit-shift algorithm",
|
||||
xfer: l3_xfer,
|
||||
};
|
||||
|
||||
int l3_bit_add_bus(struct l3_adapter *adap)
|
||||
{
|
||||
adap->algo = &l3_bit_algo;
|
||||
return l3_add_adapter(adap);
|
||||
}
|
||||
|
||||
int l3_bit_del_bus(struct l3_adapter *adap)
|
||||
{
|
||||
return l3_del_adapter(adap);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(l3_bit_add_bus);
|
||||
EXPORT_SYMBOL(l3_bit_del_bus);
|
||||
213
drivers/l3/l3-bit-s3c.c
Normal file
213
drivers/l3/l3-bit-s3c.c
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* linux/drivers/l3/l3-bit-sa1100.c
|
||||
*
|
||||
* Copyright (C) 2001 Russell King
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This is a combined I2C and L3 bus driver.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-algo-bit.h>
|
||||
#include <linux/l3/algo-bit.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/arch/regs-gpio.h>
|
||||
|
||||
#define NAME "l3-bit-s3c-gpio"
|
||||
|
||||
struct bit_data {
|
||||
unsigned int sda;
|
||||
unsigned int scl;
|
||||
unsigned int l3_mode;
|
||||
};
|
||||
|
||||
static int getsda(void *data)
|
||||
{
|
||||
struct bit_data *bits = data;
|
||||
return s3c2410_gpio_getpin(bits->sda);
|
||||
}
|
||||
|
||||
static DECLARE_MUTEX(l3_lock);
|
||||
#define LOCK &l3_lock
|
||||
|
||||
|
||||
/*
|
||||
* iPAQs need the clock line driven hard high and low.
|
||||
*/
|
||||
|
||||
static void l3_setscl(void *data, int state)
|
||||
{
|
||||
struct bit_data *bits = data;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (state)
|
||||
s3c2410_gpio_setpin(bits->scl, 1);
|
||||
else
|
||||
s3c2410_gpio_setpin(bits->scl, 0);
|
||||
|
||||
#if defined CONFIG_MACH_SMDK2443
|
||||
s3c2410_gpio_cfgpin(bits->scl, S3C2410_GPG2_OUTP);
|
||||
#elif defined CONFIG_MACH_SMDK2412
|
||||
s3c2410_gpio_cfgpin(bits->scl, S3C_GPB4_OUTP);
|
||||
#endif
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void l3_setsda(void *data, int state)
|
||||
{
|
||||
struct bit_data *bits = data;
|
||||
|
||||
if (state)
|
||||
s3c2410_gpio_setpin(bits->sda, 1);
|
||||
else
|
||||
s3c2410_gpio_setpin(bits->sda, 0);
|
||||
}
|
||||
static void l3_setdir(void *data, int in)
|
||||
{
|
||||
struct bit_data *bits = data;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
#if defined CONFIG_MACH_SMDK2443
|
||||
#if 0 //ryu
|
||||
if (in)
|
||||
s3c2410_gpio_cfgpin(bits->sda, S3C_GPG1_INP);
|
||||
else
|
||||
#endif
|
||||
s3c2410_gpio_cfgpin(bits->sda, S3C2410_GPG1_OUTP);
|
||||
#elif defined CONFIG_MACH_SMDK2412
|
||||
if (in)
|
||||
s3c2410_gpio_cfgpin(bits->sda, S3C_GPB3_INP);
|
||||
else
|
||||
s3c2410_gpio_cfgpin(bits->sda, S3C_GPB3_OUTP);
|
||||
#endif
|
||||
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void l3_setmode(void *data, int state)
|
||||
{
|
||||
struct bit_data *bits = data;
|
||||
|
||||
if (state)
|
||||
s3c2410_gpio_setpin(bits->l3_mode, 1);
|
||||
else
|
||||
s3c2410_gpio_setpin(bits->l3_mode, 0);
|
||||
}
|
||||
|
||||
static struct l3_algo_bit_data l3_bit_data = {
|
||||
.data = NULL,
|
||||
.setdat = l3_setsda,
|
||||
.setclk = l3_setscl,
|
||||
.setmode = l3_setmode,
|
||||
.setdir = l3_setdir,
|
||||
.getdat = getsda,
|
||||
.data_hold = 1,
|
||||
.data_setup = 1,
|
||||
.clock_high = 1,
|
||||
.mode_hold = 1,
|
||||
.mode_setup = 1,
|
||||
};
|
||||
|
||||
static struct l3_adapter l3_adapter_s3c= {
|
||||
.owner = THIS_MODULE,
|
||||
.name = NAME,
|
||||
.algo_data = &l3_bit_data,
|
||||
.lock = LOCK,
|
||||
};
|
||||
|
||||
static int __init l3_init(struct bit_data *bits)
|
||||
{
|
||||
l3_bit_data.data = bits;
|
||||
return l3_bit_add_bus(&l3_adapter_s3c);
|
||||
}
|
||||
|
||||
static void l3_exit(void)
|
||||
{
|
||||
l3_bit_del_bus(&l3_adapter_s3c);
|
||||
}
|
||||
|
||||
static struct bit_data bit_data;
|
||||
|
||||
static int __init bus_init(void)
|
||||
{
|
||||
|
||||
struct bit_data *bit = &bit_data;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
#if defined CONFIG_MACH_SMDK2443
|
||||
bit->sda = S3C2410_GPG1;
|
||||
bit->scl = S3C2410_GPG2;
|
||||
bit->l3_mode = S3C2410_GPG0;
|
||||
#elif defined CONFIG_MACH_SMDK2412
|
||||
bit->sda = S3C_GPB3;
|
||||
bit->scl = S3C_GPB4;
|
||||
bit->l3_mode = S3C_GPB2;
|
||||
#endif
|
||||
|
||||
if (!bit->sda)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Default level for L3 mode is low.
|
||||
*/
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
s3c2410_gpio_setpin(bit->l3_mode, 1);
|
||||
|
||||
s3c2410_gpio_setpin(bit->scl, 1);
|
||||
|
||||
s3c2410_gpio_setpin(bit->sda, 0);
|
||||
|
||||
#if defined CONFIG_MACH_SMDK2443
|
||||
s3c2410_gpio_cfgpin(bit->l3_mode, S3C2410_GPG0_OUTP);
|
||||
s3c2410_gpio_cfgpin(bit->sda, S3C2410_GPG1_OUTP);
|
||||
s3c2410_gpio_cfgpin(bit->scl, S3C2410_GPG2_OUTP);
|
||||
#elif defined CONFIG_MACH_SMDK2412
|
||||
s3c2410_gpio_cfgpin(bit->l3_mode, S3C_GPB2_OUTP);
|
||||
s3c2410_gpio_cfgpin(bit->sda, S3C_GPB3_OUTP);
|
||||
s3c2410_gpio_cfgpin(bit->scl, S3C_GPB4_OUTP);
|
||||
#endif
|
||||
|
||||
/* L3 gpio interface set */
|
||||
local_irq_restore(flags);
|
||||
|
||||
ret = l3_init(bit);
|
||||
if (ret)
|
||||
{
|
||||
|
||||
printk("l3 init failed \n");
|
||||
l3_exit();
|
||||
}
|
||||
printk("GPIO L3 bus interface for s3c, installed\n");
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static void __exit bus_exit(void)
|
||||
{
|
||||
l3_exit();
|
||||
}
|
||||
|
||||
module_init(bus_init);
|
||||
module_exit(bus_exit);
|
||||
203
drivers/l3/l3-core.c
Normal file
203
drivers/l3/l3-core.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* linux/drivers/l3/l3-core.c
|
||||
*
|
||||
* Copyright (C) 2001 Russell King
|
||||
*
|
||||
* General structure taken from i2c-core.c by Simon G. Vogl
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* See linux/Documentation/l3 for further documentation.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/l3/l3.h>
|
||||
|
||||
static DECLARE_MUTEX(adapter_lock);
|
||||
static LIST_HEAD(adapter_list);
|
||||
|
||||
static DECLARE_MUTEX(driver_lock);
|
||||
static LIST_HEAD(driver_list);
|
||||
|
||||
/**
|
||||
* l3_add_adapter - register a new L3 bus adapter
|
||||
* @adap: l3_adapter structure for the registering adapter
|
||||
*
|
||||
* Make the adapter available for use by clients using name adap->name.
|
||||
* The adap->adapters list is initialised by this function.
|
||||
*
|
||||
* Returns 0;
|
||||
*/
|
||||
int l3_add_adapter(struct l3_adapter *adap)
|
||||
{
|
||||
down(&adapter_lock);
|
||||
list_add(&adap->adapters, &adapter_list);
|
||||
up(&adapter_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* l3_del_adapter - unregister a L3 bus adapter
|
||||
* @adap: l3_adapter structure to unregister
|
||||
*
|
||||
* Remove an adapter from the list of available L3 Bus adapters.
|
||||
*
|
||||
* Returns 0;
|
||||
*/
|
||||
int l3_del_adapter(struct l3_adapter *adap)
|
||||
{
|
||||
down(&adapter_lock);
|
||||
list_del(&adap->adapters);
|
||||
up(&adapter_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct l3_adapter *__l3_get_adapter(const char *name)
|
||||
{
|
||||
struct list_head *l;
|
||||
|
||||
list_for_each(l, &adapter_list) {
|
||||
struct l3_adapter *adap = list_entry(l, struct l3_adapter, adapters);
|
||||
|
||||
if (strcmp(adap->name, name) == 0)
|
||||
return adap;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* l3_get_adapter - get a reference to an adapter
|
||||
* @name: driver name
|
||||
*
|
||||
* Obtain a l3_adapter structure for the specified adapter. If the adapter
|
||||
* is not currently load, then load it. The adapter will be locked in core
|
||||
* until all references are released via l3_put_adapter.
|
||||
*/
|
||||
struct l3_adapter *l3_get_adapter(const char *name)
|
||||
{
|
||||
struct l3_adapter *adap;
|
||||
int try;
|
||||
|
||||
for (try = 0; try < 2; try ++) {
|
||||
down(&adapter_lock);
|
||||
adap = __l3_get_adapter(name);
|
||||
if (adap && !try_module_get(adap->owner))
|
||||
adap = NULL;
|
||||
up(&adapter_lock);
|
||||
|
||||
if (adap)
|
||||
break;
|
||||
|
||||
if (try == 0)
|
||||
request_module(name);
|
||||
}
|
||||
|
||||
return adap;
|
||||
}
|
||||
|
||||
/**
|
||||
* l3_put_adapter - release a reference to an adapter
|
||||
* @adap: driver to release reference
|
||||
*
|
||||
* Indicate to the L3 core that you no longer require the adapter reference.
|
||||
* The adapter module may be unloaded when there are no references to its
|
||||
* data structure.
|
||||
*
|
||||
* You must not use the reference after calling this function.
|
||||
*/
|
||||
void l3_put_adapter(struct l3_adapter *adap)
|
||||
{
|
||||
if (adap && adap->owner)
|
||||
module_put(adap->owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* l3_transfer - transfer information on an L3 bus
|
||||
* @adap: adapter structure to perform transfer on
|
||||
* @msgs: array of l3_msg structures describing transfer
|
||||
* @num: number of l3_msg structures
|
||||
*
|
||||
* Transfer the specified messages to/from a device on the L3 bus.
|
||||
*
|
||||
* Returns number of messages successfully transferred, otherwise negative
|
||||
* error code.
|
||||
*/
|
||||
int l3_transfer(struct l3_adapter *adap, struct l3_msg msgs[], int num)
|
||||
{
|
||||
int ret = -ENOSYS;
|
||||
|
||||
if (adap->algo->xfer) {
|
||||
down(adap->lock);
|
||||
ret = adap->algo->xfer(adap, msgs, num);
|
||||
up(adap->lock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* l3_write - send data to a device on an L3 bus
|
||||
* @adap: L3 bus adapter
|
||||
* @addr: L3 bus address
|
||||
* @buf: buffer for bytes to send
|
||||
* @len: number of bytes to send
|
||||
*
|
||||
* Send len bytes pointed to by buf to device address addr on the L3 bus
|
||||
* described by client.
|
||||
*
|
||||
* Returns the number of bytes transferred, or negative error code.
|
||||
*/
|
||||
int l3_write(struct l3_adapter *adap, int addr, const char *buf, int len)
|
||||
{
|
||||
struct l3_msg msg;
|
||||
int ret;
|
||||
|
||||
msg.addr = addr;
|
||||
msg.flags = 0;
|
||||
msg.buf = (char *)buf;
|
||||
msg.len = len;
|
||||
|
||||
ret = l3_transfer(adap, &msg, 1);
|
||||
return ret == 1 ? len : ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* l3_read - receive data from a device on an L3 bus
|
||||
* @adap: L3 bus adapter
|
||||
* @addr: L3 bus address
|
||||
* @buf: buffer for bytes to receive
|
||||
* @len: number of bytes to receive
|
||||
*
|
||||
* Receive len bytes from device address addr on the L3 bus described by
|
||||
* client to a buffer pointed to by buf.
|
||||
*
|
||||
* Returns the number of bytes transferred, or negative error code.
|
||||
*/
|
||||
int l3_read(struct l3_adapter *adap, int addr, char *buf, int len)
|
||||
{
|
||||
struct l3_msg msg;
|
||||
int ret;
|
||||
|
||||
msg.addr = addr;
|
||||
msg.flags = L3_M_RD;
|
||||
msg.buf = buf;
|
||||
msg.len = len;
|
||||
|
||||
ret = l3_transfer(adap, &msg, 1);
|
||||
return ret == 1 ? len : ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(l3_add_adapter);
|
||||
EXPORT_SYMBOL(l3_del_adapter);
|
||||
EXPORT_SYMBOL(l3_get_adapter);
|
||||
EXPORT_SYMBOL(l3_put_adapter);
|
||||
EXPORT_SYMBOL(l3_transfer);
|
||||
EXPORT_SYMBOL(l3_write);
|
||||
EXPORT_SYMBOL(l3_read);
|
||||
Reference in New Issue
Block a user