Commit 486a45c2 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/i2c: do parsing of i2c-related vbios info in nouveau_i2c.c

Not much point parsing the vbios data into a struct which is only used once
to parse the data into another struct, go directly from vbios to
nouveau_i2c_chan.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 6b5a81a2
......@@ -720,116 +720,20 @@ static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
return dcb_entry;
}
static int
read_dcb_i2c_entry(struct drm_device *dev, int dcb_version, uint8_t *i2ctable, int index, struct dcb_i2c_entry *i2c)
{
uint8_t dcb_i2c_ver = dcb_version, headerlen = 0, entry_len = 4;
int i2c_entries = DCB_MAX_NUM_I2C_ENTRIES;
int recordoffset = 0, rdofs = 1, wrofs = 0;
uint8_t port_type = 0;
if (!i2ctable)
return -EINVAL;
if (dcb_version >= 0x30) {
if (i2ctable[0] != dcb_version) /* necessary? */
NV_WARN(dev,
"DCB I2C table version mismatch (%02X vs %02X)\n",
i2ctable[0], dcb_version);
dcb_i2c_ver = i2ctable[0];
headerlen = i2ctable[1];
if (i2ctable[2] <= DCB_MAX_NUM_I2C_ENTRIES)
i2c_entries = i2ctable[2];
else
NV_WARN(dev,
"DCB I2C table has more entries than indexable "
"(%d entries, max %d)\n", i2ctable[2],
DCB_MAX_NUM_I2C_ENTRIES);
entry_len = i2ctable[3];
/* [4] is i2c_default_indices, read in parse_dcb_table() */
}
/*
* It's your own fault if you call this function on a DCB 1.1 BIOS --
* the test below is for DCB 1.2
*/
if (dcb_version < 0x14) {
recordoffset = 2;
rdofs = 0;
wrofs = 1;
}
if (index == 0xf)
return 0;
if (index >= i2c_entries) {
NV_ERROR(dev, "DCB I2C index too big (%d >= %d)\n",
index, i2ctable[2]);
return -ENOENT;
}
if (i2ctable[headerlen + entry_len * index + 3] == 0xff) {
NV_ERROR(dev, "DCB I2C entry invalid\n");
return -EINVAL;
}
if (dcb_i2c_ver >= 0x30) {
port_type = i2ctable[headerlen + recordoffset + 3 + entry_len * index];
/*
* Fixup for chips using same address offset for read and
* write.
*/
if (port_type == 4) /* seen on C51 */
rdofs = wrofs = 1;
if (port_type >= 5) /* G80+ */
rdofs = wrofs = 0;
}
if (dcb_i2c_ver >= 0x40) {
if (port_type != 5 && port_type != 6)
NV_WARN(dev, "DCB I2C table has port type %d\n", port_type);
i2c->entry = ROM32(i2ctable[headerlen + recordoffset + entry_len * index]);
}
i2c->port_type = port_type;
i2c->read = i2ctable[headerlen + recordoffset + rdofs + entry_len * index];
i2c->write = i2ctable[headerlen + recordoffset + wrofs + entry_len * index];
return 0;
}
static struct nouveau_i2c_chan *
init_i2c_device_find(struct drm_device *dev, int i2c_index)
{
if (i2c_index == 0xff) {
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct dcb_table *dcb = &dev_priv->vbios.dcb;
if (i2c_index == 0xff) {
/* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
int idx = dcb_entry_idx_from_crtchead(dev), shift = 0;
int default_indices = dcb->i2c_default_indices;
int idx = dcb_entry_idx_from_crtchead(dev);
i2c_index = NV_I2C_DEFAULT(0);
if (idx != 0x7f && dcb->entry[idx].i2c_upper_default)
shift = 4;
i2c_index = (default_indices >> shift) & 0xf;
}
if (i2c_index == 0x80) /* g80+ */
i2c_index = dcb->i2c_default_indices & 0xf;
else
if (i2c_index == 0x81)
i2c_index = (dcb->i2c_default_indices & 0xf0) >> 4;
if (i2c_index >= DCB_MAX_NUM_I2C_ENTRIES) {
NV_ERROR(dev, "invalid i2c_index 0x%x\n", i2c_index);
return NULL;
i2c_index = NV_I2C_DEFAULT(1);
}
/* Make sure i2c table entry has been parsed, it may not
* have been if this is a bus not referenced by a DCB encoder
*/
read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
i2c_index, &dcb->i2c[i2c_index]);
return nouveau_i2c_find(dev, i2c_index);
}
......@@ -5595,10 +5499,6 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
uint16_t legacy_scripts_offset, legacy_i2c_offset;
/* load needed defaults in case we can't parse this info */
bios->dcb.i2c[0].write = NV_CIO_CRE_DDC_WR__INDEX;
bios->dcb.i2c[0].read = NV_CIO_CRE_DDC_STATUS__INDEX;
bios->dcb.i2c[1].write = NV_CIO_CRE_DDC0_WR__INDEX;
bios->dcb.i2c[1].read = NV_CIO_CRE_DDC0_STATUS__INDEX;
bios->digital_min_front_porch = 0x4b;
bios->fmaxvco = 256000;
bios->fminvco = 128000;
......@@ -5706,14 +5606,6 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi
bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset];
bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1];
bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2];
if (bios->data[legacy_i2c_offset + 4])
bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4];
if (bios->data[legacy_i2c_offset + 5])
bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5];
if (bios->data[legacy_i2c_offset + 6])
bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6];
if (bios->data[legacy_i2c_offset + 7])
bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7];
if (bmplength > 74) {
bios->fmaxvco = ROM32(bmp[67]);
......@@ -6549,10 +6441,6 @@ parse_dcb_entry(struct drm_device *dev, void *data, int idx, u8 *outp)
ret = parse_dcb15_entry(dev, dcb, conn, conf, entry);
if (!ret)
return 1; /* stop parsing */
read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
entry->i2c_index,
&dcb->i2c[entry->i2c_index]);
}
return 0;
......@@ -6562,7 +6450,6 @@ static int
parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
{
struct dcb_table *dcb = &bios->dcb;
u16 i2ctabptr = 0x0000;
u8 *dcbt;
dcbt = dcb_table(dev);
......@@ -6580,32 +6467,8 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
dcb->version = dcbt[0];
if (dcb->version >= 0x30) {
i2ctabptr = ROM16(dcbt[4]);
dcb->gpio_table_ptr = ROM16(dcbt[10]);
dcb->connector_table_ptr = ROM16(dcbt[20]);
} else
if (dcb->version >= 0x15) {
i2ctabptr = ROM16(dcbt[2]);
}
if (!i2ctabptr)
NV_WARN(dev, "No pointer to DCB I2C port table\n");
else {
dcb->i2c_table = &bios->data[i2ctabptr];
if (dcb->version >= 0x30)
dcb->i2c_default_indices = dcb->i2c_table[4];
/*
* Parse the "management" I2C bus, used for hardware
* monitoring and some external TMDS transmitters.
*/
if (dcb->version >= 0x22) {
int idx = (dcb->version >= 0x40 ?
dcb->i2c_default_indices & 0xf : 2);
read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
idx, &dcb->i2c[idx]);
}
}
dcb_outp_foreach(dev, NULL, parse_dcb_entry);
......@@ -6893,19 +6756,6 @@ nouveau_run_vbios_init(struct drm_device *dev)
return ret;
}
static void
nouveau_bios_i2c_devices_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->vbios;
struct dcb_i2c_entry *entry;
int i;
entry = &bios->dcb.i2c[0];
for (i = 0; i < DCB_MAX_NUM_I2C_ENTRIES; i++, entry++)
nouveau_i2c_fini(dev, entry);
}
static bool
nouveau_bios_posted(struct drm_device *dev)
{
......@@ -6942,6 +6792,10 @@ nouveau_bios_init(struct drm_device *dev)
if (ret)
return ret;
ret = nouveau_i2c_init(dev);
if (ret)
return ret;
ret = parse_dcb_table(dev, bios);
if (ret)
return ret;
......@@ -6984,5 +6838,5 @@ nouveau_bios_init(struct drm_device *dev)
void
nouveau_bios_takedown(struct drm_device *dev)
{
nouveau_bios_i2c_devices_takedown(dev);
nouveau_i2c_fini(dev);
}
......@@ -53,13 +53,6 @@ struct bit_entry {
int bit_table(struct drm_device *, u8 id, struct bit_entry *);
struct dcb_i2c_entry {
uint32_t entry;
uint8_t port_type;
uint8_t read, write;
struct nouveau_i2c_chan *chan;
};
enum dcb_gpio_tag {
DCB_GPIO_TVDAC0 = 0xc,
DCB_GPIO_TVDAC1 = 0x2d,
......@@ -166,10 +159,6 @@ struct dcb_table {
int entries;
struct dcb_entry entry[DCB_MAX_NUM_ENTRIES];
uint8_t *i2c_table;
uint8_t i2c_default_indices;
struct dcb_i2c_entry i2c[DCB_MAX_NUM_I2C_ENTRIES];
uint16_t gpio_table_ptr;
struct dcb_gpio_table gpio;
uint16_t connector_table_ptr;
......
......@@ -793,6 +793,7 @@ struct drm_nouveau_private {
struct nouveau_vm *chan_vm;
struct nvbios vbios;
struct list_head i2c_ports;
struct nv04_mode_state mode_reg;
struct nv04_mode_state saved_reg;
......
......@@ -109,13 +109,6 @@ nv4e_i2c_getsda(void *data)
return !!((nv_rd32(dev, i2c->rd) >> 16) & 8);
}
static const uint32_t nv50_i2c_port[] = {
0x00e138, 0x00e150, 0x00e168, 0x00e180,
0x00e254, 0x00e274, 0x00e764, 0x00e780,
0x00e79c, 0x00e7b8
};
#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port)
static int
nv50_i2c_getscl(void *data)
{
......@@ -125,7 +118,6 @@ nv50_i2c_getscl(void *data)
return !!(nv_rd32(dev, i2c->rd) & 1);
}
static int
nv50_i2c_getsda(void *data)
{
......@@ -166,125 +158,233 @@ nvd0_i2c_getsda(void *data)
return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20);
}
static const uint32_t nv50_i2c_port[] = {
0x00e138, 0x00e150, 0x00e168, 0x00e180,
0x00e254, 0x00e274, 0x00e764, 0x00e780,
0x00e79c, 0x00e7b8
};
static u8 *
i2c_table(struct drm_device *dev, u8 *version)
{
u8 *dcb = dcb_table(dev), *i2c = NULL;
if (dcb) {
if (dcb[0] >= 0x15)
i2c = ROMPTR(dev, dcb[2]);
if (dcb[0] >= 0x30)
i2c = ROMPTR(dev, dcb[4]);
}
/* early revisions had no version number, use dcb version */
if (i2c) {
*version = dcb[0];
if (*version >= 0x30)
*version = i2c[0];
}
return i2c;
}
int
nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
nouveau_i2c_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_i2c_chan *i2c;
int ret;
struct nvbios *bios = &dev_priv->vbios;
struct nouveau_i2c_chan *port;
u8 *i2c, *entry, legacy[2][4] = {};
u8 version, entries, recordlen;
int ret, i;
INIT_LIST_HEAD(&dev_priv->i2c_ports);
i2c = i2c_table(dev, &version);
if (!i2c) {
u8 *bmp = &bios->data[bios->offset];
if (bios->type != NVBIOS_BMP)
return -ENODEV;
if (entry->chan)
return -EEXIST;
legacy[0][0] = NV_CIO_CRE_DDC_WR__INDEX;
legacy[0][1] = NV_CIO_CRE_DDC_STATUS__INDEX;
legacy[1][0] = NV_CIO_CRE_DDC0_WR__INDEX;
legacy[1][1] = NV_CIO_CRE_DDC0_STATUS__INDEX;
/* BMP (from v4.0) has i2c info in the structure, it's in a
* fixed location on earlier VBIOS
*/
if (bmp[5] < 4)
i2c = &bios->data[0x48];
else
i2c = &bmp[0x36];
if (i2c[4]) legacy[0][0] = i2c[4];
if (i2c[5]) legacy[0][1] = i2c[5];
if (i2c[6]) legacy[1][0] = i2c[6];
if (i2c[7]) legacy[1][1] = i2c[7];
}
if (dev_priv->card_type >= NV_50 &&
dev_priv->card_type <= NV_C0 && entry->read >= NV50_I2C_PORTS) {
NV_ERROR(dev, "unknown i2c port %d\n", entry->read);
return -EINVAL;
if (i2c && version >= 0x30) {
entry = i2c[1] + i2c;
entries = i2c[2];
recordlen = i2c[3];
} else
if (i2c) {
entry = i2c;
entries = 16;
recordlen = 4;
} else {
entry = legacy[0];
entries = 2;
recordlen = 4;
}
i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
if (i2c == NULL)
for (i = 0; i < entries; i++, entry += recordlen) {
port = kzalloc(sizeof(*port), GFP_KERNEL);
if (port == NULL) {
nouveau_i2c_fini(dev);
return -ENOMEM;
}
port->type = entry[3];
if (version < 0x30) {
port->type &= 0x07;
if (port->type == 0x07)
port->type = 0xff;
}
if (port->type == 0xff) {
kfree(port);
continue;
}
switch (entry->port_type) {
case 0:
i2c->bit.setsda = nv04_i2c_setsda;
i2c->bit.setscl = nv04_i2c_setscl;
i2c->bit.getsda = nv04_i2c_getsda;
i2c->bit.getscl = nv04_i2c_getscl;
i2c->rd = entry->read;
i2c->wr = entry->write;
switch (port->type) {
case 0: /* NV04:NV50 */
port->wr = entry[0];
port->rd = entry[1];
port->bit.setsda = nv04_i2c_setsda;
port->bit.setscl = nv04_i2c_setscl;
port->bit.getsda = nv04_i2c_getsda;
port->bit.getscl = nv04_i2c_getscl;
break;
case 4:
i2c->bit.setsda = nv4e_i2c_setsda;
i2c->bit.setscl = nv4e_i2c_setscl;
i2c->bit.getsda = nv4e_i2c_getsda;
i2c->bit.getscl = nv4e_i2c_getscl;
i2c->rd = 0x600800 + entry->read;
i2c->wr = 0x600800 + entry->write;
case 4: /* NV4E */
port->wr = 0x600800 + entry[1];
port->rd = port->wr;
port->bit.setsda = nv4e_i2c_setsda;
port->bit.setscl = nv4e_i2c_setscl;
port->bit.getsda = nv4e_i2c_getsda;
port->bit.getscl = nv4e_i2c_getscl;
break;
case 5:
i2c->bit.setsda = nv50_i2c_setsda;
i2c->bit.setscl = nv50_i2c_setscl;
case 5: /* NV50- */
port->wr = entry[0] & 0x0f;
if (dev_priv->card_type < NV_D0) {
i2c->bit.getsda = nv50_i2c_getsda;
i2c->bit.getscl = nv50_i2c_getscl;
i2c->rd = nv50_i2c_port[entry->read];
i2c->wr = i2c->rd;
if (port->wr >= ARRAY_SIZE(nv50_i2c_port))
break;
port->wr = nv50_i2c_port[port->wr];
port->rd = port->wr;
port->bit.getsda = nv50_i2c_getsda;
port->bit.getscl = nv50_i2c_getscl;
} else {
i2c->bit.getsda = nvd0_i2c_getsda;
i2c->bit.getscl = nvd0_i2c_getscl;
i2c->rd = 0x00d014 + (entry->read * 0x20);
i2c->wr = i2c->rd;
port->wr = 0x00d014 + (port->wr * 0x20);
port->rd = port->wr;
port->bit.getsda = nvd0_i2c_getsda;
port->bit.getscl = nvd0_i2c_getscl;
}
port->bit.setsda = nv50_i2c_setsda;
port->bit.setscl = nv50_i2c_setscl;
break;
case 6:
i2c->rd = entry->read;
i2c->wr = entry->write;
case 6: /* NV50- DP AUX */
port->wr = entry[0];
port->rd = port->wr;
port->adapter.algo = &nouveau_dp_i2c_algo;
break;
default:
NV_ERROR(dev, "DCB I2C port type %d unknown\n",
entry->port_type);
kfree(i2c);
return -EINVAL;
break;
}
snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
"nouveau-%s-%d", pci_name(dev->pdev), index);
i2c->adapter.owner = THIS_MODULE;
i2c->adapter.dev.parent = &dev->pdev->dev;
i2c->dev = dev;
i2c_set_adapdata(&i2c->adapter, i2c);
if (entry->port_type < 6) {
i2c->adapter.algo_data = &i2c->bit;
i2c->bit.udelay = 40;
i2c->bit.timeout = usecs_to_jiffies(5000);
i2c->bit.data = i2c;
ret = i2c_bit_add_bus(&i2c->adapter);
if (!port->adapter.algo && !port->wr) {
NV_ERROR(dev, "I2C%d: type %d index %x/%x unknown\n",
i, port->type, port->wr, port->rd);
kfree(port);
continue;
}
snprintf(port->adapter.name, sizeof(port->adapter.name),
"nouveau-%s-%d", pci_name(dev->pdev), i);
port->adapter.owner = THIS_MODULE;
port->adapter.dev.parent = &dev->pdev->dev;
port->dev = dev;
port->index = i;
port->dcb = ROM32(entry[0]);
i2c_set_adapdata(&port->adapter, i2c);
if (port->adapter.algo != &nouveau_dp_i2c_algo) {
port->adapter.algo_data = &port->bit;
port->bit.udelay = 40;
port->bit.timeout = usecs_to_jiffies(5000);
port->bit.data = port;
ret = i2c_bit_add_bus(&port->adapter);
} else {
i2c->adapter.algo = &nouveau_dp_i2c_algo;
ret = i2c_add_adapter(&i2c->adapter);
port->adapter.algo = &nouveau_dp_i2c_algo;
ret = i2c_add_adapter(&port->adapter);
}
if (ret) {
NV_ERROR(dev, "Failed to register i2c %d\n", index);
kfree(i2c);
return ret;
NV_ERROR(dev, "I2C%d: failed register: %d\n", i, ret);
kfree(port);
continue;
}
list_add_tail(&port->head, &dev_priv->i2c_ports);
}
entry->chan = i2c;
return 0;
}
void
nouveau_i2c_fini(struct drm_device *dev, struct dcb_i2c_entry *entry)
nouveau_i2c_fini(struct drm_device *dev)
{
if (!entry->chan)
return;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_i2c_chan *port, *tmp;
i2c_del_adapter(&entry->chan->adapter);
kfree(entry->chan);
entry->chan = NULL;
list_for_each_entry_safe(port, tmp, &dev_priv->i2c_ports, head) {
i2c_del_adapter(&port->adapter);
kfree(port);
}
}
struct nouveau_i2c_chan *
nouveau_i2c_find(struct drm_device *dev, int index)
nouveau_i2c_find(struct drm_device *dev, u8 index)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct dcb_i2c_entry *i2c = &dev_priv->vbios.dcb.i2c[index];
struct nouveau_i2c_chan *port;
if (index == NV_I2C_DEFAULT(0) ||
index == NV_I2C_DEFAULT(1)) {
u8 version, *i2c = i2c_table(dev, &version);
if (i2c && version >= 0x30) {
if (index == NV_I2C_DEFAULT(0))
index = (i2c[4] & 0x0f);
else
index = (i2c[4] & 0xf0) >> 4;
} else {
index = 2;
}
}
if (index >= DCB_MAX_NUM_I2C_ENTRIES)
return NULL;
list_for_each_entry(port, &dev_priv->i2c_ports, head) {
if (port->index == index)
break;
}
if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) {
uint32_t reg = 0xe500, val;
if (&port->head == &dev_priv->i2c_ports)
return NULL;
if (i2c->port_type == 6) {
reg += i2c->read * 0x50;
if (dev_priv->card_type >= NV_50 && (port->dcb & 0x00000100)) {
u32 reg = 0x00e500, val;
if (port->type == 6) {
reg += port->rd * 0x50;
val = 0x2002;
} else {
reg += ((i2c->entry & 0x1e00) >> 9) * 0x50;
reg += ((port->dcb & 0x1e00) >> 9) * 0x50;
val = 0xe001;
}
......@@ -294,9 +394,7 @@ nouveau_i2c_find(struct drm_device *dev, int index)
nv_mask(dev, reg + 0x00, 0x0000f003, val);
}
if (!i2c->chan && nouveau_i2c_init(dev, i2c, index))
return NULL;
return i2c->chan;
return port;
}
bool
......
......@@ -27,20 +27,26 @@
#include <linux/i2c-algo-bit.h>
#include "drm_dp_helper.h"
struct dcb_i2c_entry;
#define NV_I2C_PORT(n) (0x00 + (n))
#define NV_I2C_PORT_NUM 0x10
#define NV_I2C_DEFAULT(n) (0x80 + (n))
struct nouveau_i2c_chan {
struct i2c_adapter adapter;
struct drm_device *dev;
struct i2c_algo_bit_data bit;
struct list_head head;
u8 index;
u8 type;
u32 dcb;
unsigned rd;
unsigned wr;
unsigned data;
};
int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index);
void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *);
struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index);
int nouveau_i2c_init(struct drm_device *);
void nouveau_i2c_fini(struct drm_device *);
struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, u8 index);
bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
int nouveau_i2c_identify(struct drm_device *dev, const char *what,
struct i2c_board_info *info,
......
......@@ -286,8 +286,6 @@ probe_monitoring_device(struct nouveau_i2c_chan *i2c,
static void
nouveau_temp_probe_i2c(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct dcb_table *dcb = &dev_priv->vbios.dcb;
struct i2c_board_info info[] = {
{ I2C_BOARD_INFO("w83l785ts", 0x2d) },
{ I2C_BOARD_INFO("w83781d", 0x2d) },
......@@ -296,11 +294,9 @@ nouveau_temp_probe_i2c(struct drm_device *dev)
{ I2C_BOARD_INFO("lm99", 0x4c) },
{ }
};
int idx = (dcb->version >= 0x40 ?
dcb->i2c_default_indices & 0xf : 2);
nouveau_i2c_identify(dev, "monitoring device", info,
probe_monitoring_device, idx);
probe_monitoring_device, NV_I2C_DEFAULT(0));
}
void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment