Commit ecb77686 authored by Jean-Francois Moine's avatar Jean-Francois Moine Committed by Mauro Carvalho Chehab

V4L/DVB (13567): gspca - sunplus/stk014: Propagate errors to higher level.

Signed-off-by: default avatarJean-Francois Moine <moinejf@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 8c4ebae4
...@@ -126,12 +126,14 @@ static const struct v4l2_pix_format vga_mode[] = { ...@@ -126,12 +126,14 @@ static const struct v4l2_pix_format vga_mode[] = {
}; };
/* -- read a register -- */ /* -- read a register -- */
static int reg_r(struct gspca_dev *gspca_dev, static u8 reg_r(struct gspca_dev *gspca_dev,
__u16 index) __u16 index)
{ {
struct usb_device *dev = gspca_dev->dev; struct usb_device *dev = gspca_dev->dev;
int ret; int ret;
if (gspca_dev->usb_err < 0)
return 0;
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
0x00, 0x00,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
...@@ -141,18 +143,21 @@ static int reg_r(struct gspca_dev *gspca_dev, ...@@ -141,18 +143,21 @@ static int reg_r(struct gspca_dev *gspca_dev,
500); 500);
if (ret < 0) { if (ret < 0) {
PDEBUG(D_ERR, "reg_r err %d", ret); PDEBUG(D_ERR, "reg_r err %d", ret);
return ret; gspca_dev->usb_err = ret;
return 0;
} }
return gspca_dev->usb_buf[0]; return gspca_dev->usb_buf[0];
} }
/* -- write a register -- */ /* -- write a register -- */
static int reg_w(struct gspca_dev *gspca_dev, static void reg_w(struct gspca_dev *gspca_dev,
__u16 index, __u16 value) __u16 index, __u16 value)
{ {
struct usb_device *dev = gspca_dev->dev; struct usb_device *dev = gspca_dev->dev;
int ret; int ret;
if (gspca_dev->usb_err < 0)
return;
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
0x01, 0x01,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
...@@ -161,13 +166,14 @@ static int reg_w(struct gspca_dev *gspca_dev, ...@@ -161,13 +166,14 @@ static int reg_w(struct gspca_dev *gspca_dev,
NULL, NULL,
0, 0,
500); 500);
if (ret < 0) if (ret < 0) {
PDEBUG(D_ERR, "reg_w err %d", ret); PDEBUG(D_ERR, "reg_w err %d", ret);
return ret; gspca_dev->usb_err = ret;
}
} }
/* -- get a bulk value (4 bytes) -- */ /* -- get a bulk value (4 bytes) -- */
static int rcv_val(struct gspca_dev *gspca_dev, static void rcv_val(struct gspca_dev *gspca_dev,
int ads) int ads)
{ {
struct usb_device *dev = gspca_dev->dev; struct usb_device *dev = gspca_dev->dev;
...@@ -182,17 +188,22 @@ static int rcv_val(struct gspca_dev *gspca_dev, ...@@ -182,17 +188,22 @@ static int rcv_val(struct gspca_dev *gspca_dev,
reg_w(gspca_dev, 0x63a, 0); reg_w(gspca_dev, 0x63a, 0);
reg_w(gspca_dev, 0x63b, 0); reg_w(gspca_dev, 0x63b, 0);
reg_w(gspca_dev, 0x630, 5); reg_w(gspca_dev, 0x630, 5);
if (gspca_dev->usb_err < 0)
return;
ret = usb_bulk_msg(dev, ret = usb_bulk_msg(dev,
usb_rcvbulkpipe(dev, 0x05), usb_rcvbulkpipe(dev, 0x05),
gspca_dev->usb_buf, gspca_dev->usb_buf,
4, /* length */ 4, /* length */
&alen, &alen,
500); /* timeout in milliseconds */ 500); /* timeout in milliseconds */
return ret; if (ret < 0) {
PDEBUG(D_ERR, "rcv_val err %d", ret);
gspca_dev->usb_err = ret;
}
} }
/* -- send a bulk value -- */ /* -- send a bulk value -- */
static int snd_val(struct gspca_dev *gspca_dev, static void snd_val(struct gspca_dev *gspca_dev,
int ads, int ads,
unsigned int val) unsigned int val)
{ {
...@@ -201,16 +212,9 @@ static int snd_val(struct gspca_dev *gspca_dev, ...@@ -201,16 +212,9 @@ static int snd_val(struct gspca_dev *gspca_dev,
__u8 seq = 0; __u8 seq = 0;
if (ads == 0x003f08) { if (ads == 0x003f08) {
ret = reg_r(gspca_dev, 0x0704); reg_r(gspca_dev, 0x0704);
if (ret < 0) seq = reg_r(gspca_dev, 0x0705);
goto ko; reg_r(gspca_dev, 0x0650);
ret = reg_r(gspca_dev, 0x0705);
if (ret < 0)
goto ko;
seq = ret; /* keep the sequence number */
ret = reg_r(gspca_dev, 0x0650);
if (ret < 0)
goto ko;
reg_w(gspca_dev, 0x654, seq); reg_w(gspca_dev, 0x654, seq);
} else { } else {
reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff); reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff);
...@@ -223,6 +227,8 @@ static int snd_val(struct gspca_dev *gspca_dev, ...@@ -223,6 +227,8 @@ static int snd_val(struct gspca_dev *gspca_dev,
reg_w(gspca_dev, 0x65a, 0); reg_w(gspca_dev, 0x65a, 0);
reg_w(gspca_dev, 0x65b, 0); reg_w(gspca_dev, 0x65b, 0);
reg_w(gspca_dev, 0x650, 5); reg_w(gspca_dev, 0x650, 5);
if (gspca_dev->usb_err < 0)
return;
gspca_dev->usb_buf[0] = val >> 24; gspca_dev->usb_buf[0] = val >> 24;
gspca_dev->usb_buf[1] = val >> 16; gspca_dev->usb_buf[1] = val >> 16;
gspca_dev->usb_buf[2] = val >> 8; gspca_dev->usb_buf[2] = val >> 8;
...@@ -233,24 +239,23 @@ static int snd_val(struct gspca_dev *gspca_dev, ...@@ -233,24 +239,23 @@ static int snd_val(struct gspca_dev *gspca_dev,
4, 4,
&alen, &alen,
500); /* timeout in milliseconds */ 500); /* timeout in milliseconds */
if (ret < 0) if (ret < 0) {
goto ko; PDEBUG(D_ERR, "snd_val err %d", ret);
gspca_dev->usb_err = ret;
} else {
if (ads == 0x003f08) { if (ads == 0x003f08) {
seq += 4; seq += 4;
seq &= 0x3f; seq &= 0x3f;
reg_w(gspca_dev, 0x705, seq); reg_w(gspca_dev, 0x705, seq);
} }
return ret; }
ko:
PDEBUG(D_ERR, "snd_val err %d", ret);
return ret;
} }
/* set a camera parameter */ /* set a camera parameter */
static int set_par(struct gspca_dev *gspca_dev, static void set_par(struct gspca_dev *gspca_dev,
int parval) int parval)
{ {
return snd_val(gspca_dev, 0x003f08, parval); snd_val(gspca_dev, 0x003f08, parval);
} }
static void setbrightness(struct gspca_dev *gspca_dev) static void setbrightness(struct gspca_dev *gspca_dev)
...@@ -311,18 +316,18 @@ static int sd_config(struct gspca_dev *gspca_dev, ...@@ -311,18 +316,18 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* this function is called at probe and resume time */ /* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev) static int sd_init(struct gspca_dev *gspca_dev)
{ {
int ret; u8 ret;
/* check if the device responds */ /* check if the device responds */
usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
ret = reg_r(gspca_dev, 0x0740); ret = reg_r(gspca_dev, 0x0740);
if (ret < 0) if (gspca_dev->usb_err >= 0) {
return ret;
if (ret != 0xff) { if (ret != 0xff) {
PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret); PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret);
return -1; gspca_dev->usb_err = -EIO;
} }
return 0; }
return gspca_dev->usb_err;
} }
/* -- start the camera -- */ /* -- start the camera -- */
...@@ -357,15 +362,12 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -357,15 +362,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
if (ret < 0) { if (ret < 0) {
PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed", PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed",
gspca_dev->iface, gspca_dev->alt); gspca_dev->iface, gspca_dev->alt);
gspca_dev->usb_err = ret;
goto out; goto out;
} }
ret = reg_r(gspca_dev, 0x0630); reg_r(gspca_dev, 0x0630);
if (ret < 0)
goto out;
rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */
ret = reg_r(gspca_dev, 0x0650); reg_r(gspca_dev, 0x0650);
if (ret < 0)
goto out;
snd_val(gspca_dev, 0x000020, 0xffffffff); snd_val(gspca_dev, 0x000020, 0xffffffff);
reg_w(gspca_dev, 0x0620, 0); reg_w(gspca_dev, 0x0620, 0);
reg_w(gspca_dev, 0x0630, 0); reg_w(gspca_dev, 0x0630, 0);
...@@ -384,11 +386,11 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -384,11 +386,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* start the video flow */ /* start the video flow */
set_par(gspca_dev, 0x01000000); set_par(gspca_dev, 0x01000000);
set_par(gspca_dev, 0x01000000); set_par(gspca_dev, 0x01000000);
PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); if (gspca_dev->usb_err >= 0)
return 0; PDEBUG(D_STREAM, "camera started alt: 0x%02x",
gspca_dev->alt);
out: out:
PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret); return gspca_dev->usb_err;
return ret;
} }
static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev)
...@@ -456,7 +458,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) ...@@ -456,7 +458,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
sd->brightness = val; sd->brightness = val;
if (gspca_dev->streaming) if (gspca_dev->streaming)
setbrightness(gspca_dev); setbrightness(gspca_dev);
return 0; return gspca_dev->usb_err;
} }
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
...@@ -474,7 +476,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) ...@@ -474,7 +476,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
sd->contrast = val; sd->contrast = val;
if (gspca_dev->streaming) if (gspca_dev->streaming)
setcontrast(gspca_dev); setcontrast(gspca_dev);
return 0; return gspca_dev->usb_err;
} }
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
...@@ -492,7 +494,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) ...@@ -492,7 +494,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
sd->colors = val; sd->colors = val;
if (gspca_dev->streaming) if (gspca_dev->streaming)
setcolors(gspca_dev); setcolors(gspca_dev);
return 0; return gspca_dev->usb_err;
} }
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
...@@ -510,7 +512,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) ...@@ -510,7 +512,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
sd->lightfreq = val; sd->lightfreq = val;
if (gspca_dev->streaming) if (gspca_dev->streaming)
setfreq(gspca_dev); setfreq(gspca_dev);
return 0; return gspca_dev->usb_err;
} }
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
...@@ -552,7 +554,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, ...@@ -552,7 +554,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev,
sd->quality = jcomp->quality; sd->quality = jcomp->quality;
if (gspca_dev->streaming) if (gspca_dev->streaming)
jpeg_set_qual(sd->jpeg_hdr, sd->quality); jpeg_set_qual(sd->jpeg_hdr, sd->quality);
return 0; return gspca_dev->usb_err;
} }
static int sd_get_jcomp(struct gspca_dev *gspca_dev, static int sd_get_jcomp(struct gspca_dev *gspca_dev,
......
...@@ -460,13 +460,17 @@ static void reg_r(struct gspca_dev *gspca_dev, ...@@ -460,13 +460,17 @@ static void reg_r(struct gspca_dev *gspca_dev,
u16 index, u16 index,
u16 len) u16 len)
{ {
int ret;
#ifdef GSPCA_DEBUG #ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) { if (len > USB_BUF_SZ) {
err("reg_r: buffer overflow"); err("reg_r: buffer overflow");
return; return;
} }
#endif #endif
usb_control_msg(gspca_dev->dev, if (gspca_dev->usb_err < 0)
return;
ret = usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0), usb_rcvctrlpipe(gspca_dev->dev, 0),
req, req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
...@@ -474,6 +478,10 @@ static void reg_r(struct gspca_dev *gspca_dev, ...@@ -474,6 +478,10 @@ static void reg_r(struct gspca_dev *gspca_dev,
index, index,
len ? gspca_dev->usb_buf : NULL, len, len ? gspca_dev->usb_buf : NULL, len,
500); 500);
if (ret < 0) {
PDEBUG(D_ERR, "reg_r err %d", ret);
gspca_dev->usb_err = ret;
}
} }
/* write one byte */ /* write one byte */
...@@ -483,40 +491,55 @@ static void reg_w_1(struct gspca_dev *gspca_dev, ...@@ -483,40 +491,55 @@ static void reg_w_1(struct gspca_dev *gspca_dev,
u16 index, u16 index,
u16 byte) u16 byte)
{ {
int ret;
if (gspca_dev->usb_err < 0)
return;
gspca_dev->usb_buf[0] = byte; gspca_dev->usb_buf[0] = byte;
usb_control_msg(gspca_dev->dev, ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0), usb_sndctrlpipe(gspca_dev->dev, 0),
req, req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, value, index,
gspca_dev->usb_buf, 1, gspca_dev->usb_buf, 1,
500); 500);
if (ret < 0) {
PDEBUG(D_ERR, "reg_w_1 err %d", ret);
gspca_dev->usb_err = ret;
}
} }
/* write req / index / value */ /* write req / index / value */
static int reg_w_riv(struct usb_device *dev, static void reg_w_riv(struct gspca_dev *gspca_dev,
u8 req, u16 index, u16 value) u8 req, u16 index, u16 value)
{ {
struct usb_device *dev = gspca_dev->dev;
int ret; int ret;
if (gspca_dev->usb_err < 0)
return;
ret = usb_control_msg(dev, ret = usb_control_msg(dev,
usb_sndctrlpipe(dev, 0), usb_sndctrlpipe(dev, 0),
req, req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, NULL, 0, 500); value, index, NULL, 0, 500);
PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d", if (ret < 0) {
req, index, value, ret); PDEBUG(D_ERR, "reg_w_riv err %d", ret);
if (ret < 0) gspca_dev->usb_err = ret;
PDEBUG(D_ERR, "reg write: error %d", ret); return;
return ret; }
PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
req, index, value);
} }
/* read 1 byte */ /* read 1 byte */
static int reg_r_1(struct gspca_dev *gspca_dev, static u8 reg_r_1(struct gspca_dev *gspca_dev,
u16 value) /* wValue */ u16 value) /* wValue */
{ {
int ret; int ret;
if (gspca_dev->usb_err < 0)
return 0;
ret = usb_control_msg(gspca_dev->dev, ret = usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0), usb_rcvctrlpipe(gspca_dev->dev, 0),
0x20, /* request */ 0x20, /* request */
...@@ -527,19 +550,22 @@ static int reg_r_1(struct gspca_dev *gspca_dev, ...@@ -527,19 +550,22 @@ static int reg_r_1(struct gspca_dev *gspca_dev,
500); /* timeout */ 500); /* timeout */
if (ret < 0) { if (ret < 0) {
PDEBUG(D_ERR, "reg_r_1 err %d", ret); PDEBUG(D_ERR, "reg_r_1 err %d", ret);
gspca_dev->usb_err = ret;
return 0; return 0;
} }
return gspca_dev->usb_buf[0]; return gspca_dev->usb_buf[0];
} }
/* read 1 or 2 bytes - returns < 0 if error */ /* read 1 or 2 bytes */
static int reg_r_12(struct gspca_dev *gspca_dev, static u16 reg_r_12(struct gspca_dev *gspca_dev,
u8 req, /* bRequest */ u8 req, /* bRequest */
u16 index, /* wIndex */ u16 index, /* wIndex */
u16 length) /* wLength (1 or 2 only) */ u16 length) /* wLength (1 or 2 only) */
{ {
int ret; int ret;
if (gspca_dev->usb_err < 0)
return 0;
gspca_dev->usb_buf[1] = 0; gspca_dev->usb_buf[1] = 0;
ret = usb_control_msg(gspca_dev->dev, ret = usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0), usb_rcvctrlpipe(gspca_dev->dev, 0),
...@@ -550,62 +576,44 @@ static int reg_r_12(struct gspca_dev *gspca_dev, ...@@ -550,62 +576,44 @@ static int reg_r_12(struct gspca_dev *gspca_dev,
gspca_dev->usb_buf, length, gspca_dev->usb_buf, length,
500); 500);
if (ret < 0) { if (ret < 0) {
PDEBUG(D_ERR, "reg_read err %d", ret); PDEBUG(D_ERR, "reg_r_12 err %d", ret);
return -1; gspca_dev->usb_err = ret;
return 0;
} }
return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
} }
static int write_vector(struct gspca_dev *gspca_dev, static void write_vector(struct gspca_dev *gspca_dev,
const struct cmd *data, int ncmds) const struct cmd *data, int ncmds)
{ {
struct usb_device *dev = gspca_dev->dev;
int ret;
while (--ncmds >= 0) { while (--ncmds >= 0) {
ret = reg_w_riv(dev, data->req, data->idx, data->val); reg_w_riv(gspca_dev, data->req, data->idx, data->val);
if (ret < 0) {
PDEBUG(D_ERR,
"Register write failed for 0x%02x, 0x%04x, 0x%04x",
data->req, data->val, data->idx);
return ret;
}
data++; data++;
} }
return 0;
} }
static int spca50x_setup_qtable(struct gspca_dev *gspca_dev, static void setup_qtable(struct gspca_dev *gspca_dev,
const u8 qtable[2][64]) const u8 qtable[2][64])
{ {
struct usb_device *dev = gspca_dev->dev; int i;
int i, err;
/* loop over y components */ /* loop over y components */
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++)
err = reg_w_riv(dev, 0x00, 0x2800 + i, qtable[0][i]); reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
if (err < 0)
return err;
}
/* loop over c components */ /* loop over c components */
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++)
err = reg_w_riv(dev, 0x00, 0x2840 + i, qtable[1][i]); reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
if (err < 0)
return err;
}
return 0;
} }
static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
u8 req, u16 idx, u16 val) u8 req, u16 idx, u16 val)
{ {
struct usb_device *dev = gspca_dev->dev; u16 notdone;
int notdone;
reg_w_riv(dev, req, idx, val); reg_w_riv(gspca_dev, req, idx, val);
notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
reg_w_riv(dev, req, idx, val); reg_w_riv(gspca_dev, req, idx, val);
PDEBUG(D_FRAM, "before wait 0x%04x", notdone); PDEBUG(D_FRAM, "before wait 0x%04x", notdone);
...@@ -616,23 +624,22 @@ static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, ...@@ -616,23 +624,22 @@ static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
u8 req, u8 req,
u16 idx, u16 val, u8 stat, u8 count) u16 idx, u16 val, u16 endcode, u8 count)
{ {
struct usb_device *dev = gspca_dev->dev; u16 status;
int status;
u8 endcode;
reg_w_riv(dev, req, idx, val); reg_w_riv(gspca_dev, req, idx, val);
status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
endcode = stat; if (gspca_dev->usb_err < 0)
PDEBUG(D_FRAM, "Status 0x%x Need 0x%04x", status, stat); return;
PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode);
if (!count) if (!count)
return; return;
count = 200; count = 200;
while (--count > 0) { while (--count > 0) {
msleep(10); msleep(10);
/* gsmart mini2 write a each wait setting 1 ms is enough */ /* gsmart mini2 write a each wait setting 1 ms is enough */
/* reg_w_riv(dev, req, idx, val); */ /* reg_w_riv(gspca_dev, req, idx, val); */
status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
if (status == endcode) { if (status == endcode) {
PDEBUG(D_FRAM, "status 0x%04x after wait %d", PDEBUG(D_FRAM, "status 0x%04x after wait %d",
...@@ -642,7 +649,7 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, ...@@ -642,7 +649,7 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
} }
} }
static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
{ {
int count = 10; int count = 10;
...@@ -652,7 +659,6 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) ...@@ -652,7 +659,6 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
break; break;
msleep(10); msleep(10);
} }
return gspca_dev->usb_buf[0];
} }
static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
...@@ -686,28 +692,26 @@ static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) ...@@ -686,28 +692,26 @@ static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
u8 Size; u8 Size;
int rc;
Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
switch (sd->bridge) { switch (sd->bridge) {
case BRIDGE_SPCA533: case BRIDGE_SPCA533:
reg_w_riv(dev, 0x31, 0, 0); reg_w_riv(gspca_dev, 0x31, 0, 0);
spca504B_WaitCmdStatus(gspca_dev); spca504B_WaitCmdStatus(gspca_dev);
rc = spca504B_PollingDataReady(gspca_dev); spca504B_PollingDataReady(gspca_dev);
spca50x_GetFirmware(gspca_dev); spca50x_GetFirmware(gspca_dev);
reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
reg_r(gspca_dev, 0x24, 8, 1); reg_r(gspca_dev, 0x24, 8, 1);
reg_w_1(gspca_dev, 0x25, 0, 4, Size); reg_w_1(gspca_dev, 0x25, 0, 4, Size);
reg_r(gspca_dev, 0x25, 4, 1); /* size */ reg_r(gspca_dev, 0x25, 4, 1); /* size */
rc = spca504B_PollingDataReady(gspca_dev); spca504B_PollingDataReady(gspca_dev);
/* Init the cam width height with some values get on init ? */ /* Init the cam width height with some values get on init ? */
reg_w_riv(dev, 0x31, 0, 0x04); reg_w_riv(gspca_dev, 0x31, 0, 0x04);
spca504B_WaitCmdStatus(gspca_dev); spca504B_WaitCmdStatus(gspca_dev);
rc = spca504B_PollingDataReady(gspca_dev); spca504B_PollingDataReady(gspca_dev);
break; break;
default: default:
/* case BRIDGE_SPCA504B: */ /* case BRIDGE_SPCA504B: */
...@@ -716,7 +720,7 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) ...@@ -716,7 +720,7 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
reg_r(gspca_dev, 0x25, 4, 1); /* size */ reg_r(gspca_dev, 0x25, 4, 1); /* size */
reg_w_1(gspca_dev, 0x27, 0, 0, 6); reg_w_1(gspca_dev, 0x27, 0, 0, 6);
reg_r(gspca_dev, 0x27, 0, 1); /* type */ reg_r(gspca_dev, 0x27, 0, 1); /* type */
rc = spca504B_PollingDataReady(gspca_dev); spca504B_PollingDataReady(gspca_dev);
break; break;
case BRIDGE_SPCA504: case BRIDGE_SPCA504:
Size += 3; Size += 3;
...@@ -733,8 +737,8 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) ...@@ -733,8 +737,8 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
break; break;
case BRIDGE_SPCA504C: case BRIDGE_SPCA504C:
/* capture mode */ /* capture mode */
reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00); reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f)); reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
break; break;
} }
} }
...@@ -762,37 +766,33 @@ static void spca504B_setQtable(struct gspca_dev *gspca_dev) ...@@ -762,37 +766,33 @@ static void spca504B_setQtable(struct gspca_dev *gspca_dev)
static void setbrightness(struct gspca_dev *gspca_dev) static void setbrightness(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
u16 reg; u16 reg;
reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7; reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
reg_w_riv(dev, 0x00, reg, sd->brightness); reg_w_riv(gspca_dev, 0x00, reg, sd->brightness);
} }
static void setcontrast(struct gspca_dev *gspca_dev) static void setcontrast(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
u16 reg; u16 reg;
reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8; reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
reg_w_riv(dev, 0x00, reg, sd->contrast); reg_w_riv(gspca_dev, 0x00, reg, sd->contrast);
} }
static void setcolors(struct gspca_dev *gspca_dev) static void setcolors(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
u16 reg; u16 reg;
reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae; reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
reg_w_riv(dev, 0x00, reg, sd->colors); reg_w_riv(gspca_dev, 0x00, reg, sd->colors);
} }
static void init_ctl_reg(struct gspca_dev *gspca_dev) static void init_ctl_reg(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
int pollreg = 1; int pollreg = 1;
setbrightness(gspca_dev); setbrightness(gspca_dev);
...@@ -807,14 +807,14 @@ static void init_ctl_reg(struct gspca_dev *gspca_dev) ...@@ -807,14 +807,14 @@ static void init_ctl_reg(struct gspca_dev *gspca_dev)
default: default:
/* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA504B: */ /* case BRIDGE_SPCA504B: */
reg_w_riv(dev, 0, 0x00, 0x21ad); /* hue */ reg_w_riv(gspca_dev, 0, 0x00, 0x21ad); /* hue */
reg_w_riv(dev, 0, 0x01, 0x21ac); /* sat/hue */ reg_w_riv(gspca_dev, 0, 0x01, 0x21ac); /* sat/hue */
reg_w_riv(dev, 0, 0x00, 0x21a3); /* gamma */ reg_w_riv(gspca_dev, 0, 0x00, 0x21a3); /* gamma */
break; break;
case BRIDGE_SPCA536: case BRIDGE_SPCA536:
reg_w_riv(dev, 0, 0x40, 0x20f5); reg_w_riv(gspca_dev, 0, 0x40, 0x20f5);
reg_w_riv(dev, 0, 0x01, 0x20f4); reg_w_riv(gspca_dev, 0, 0x01, 0x20f4);
reg_w_riv(dev, 0, 0x00, 0x2089); reg_w_riv(gspca_dev, 0, 0x00, 0x2089);
break; break;
} }
if (pollreg) if (pollreg)
...@@ -881,18 +881,17 @@ static int sd_config(struct gspca_dev *gspca_dev, ...@@ -881,18 +881,17 @@ static int sd_config(struct gspca_dev *gspca_dev,
static int sd_init(struct gspca_dev *gspca_dev) static int sd_init(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev; int i;
int i, err_code;
u8 info[6]; u8 info[6];
switch (sd->bridge) { switch (sd->bridge) {
case BRIDGE_SPCA504B: case BRIDGE_SPCA504B:
reg_w_riv(dev, 0x1d, 0x00, 0); reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
reg_w_riv(dev, 0, 0x01, 0x2306); reg_w_riv(gspca_dev, 0, 0x01, 0x2306);
reg_w_riv(dev, 0, 0x00, 0x0d04); reg_w_riv(gspca_dev, 0, 0x00, 0x0d04);
reg_w_riv(dev, 0, 0x00, 0x2000); reg_w_riv(gspca_dev, 0, 0x00, 0x2000);
reg_w_riv(dev, 0, 0x13, 0x2301); reg_w_riv(gspca_dev, 0, 0x13, 0x2301);
reg_w_riv(dev, 0, 0x00, 0x2306); reg_w_riv(gspca_dev, 0, 0x00, 0x2306);
/* fall thru */ /* fall thru */
case BRIDGE_SPCA533: case BRIDGE_SPCA533:
spca504B_PollingDataReady(gspca_dev); spca504B_PollingDataReady(gspca_dev);
...@@ -904,13 +903,13 @@ static int sd_init(struct gspca_dev *gspca_dev) ...@@ -904,13 +903,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
reg_w_1(gspca_dev, 0x24, 0, 0, 0); reg_w_1(gspca_dev, 0x24, 0, 0, 0);
reg_r(gspca_dev, 0x24, 0, 1); reg_r(gspca_dev, 0x24, 0, 1);
spca504B_PollingDataReady(gspca_dev); spca504B_PollingDataReady(gspca_dev);
reg_w_riv(dev, 0x34, 0, 0); reg_w_riv(gspca_dev, 0x34, 0, 0);
spca504B_WaitCmdStatus(gspca_dev); spca504B_WaitCmdStatus(gspca_dev);
break; break;
case BRIDGE_SPCA504C: /* pccam600 */ case BRIDGE_SPCA504C: /* pccam600 */
PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)"); PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
reg_w_riv(dev, 0xe0, 0x0000, 0x0000); reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */ reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
spca504_wait_status(gspca_dev); spca504_wait_status(gspca_dev);
if (sd->subtype == LogitechClickSmart420) if (sd->subtype == LogitechClickSmart420)
write_vector(gspca_dev, write_vector(gspca_dev,
...@@ -919,12 +918,7 @@ static int sd_init(struct gspca_dev *gspca_dev) ...@@ -919,12 +918,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
else else
write_vector(gspca_dev, spca504_pccam600_open_data, write_vector(gspca_dev, spca504_pccam600_open_data,
ARRAY_SIZE(spca504_pccam600_open_data)); ARRAY_SIZE(spca504_pccam600_open_data));
err_code = spca50x_setup_qtable(gspca_dev, setup_qtable(gspca_dev, qtable_creative_pccam);
qtable_creative_pccam);
if (err_code < 0) {
PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed");
return err_code;
}
break; break;
default: default:
/* case BRIDGE_SPCA504: */ /* case BRIDGE_SPCA504: */
...@@ -958,29 +952,24 @@ static int sd_init(struct gspca_dev *gspca_dev) ...@@ -958,29 +952,24 @@ static int sd_init(struct gspca_dev *gspca_dev)
6, 0, 0x86, 1); */ 6, 0, 0x86, 1); */
/* spca504A_acknowledged_command (gspca_dev, 0x24, /* spca504A_acknowledged_command (gspca_dev, 0x24,
0, 0, 0x9D, 1); */ 0, 0, 0x9D, 1); */
reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */ reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
reg_w_riv(dev, 0x00, 0x2310, 0x05); /* L92 sno1t.txt */
reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
spca504A_acknowledged_command(gspca_dev, 0x01, spca504A_acknowledged_command(gspca_dev, 0x01,
0x0f, 0, 0xff, 0); 0x0f, 0, 0xff, 0);
} }
/* setup qtable */ /* setup qtable */
reg_w_riv(dev, 0, 0x2000, 0); reg_w_riv(gspca_dev, 0, 0x2000, 0);
reg_w_riv(dev, 0, 0x2883, 1); reg_w_riv(gspca_dev, 0, 0x2883, 1);
err_code = spca50x_setup_qtable(gspca_dev, setup_qtable(gspca_dev, qtable_spca504_default);
qtable_spca504_default);
if (err_code < 0) {
PDEBUG(D_ERR, "spca50x_setup_qtable failed");
return err_code;
}
break; break;
} }
return 0; return gspca_dev->usb_err;
} }
static int sd_start(struct gspca_dev *gspca_dev) static int sd_start(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
int enable; int enable;
int i; int i;
u8 info[6]; u8 info[6];
...@@ -1005,13 +994,13 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -1005,13 +994,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
case MegapixV4: case MegapixV4:
case LogitechClickSmart820: case LogitechClickSmart820:
case MegaImageVI: case MegaImageVI:
reg_w_riv(dev, 0xf0, 0, 0); reg_w_riv(gspca_dev, 0xf0, 0, 0);
spca504B_WaitCmdStatus(gspca_dev); spca504B_WaitCmdStatus(gspca_dev);
reg_r(gspca_dev, 0xf0, 4, 0); reg_r(gspca_dev, 0xf0, 4, 0);
spca504B_WaitCmdStatus(gspca_dev); spca504B_WaitCmdStatus(gspca_dev);
break; break;
default: default:
reg_w_riv(dev, 0x31, 0, 0x04); reg_w_riv(gspca_dev, 0x31, 0, 0x04);
spca504B_WaitCmdStatus(gspca_dev); spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev); spca504B_PollingDataReady(gspca_dev);
break; break;
...@@ -1048,8 +1037,9 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -1048,8 +1037,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
} }
spca504B_SetSizeType(gspca_dev); spca504B_SetSizeType(gspca_dev);
reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */ reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
reg_w_riv(dev, 0x00, 0x2310, 0x05); /* L92 sno1t.txt */
reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
break; break;
case BRIDGE_SPCA504C: case BRIDGE_SPCA504C:
if (sd->subtype == LogitechClickSmart420) { if (sd->subtype == LogitechClickSmart420) {
...@@ -1061,36 +1051,37 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -1061,36 +1051,37 @@ static int sd_start(struct gspca_dev *gspca_dev)
ARRAY_SIZE(spca504_pccam600_init_data)); ARRAY_SIZE(spca504_pccam600_init_data));
} }
enable = (sd->autogain ? 0x04 : 0x01); enable = (sd->autogain ? 0x04 : 0x01);
reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */ reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */ /* auto exposure */
reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
/* auto whiteness */
/* set default exposure compensation and whiteness balance */ /* set default exposure compensation and whiteness balance */
reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */ reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */
reg_w_riv(dev, 0x30, 0x0002, 1600); reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
spca504B_SetSizeType(gspca_dev); spca504B_SetSizeType(gspca_dev);
break; break;
} }
init_ctl_reg(gspca_dev); init_ctl_reg(gspca_dev);
return 0; return gspca_dev->usb_err;
} }
static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct usb_device *dev = gspca_dev->dev;
switch (sd->bridge) { switch (sd->bridge) {
default: default:
/* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA536: */ /* case BRIDGE_SPCA536: */
/* case BRIDGE_SPCA504B: */ /* case BRIDGE_SPCA504B: */
reg_w_riv(dev, 0x31, 0, 0); reg_w_riv(gspca_dev, 0x31, 0, 0);
spca504B_WaitCmdStatus(gspca_dev); spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev); spca504B_PollingDataReady(gspca_dev);
break; break;
case BRIDGE_SPCA504: case BRIDGE_SPCA504:
case BRIDGE_SPCA504C: case BRIDGE_SPCA504C:
reg_w_riv(dev, 0x00, 0x2000, 0x0000); reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
if (sd->subtype == AiptekMiniPenCam13) { if (sd->subtype == AiptekMiniPenCam13) {
/* spca504a aiptek */ /* spca504a aiptek */
...@@ -1102,7 +1093,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ...@@ -1102,7 +1093,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
0x0f, 0x00, 0xff, 1); 0x0f, 0x00, 0xff, 1);
} else { } else {
spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
reg_w_riv(dev, 0x01, 0x000f, 0x0000); reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
} }
break; break;
} }
...@@ -1216,7 +1207,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) ...@@ -1216,7 +1207,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
sd->brightness = val; sd->brightness = val;
if (gspca_dev->streaming) if (gspca_dev->streaming)
setbrightness(gspca_dev); setbrightness(gspca_dev);
return 0; return gspca_dev->usb_err;
} }
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
...@@ -1234,7 +1225,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) ...@@ -1234,7 +1225,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
sd->contrast = val; sd->contrast = val;
if (gspca_dev->streaming) if (gspca_dev->streaming)
setcontrast(gspca_dev); setcontrast(gspca_dev);
return 0; return gspca_dev->usb_err;
} }
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
...@@ -1252,7 +1243,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) ...@@ -1252,7 +1243,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
sd->colors = val; sd->colors = val;
if (gspca_dev->streaming) if (gspca_dev->streaming)
setcolors(gspca_dev); setcolors(gspca_dev);
return 0; return gspca_dev->usb_err;
} }
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
...@@ -1292,7 +1283,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, ...@@ -1292,7 +1283,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev,
sd->quality = jcomp->quality; sd->quality = jcomp->quality;
if (gspca_dev->streaming) if (gspca_dev->streaming)
jpeg_set_qual(sd->jpeg_hdr, sd->quality); jpeg_set_qual(sd->jpeg_hdr, sd->quality);
return 0; return gspca_dev->usb_err;
} }
static int sd_get_jcomp(struct gspca_dev *gspca_dev, static int sd_get_jcomp(struct gspca_dev *gspca_dev,
......
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