0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009 #define MODULE_NAME "dtcs033"
0010 #include "gspca.h"
0011
0012 MODULE_AUTHOR("Robert Butora <robert.butora.fi@gmail.com>");
0013 MODULE_DESCRIPTION("Scopium DTCS033 astro-cam USB Camera Driver");
0014 MODULE_LICENSE("GPL");
0015
0016 struct dtcs033_usb_requests {
0017 u8 bRequestType;
0018 u8 bRequest;
0019 u16 wValue;
0020 u16 wIndex;
0021 u16 wLength;
0022 };
0023
0024
0025 static void reg_rw(struct gspca_dev *gspca_dev,
0026 u8 bRequestType, u8 bRequest,
0027 u16 wValue, u16 wIndex, u16 wLength)
0028 {
0029 struct usb_device *udev = gspca_dev->dev;
0030 int ret;
0031
0032 if (gspca_dev->usb_err < 0)
0033 return;
0034
0035 ret = usb_control_msg(udev,
0036 usb_rcvctrlpipe(udev, 0),
0037 bRequest,
0038 bRequestType,
0039 wValue, wIndex,
0040 gspca_dev->usb_buf, wLength, 500);
0041
0042 if (ret < 0) {
0043 gspca_dev->usb_err = ret;
0044 pr_err("usb_control_msg error %d\n", ret);
0045 }
0046
0047 return;
0048 }
0049
0050 static int reg_reqs(struct gspca_dev *gspca_dev,
0051 const struct dtcs033_usb_requests *preqs, int n_reqs)
0052 {
0053 int i = 0;
0054 const struct dtcs033_usb_requests *preq;
0055
0056 while ((i < n_reqs) && (gspca_dev->usb_err >= 0)) {
0057
0058 preq = &preqs[i];
0059
0060 reg_rw(gspca_dev, preq->bRequestType, preq->bRequest,
0061 preq->wValue, preq->wIndex, preq->wLength);
0062
0063 if (gspca_dev->usb_err < 0) {
0064
0065 gspca_err(gspca_dev, "usb error request no: %d / %d\n",
0066 i, n_reqs);
0067 } else if (preq->bRequestType & USB_DIR_IN) {
0068
0069 gspca_dbg(gspca_dev, D_STREAM,
0070 "USB IN (%d) returned[%d] %3ph %s",
0071 i,
0072 preq->wLength,
0073 gspca_dev->usb_buf,
0074 preq->wLength > 3 ? "...\n" : "\n");
0075 }
0076
0077 i++;
0078 }
0079 return gspca_dev->usb_err;
0080 }
0081
0082
0083
0084 #define DT_COLS (640)
0085 static const struct v4l2_pix_format dtcs033_mode[] = {
0086
0087 {DT_COLS, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
0088 .bytesperline = DT_COLS,
0089 .sizeimage = DT_COLS*480,
0090 .colorspace = V4L2_COLORSPACE_SRGB,
0091 },
0092
0093 {DT_COLS, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
0094 .bytesperline = DT_COLS,
0095 .sizeimage = DT_COLS*480,
0096 .colorspace = V4L2_COLORSPACE_SRGB,
0097 }
0098 };
0099
0100
0101 static int sd_config(struct gspca_dev *gspca_dev,
0102 const struct usb_device_id *id)
0103 {
0104 gspca_dev->cam.cam_mode = dtcs033_mode;
0105 gspca_dev->cam.nmodes = ARRAY_SIZE(dtcs033_mode);
0106
0107 gspca_dev->cam.bulk = 1;
0108 gspca_dev->cam.bulk_nurbs = 1;
0109 gspca_dev->cam.bulk_size = DT_COLS*512;
0110
0111 return 0;
0112 }
0113
0114
0115 static int sd_init(struct gspca_dev *gspca_dev)
0116 {
0117 return 0;
0118 }
0119
0120
0121 static int dtcs033_start(struct gspca_dev *gspca_dev);
0122 static void dtcs033_stopN(struct gspca_dev *gspca_dev);
0123
0124
0125 static void dtcs033_pkt_scan(struct gspca_dev *gspca_dev,
0126 u8 *data,
0127 int len)
0128 {
0129
0130 if (len != DT_COLS*512) {
0131 gspca_dev->last_packet_type = DISCARD_PACKET;
0132
0133 return;
0134 }
0135
0136
0137 gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
0138 gspca_frame_add(gspca_dev, INTER_PACKET,
0139 data + 16*DT_COLS,
0140 len - 32*DT_COLS);
0141 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
0142
0143 return;
0144 }
0145
0146
0147
0148 static void dtcs033_setexposure(struct gspca_dev *gspca_dev,
0149 s32 expo, s32 gain)
0150 {
0151
0152 u16 sGain = (u16)gain;
0153 u16 gainVal = 224+(sGain-14)*(768-224)/(33-14);
0154 u16 wIndex = 0x0100|(0x00FF&gainVal);
0155 u16 wValue = (0xFF00&gainVal)>>8;
0156
0157
0158 u16 sXTime = (u16)expo;
0159 u16 xtimeVal = (524*(150-(sXTime-1)))/150;
0160
0161 const u8 bRequestType =
0162 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
0163 const u8 bRequest = 0x18;
0164
0165 reg_rw(gspca_dev,
0166 bRequestType, bRequest, wValue, wIndex, 0);
0167 if (gspca_dev->usb_err < 0)
0168 gspca_err(gspca_dev, "usb error in setexposure(gain) sequence\n");
0169
0170 reg_rw(gspca_dev,
0171 bRequestType, bRequest, (xtimeVal<<4), 0x6300, 0);
0172 if (gspca_dev->usb_err < 0)
0173 gspca_err(gspca_dev, "usb error in setexposure(time) sequence\n");
0174 }
0175
0176
0177 struct sd {
0178 struct gspca_dev gspca_dev;
0179
0180
0181 struct {
0182 struct v4l2_ctrl *exposure;
0183 struct v4l2_ctrl *gain;
0184 };
0185 };
0186
0187 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
0188 {
0189 struct gspca_dev *gspca_dev =
0190 container_of(ctrl->handler,
0191 struct gspca_dev, ctrl_handler);
0192 struct sd *sd = (struct sd *) gspca_dev;
0193
0194 gspca_dev->usb_err = 0;
0195
0196 if (!gspca_dev->streaming)
0197 return 0;
0198
0199 switch (ctrl->id) {
0200 case V4L2_CID_EXPOSURE:
0201 dtcs033_setexposure(gspca_dev,
0202 ctrl->val, sd->gain->val);
0203 break;
0204 case V4L2_CID_GAIN:
0205 dtcs033_setexposure(gspca_dev,
0206 sd->exposure->val, ctrl->val);
0207 break;
0208 }
0209 return gspca_dev->usb_err;
0210 }
0211
0212 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
0213 .s_ctrl = sd_s_ctrl,
0214 };
0215
0216 static int dtcs033_init_controls(struct gspca_dev *gspca_dev)
0217 {
0218 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
0219 struct sd *sd = (struct sd *) gspca_dev;
0220
0221 gspca_dev->vdev.ctrl_handler = hdl;
0222 v4l2_ctrl_handler_init(hdl, 2);
0223
0224 sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0225 V4L2_CID_EXPOSURE,
0226 1, 150, 1, 75);
0227 sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0228 V4L2_CID_GAIN,
0229 14, 33, 1, 24);
0230 if (hdl->error) {
0231 gspca_err(gspca_dev, "Could not initialize controls: %d\n",
0232 hdl->error);
0233 return hdl->error;
0234 }
0235
0236 v4l2_ctrl_cluster(2, &sd->exposure);
0237 return 0;
0238 }
0239
0240
0241 static const struct sd_desc sd_desc = {
0242 .name = MODULE_NAME,
0243 .config = sd_config,
0244 .init = sd_init,
0245 .start = dtcs033_start,
0246 .stopN = dtcs033_stopN,
0247 .pkt_scan = dtcs033_pkt_scan,
0248 .init_controls = dtcs033_init_controls,
0249 };
0250
0251
0252
0253 static const struct usb_device_id device_table[] = {
0254 {USB_DEVICE(0x0547, 0x7303)},
0255 {}
0256 };
0257 MODULE_DEVICE_TABLE(usb, device_table);
0258
0259
0260 static int sd_probe(struct usb_interface *intf,
0261 const struct usb_device_id *id)
0262 {
0263 return gspca_dev_probe(intf, id,
0264 &sd_desc, sizeof(struct sd),
0265 THIS_MODULE);
0266 }
0267
0268 static struct usb_driver sd_driver = {
0269 .name = MODULE_NAME,
0270 .id_table = device_table,
0271 .probe = sd_probe,
0272 .disconnect = gspca_disconnect,
0273 #ifdef CONFIG_PM
0274 .suspend = gspca_suspend,
0275 .resume = gspca_resume,
0276 .reset_resume = gspca_resume,
0277 #endif
0278 };
0279 module_usb_driver(sd_driver);
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289 static const struct dtcs033_usb_requests dtcs033_start_reqs[] = {
0290
0291 { 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
0292 { 0x40, 0x01, 0x0000, 0x000F, 0x0000 },
0293 { 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
0294 { 0x40, 0x18, 0x0000, 0x7F00, 0x0000 },
0295 { 0x40, 0x18, 0x0000, 0x1001, 0x0000 },
0296 { 0x40, 0x18, 0x0000, 0x0004, 0x0000 },
0297 { 0x40, 0x18, 0x0000, 0x7F01, 0x0000 },
0298 { 0x40, 0x18, 0x30E0, 0x0009, 0x0000 },
0299 { 0x40, 0x18, 0x0500, 0x012C, 0x0000 },
0300 { 0x40, 0x18, 0x0380, 0x0200, 0x0000 },
0301 { 0x40, 0x18, 0x0000, 0x035C, 0x0000 },
0302 { 0x40, 0x18, 0x05C0, 0x0438, 0x0000 },
0303 { 0x40, 0x18, 0x0440, 0x0500, 0x0000 },
0304 { 0x40, 0x18, 0x0000, 0x0668, 0x0000 },
0305 { 0x40, 0x18, 0x0000, 0x0700, 0x0000 },
0306 { 0x40, 0x18, 0x0000, 0x0800, 0x0000 },
0307 { 0x40, 0x18, 0x0000, 0x0900, 0x0000 },
0308 { 0x40, 0x18, 0x0000, 0x0A00, 0x0000 },
0309 { 0x40, 0x18, 0x0000, 0x0B00, 0x0000 },
0310 { 0x40, 0x18, 0x30E0, 0x6009, 0x0000 },
0311 { 0x40, 0x18, 0x0500, 0x612C, 0x0000 },
0312 { 0x40, 0x18, 0x2090, 0x6274, 0x0000 },
0313 { 0x40, 0x18, 0x05C0, 0x6338, 0x0000 },
0314 { 0x40, 0x18, 0x0000, 0x6400, 0x0000 },
0315 { 0x40, 0x18, 0x05C0, 0x6538, 0x0000 },
0316 { 0x40, 0x18, 0x0000, 0x6600, 0x0000 },
0317 { 0x40, 0x18, 0x0680, 0x6744, 0x0000 },
0318 { 0x40, 0x18, 0x0000, 0x6800, 0x0000 },
0319 { 0x40, 0x18, 0x0000, 0x6900, 0x0000 },
0320 { 0x40, 0x18, 0x0000, 0x6A00, 0x0000 },
0321 { 0x40, 0x18, 0x0000, 0x6B00, 0x0000 },
0322 { 0x40, 0x18, 0x0000, 0x6C00, 0x0000 },
0323 { 0x40, 0x18, 0x0000, 0x6D00, 0x0000 },
0324 { 0x40, 0x18, 0x0000, 0x6E00, 0x0000 },
0325 { 0x40, 0x18, 0x0000, 0x808C, 0x0000 },
0326 { 0x40, 0x18, 0x0010, 0x8101, 0x0000 },
0327 { 0x40, 0x18, 0x30E0, 0x8200, 0x0000 },
0328 { 0x40, 0x18, 0x0810, 0x832C, 0x0000 },
0329 { 0x40, 0x18, 0x0680, 0x842B, 0x0000 },
0330 { 0x40, 0x18, 0x0000, 0x8500, 0x0000 },
0331 { 0x40, 0x18, 0x0000, 0x8600, 0x0000 },
0332 { 0x40, 0x18, 0x0280, 0x8715, 0x0000 },
0333 { 0x40, 0x18, 0x0000, 0x880C, 0x0000 },
0334 { 0x40, 0x18, 0x0010, 0x8901, 0x0000 },
0335 { 0x40, 0x18, 0x30E0, 0x8A00, 0x0000 },
0336 { 0x40, 0x18, 0x0810, 0x8B2C, 0x0000 },
0337 { 0x40, 0x18, 0x0680, 0x8C2B, 0x0000 },
0338 { 0x40, 0x18, 0x0000, 0x8D00, 0x0000 },
0339 { 0x40, 0x18, 0x0000, 0x8E00, 0x0000 },
0340 { 0x40, 0x18, 0x0280, 0x8F15, 0x0000 },
0341 { 0x40, 0x18, 0x0010, 0xD040, 0x0000 },
0342 { 0x40, 0x18, 0x0000, 0xD100, 0x0000 },
0343 { 0x40, 0x18, 0x00B0, 0xD20A, 0x0000 },
0344 { 0x40, 0x18, 0x0000, 0xD300, 0x0000 },
0345 { 0x40, 0x18, 0x30E2, 0xD40D, 0x0000 },
0346 { 0x40, 0x18, 0x0001, 0xD5C0, 0x0000 },
0347 { 0x40, 0x18, 0x00A0, 0xD60A, 0x0000 },
0348 { 0x40, 0x18, 0x0000, 0xD700, 0x0000 },
0349 { 0x40, 0x18, 0x0000, 0x7F00, 0x0000 },
0350 { 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
0351 { 0x40, 0x18, 0x0001, 0x01FF, 0x0000 },
0352 { 0x40, 0x18, 0x0000, 0x0200, 0x0000 },
0353 { 0x40, 0x18, 0x0000, 0x0304, 0x0000 },
0354 { 0x40, 0x18, 0x0000, 0x1101, 0x0000 },
0355 { 0x40, 0x18, 0x0000, 0x1201, 0x0000 },
0356 { 0x40, 0x18, 0x0000, 0x1300, 0x0000 },
0357 { 0x40, 0x18, 0x0000, 0x1400, 0x0000 },
0358 { 0x40, 0x18, 0x0000, 0x1601, 0x0000 },
0359 { 0x40, 0x18, 0x0000, 0x1800, 0x0000 },
0360 { 0x40, 0x18, 0x0000, 0x1900, 0x0000 },
0361 { 0x40, 0x18, 0x0000, 0x1A00, 0x0000 },
0362 { 0x40, 0x18, 0x2000, 0x1B00, 0x0000 },
0363 { 0x40, 0x18, 0x0000, 0x1C00, 0x0000 },
0364 { 0x40, 0x18, 0x0000, 0x2100, 0x0000 },
0365 { 0x40, 0x18, 0x00C0, 0x228E, 0x0000 },
0366 { 0x40, 0x18, 0x0000, 0x3001, 0x0000 },
0367 { 0x40, 0x18, 0x0010, 0x3101, 0x0000 },
0368 { 0x40, 0x18, 0x0008, 0x3301, 0x0000 },
0369 { 0x40, 0x18, 0x0000, 0x3400, 0x0000 },
0370 { 0x40, 0x18, 0x0012, 0x3549, 0x0000 },
0371 { 0x40, 0x18, 0x0000, 0x3620, 0x0000 },
0372 { 0x40, 0x18, 0x0001, 0x3700, 0x0000 },
0373 { 0x40, 0x18, 0x0000, 0x4000, 0x0000 },
0374 { 0x40, 0x18, 0xFFFF, 0x41FF, 0x0000 },
0375 { 0x40, 0x18, 0xFFFF, 0x42FF, 0x0000 },
0376 { 0x40, 0x18, 0x0000, 0x500F, 0x0000 },
0377 { 0x40, 0x18, 0x2272, 0x5108, 0x0000 },
0378 { 0x40, 0x18, 0x2272, 0x5208, 0x0000 },
0379 { 0x40, 0x18, 0xFFFF, 0x53FF, 0x0000 },
0380 { 0x40, 0x18, 0xFFFF, 0x54FF, 0x0000 },
0381 { 0x40, 0x18, 0x0000, 0x6000, 0x0000 },
0382 { 0x40, 0x18, 0x0000, 0x6102, 0x0000 },
0383 { 0x40, 0x18, 0x0010, 0x6214, 0x0000 },
0384 { 0x40, 0x18, 0x0C80, 0x6300, 0x0000 },
0385 { 0x40, 0x18, 0x0000, 0x6401, 0x0000 },
0386 { 0x40, 0x18, 0x0680, 0x6551, 0x0000 },
0387 { 0x40, 0x18, 0xFFFF, 0x66FF, 0x0000 },
0388 { 0x40, 0x18, 0x0000, 0x6702, 0x0000 },
0389 { 0x40, 0x18, 0x0010, 0x6800, 0x0000 },
0390 { 0x40, 0x18, 0x0000, 0x6900, 0x0000 },
0391 { 0x40, 0x18, 0x0000, 0x6A00, 0x0000 },
0392 { 0x40, 0x18, 0x0000, 0x6B00, 0x0000 },
0393 { 0x40, 0x18, 0x0000, 0x6C00, 0x0000 },
0394 { 0x40, 0x18, 0x0000, 0x6D01, 0x0000 },
0395 { 0x40, 0x18, 0x0000, 0x6E00, 0x0000 },
0396 { 0x40, 0x18, 0x0000, 0x6F00, 0x0000 },
0397 { 0x40, 0x18, 0x0000, 0x7000, 0x0000 },
0398 { 0x40, 0x18, 0x0001, 0x7118, 0x0000 },
0399 { 0x40, 0x18, 0x0000, 0x2001, 0x0000 },
0400 { 0x40, 0x18, 0x0000, 0x1101, 0x0000 },
0401 { 0x40, 0x18, 0x0000, 0x1301, 0x0000 },
0402 { 0x40, 0x18, 0x0000, 0x1300, 0x0000 },
0403 { 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
0404 { 0xC0, 0x11, 0x0000, 0x24C0, 0x0003 },
0405 { 0x40, 0x18, 0x0000, 0x3000, 0x0000 },
0406 { 0x40, 0x18, 0x0000, 0x3620, 0x0000 },
0407 { 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
0408 { 0x40, 0x18, 0x0010, 0x6300, 0x0000 },
0409 { 0x40, 0x18, 0x0002, 0x01F0, 0x0000 },
0410 { 0x40, 0x01, 0x0003, 0x000F, 0x0000 }
0411 };
0412
0413 static const struct dtcs033_usb_requests dtcs033_stop_reqs[] = {
0414
0415 { 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
0416 { 0x40, 0x01, 0x0000, 0x000F, 0x0000 },
0417 { 0x40, 0x18, 0x0000, 0x0003, 0x0000 }
0418 };
0419 static int dtcs033_start(struct gspca_dev *gspca_dev)
0420 {
0421 return reg_reqs(gspca_dev, dtcs033_start_reqs,
0422 ARRAY_SIZE(dtcs033_start_reqs));
0423 }
0424
0425 static void dtcs033_stopN(struct gspca_dev *gspca_dev)
0426 {
0427 reg_reqs(gspca_dev, dtcs033_stop_reqs,
0428 ARRAY_SIZE(dtcs033_stop_reqs));
0429 return;
0430 }