📄 qcamvc_pp.c
字号:
cond_resched();#endif if ( (read=parport_read(parport, buffer + counter, 1)) != 1 ) { printk(KERN_ERR "QuickCamVC: qcamvc_stream_read2: failed to read: error %i.\n", read); break; } read_bytes += read; } return read_bytes;}/********************************************************************//* qcamvc_read general purpose parport read interface *//****************************************************************/static size_t qcamvc_read(void *privdata, void *buffer, size_t len){ struct pp_cam_entry *cam = privdata; if(!cam || !cam->open_count) return 0; struct parport *parport = cam->port; size_t ret=0; if(parport_negotiate(parport, IEEE1284_DATA | ppmode) != 0) { printk(KERN_ERR "QuickCamVC: qcamvc_read: ieee1284 failed negotiation\n"); return -1; } parport_read(parport, buffer, len); return ret = len;}/******************************************************************//* qcamvc_write general purpose parport write interface *//****************************************************************/static int qcamvc_write(void *privdata, void *buffer, size_t len){ struct pp_cam_entry *cam = privdata; if(!cam || !cam->open_count) return 0; struct parport *parport = cam->port; int ret=0; if(parport_negotiate(parport, IEEE1284_DATA | ppmode) != 0) { printk(KERN_ERR "QuickCamVC: qcamvc_write: ieee1284 failed negotiation\n"); return -1; } parport_write(parport, buffer, len); return ret = len;}/********************************************************************************//* qcamvc_set_reg register value set method for the parport version of the QuickCamVC *//********************************************************************************/static int qcamvc_set_reg(void *privdata, unsigned char reg, void *buffer, size_t len){ struct pp_cam_entry *cam = privdata; if(!cam || !cam->open_count) return 0; struct parport *parport = cam->port; int ret=0; if ( parport_negotiate(parport, IEEE1284_ADDR | ppmode) != 0 ) { printk(KERN_ERR "QuickCamVC:WCN1 qcamvc_set_reg1: ieee1284 failed negotiation\n"); return -1; } if (parport_write(parport, ®, 1) != 1) printk(KERN_INFO "QuickCamVC: qcamvc_set_reg: write failed #1\n"); if(parport_negotiate(parport, IEEE1284_DATA | ppmode) != 0) { printk(KERN_ERR "QuickCamVC: qcamvc_set_reg2: ieee1284 failed negotiation\n"); return -1; } if (parport_write(parport, buffer, len) != len) printk(KERN_ERR "QuickCamVC: qcamvc_set_reg: write failed #2\n"); return ret = len;}/********************************************************************************//* qcamvc_get_reg register value retrieval method for the parport version of theQuickCamVC *//*********************************************************************************/static size_t qcamvc_get_reg(void *privdata, unsigned char reg, void *buffer, size_t len){ struct pp_cam_entry *cam = privdata; if(!cam || !cam->open_count) return 0; struct parport *parport = cam->port; int ret=0; if(parport_negotiate(cam->port, IEEE1284_ADDR | ppmode) != 0) { printk(KERN_ERR "QuickCamVC:WCN1 qcamvc_get_reg1: ieee1284 failed negotiation\n"); return -1; } ret=parport_write(parport, ®, 1); if (len == 0 || buffer == NULL) return ret; if(parport_negotiate(parport, IEEE1284_DATA | ppmode) != 0) { printk(KERN_ERR "QuickCamVC: qcamvc_get_reg2: ieee1284 failed negotiation\n"); return -1; } parport_read(parport, buffer, len); return len;}/************************************************************************//* qcamvc_register registers the camera with the V4L driver and the parport driver*//**************************************************************************/static int qcamvc_register(struct parport *port) { struct pardevice *pdev = NULL; struct pp_cam_entry *cam; struct qcamvc_data *qcamvc; if (!(port->modes & PARPORT_MODE_ECP) && !(port->modes & PARPORT_MODE_TRISTATE)) { printk(KERN_ERR "QuickCam VC(PP): Port is not ECP capable!\n"); return -ENXIO; } if (port->modes & PARPORT_MODE_DMA) printk(KERN_INFO "QuickCam VC(PP): Port is DMA capable.\n"); cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL); if (cam == NULL) { printk(KERN_ERR "QuickCam VC(PP): Failed to allocate pp_cam_entry.\n"); return -ENOMEM; } memset(cam,0,sizeof(struct pp_cam_entry)); pdev = parport_register_device(port, "Connectix QuickCam VC", NULL, NULL, NULL, 0, cam); if (!pdev) { //LOG("failed to parport_register_device\n"); printk(KERN_ERR "Failed to parport_register_device.\n"); kfree(cam); return -ENXIO; } cam->pdev = pdev; cam->port = port; if( (qcamvc = qcamvc_register_camera(&qcamvc_pp_ops, cam, "QuickCam VC(PP)")) == NULL ) { printk(KERN_ERR "Failed to qcamvc_register_camera.\n"); parport_unregister_device(pdev); kfree(cam); return -ENXIO; } printk(KERN_INFO "QuickCam VC(PP): sucessfully registered.\n"); spin_lock( &cam_list_lock_pp ); list_add( &qcamvc->cam_data_list, &cam_list ); spin_unlock( &cam_list_lock_pp ); return 0;}/*****************************************************************//* qcamvc_pp_detach Used to remove the driver from the kernel *//****************************************************************/static void qcamvc_pp_detach(struct parport *port){ struct list_head *tmp; struct qcamvc_data *qcamvc = NULL; struct pp_cam_entry *cam = NULL; spin_lock( &cam_list_lock_pp ); list_for_each (tmp, &cam_list) { qcamvc = list_entry(tmp, struct qcamvc_data, cam_data_list); cam = (struct pp_cam_entry *) qcamvc->lowlevel_data; if (cam && cam->port->number == port->number) { break; } qcamvc = NULL; } spin_unlock( &cam_list_lock_pp ); if (!qcamvc || !cam) { printk(KERN_ERR "qcamvc_pp_detach failed to find qcamvc in cam_data_list\n"); return; } if(cam->open_count > 0) qcamvc_close(cam); parport_unregister_device(cam->pdev); qcamvc->lowlevel_data = NULL; kfree(cam);}/*****************************************************************//* qcamvc_pp_attach used to attach the driver to the kernel *//**************************************************************/static void qcamvc_pp_attach(struct parport *port){ unsigned int i; switch (parport_nr[0]) { case QCAMVC_PARPORT_UNSPEC: case QCAMVC_PARPORT_AUTO: if (port->probe_info[0].class != PARPORT_CLASS_MEDIA || strncmp(port->probe_info[0].mfr, "Connectix", 9) != 0 || strncmp(port->probe_info[0].model, "QuickCam VC", 11) != 0 ) { printk(KERN_ERR "qcamvc_pp_attach failed.\n"); return; } qcamvc_register(port); break; default: for (i = 0; i < PARPORT_MAX; ++i) { if (port->number == parport_nr[i]) { qcamvc_register(port); break; } } break; }}static struct parport_driver qcamvc_pp_driver = { .name = "Connectix QuickCam VC", .attach = qcamvc_pp_attach, .detach = qcamvc_pp_detach,};static int qcamvc_pp_init(void){ if(parport_nr[0] == QCAMVC_PARPORT_OFF) { printk(" disabled\n"); return 0; } spin_lock_init( &cam_list_lock_pp ); if (parport_register_driver (&qcamvc_pp_driver)) { printk(KERN_ERR "unable to register with parport\n"); return -EIO; } return 0;}#ifdef MODULE/********************************************************************//* qcamvc_pp_init_module used by the wrapper below to insmod (or modprobe) *//*********************************************************************/static int __init qcamvc_pp_init_module (void){ printk("QuickCam VC(PP): (C) 2001 by De Marchi Daniele, <demarchidaniele@libero.it>\n"); printk("QuickCam VC(PP): lowlevel driver version %s registered.\n",QCAMVCVERSION); if (parport[0]) { /* The user gave some parameters. Let's see what they were. */ if (!strncmp(parport[0], "auto", 4)) { parport_nr[0] = QCAMVC_PARPORT_AUTO; } else { int n; for (n = 0; n < PARPORT_MAX && parport[n]; n++) { if (!strncmp(parport[n], "none", 4)) { parport_nr[n] = QCAMVC_PARPORT_NONE; } else { char *ep; unsigned long r = simple_strtoul(parport[n], &ep, 0); if (ep != parport[n]) { parport_nr[n] = r; } else { printk("bad port specifier `%s'\n", parport[n]); return -ENODEV; } } } } }#if defined(CONFIG_KMOD) && defined(CONFIG_PNP_PARPORT_MODULE) if(parport_enumerate() && !parport_enumerate()->probe_info.model) { request_module("parport_probe"); }#endif return qcamvc_pp_init();}/***************************************************************************//* qcamvc_pp_exit_module used by the wrapper below to rmmod *//**************************************************************************/static void __exit qcamvc_pp_exit_module(void){ parport_unregister_driver(&qcamvc_pp_driver); /* finally unregister video. can't do this in detach() because the call to qcamvc_unregister_camera() blocks and causes "bad: scheduling while atomic!" when unloading this module. */ struct list_head *tmp; struct qcamvc_data *qcamvc = NULL; spin_lock( &cam_list_lock_pp ); list_for_each (tmp, &cam_list) { qcamvc = list_entry(tmp, struct qcamvc_data, cam_data_list); /* lowlevel_data will be NULL if it's the one we want ie. lowlevel_data=NULL in detach() from call to parport_unregister_driver() */ if (!qcamvc->lowlevel_data) { list_del(&qcamvc->cam_data_list); break; } qcamvc = NULL; } spin_unlock( &cam_list_lock_pp ); if (!qcamvc) printk("qcamvc_pp_exit_module: failed to find qcamvc in cam_data_list\n"); else qcamvc_unregister_camera(qcamvc);}/**************************************//* wrappers used by insmod and rmmod to load and unload the driver as a module *//**************************************/module_init(qcamvc_pp_init_module);module_exit(qcamvc_pp_exit_module);#else /*!MODULE*//**************************************************//* used if compiled into the kernel *//*************************************************/static int __init qcamvc_pp_setup(char *str){ if (!strncmp(str, "parport", 7)) { int n = simple_strtoul(str + 7, NULL, 10); if (parport_ptr < PARPORT_MAX) { parport_nr[parport_ptr++] = n; } else { LOG("too many ports, %s ignored.\n", str); } } else if (!strcmp(str, "auto")) { parport_nr[0] = QCAMVC_PARPORT_AUTO; } else if (!strcmp(str, "none")) { parport_nr[parport_ptr++] = QCAMVC_PARPORT_NONE; } return 0;}__setup("qcamvc_pp=", qcamvc_pp_setup);#endif /* MODULE *//* ----------------------------------------*//* Parallel Port DMA Code from CPiA driver *//* ----------------------------------------*/#ifdef QCAMVC_PARPORT_DMA/*-----------------------------------------------------------------------*//* stuff below is static stuff * copied from parport_pc.c (should be made public) */#define DPRINTK(fmt,args...) do {} while(0)/* ECR modes */#define ECR_SPP 00#define ECR_PS2 01#define ECR_PPF 02#define ECR_ECP 03#define ECR_EPP 04#define ECR_VND 05#define ECR_TST 06#define ECR_CNF 07#define ECR_MODE_MASK 0xe0#define ECR_WRITE(p,v) frob_econtrol((p),0xff,(v))#define ECONTROL(p) ((p)->base_hi + 0x2)/* frob_control, but for ECR */static void frob_econtrol (struct parport *pb, unsigned char m, unsigned char v){ unsigned char ectr = 0; if (m != 0xff) ectr = inb (ECONTROL (pb)); DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n", m, v, ectr, (ectr & ~m) ^ v); outb ((ectr & ~m) ^ v, ECONTROL (pb));}/* Safely change the mode bits in the ECR Returns: 0 : Success -EBUSY: Could not drain FIFO in some finite amount of time, mode not changed! */static int change_mode(struct parport *p, int m){ const struct parport_pc_private *priv = p->physport->private_data; unsigned char oecr; int mode; DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n",m); if (!priv->ecr) { printk (KERN_DEBUG "change_mode: but there's no ECR!\n"); return 0; } /* Bits <7:5> contain the mode. */ oecr = inb (ECONTROL (p)); mode = (oecr >> 5) & 0x7; if (mode == m) return 0; if (mode >= 2 && !(priv->ctr & 0x20)) { /* This mode resets the FIFO, so we may * have to wait for it to drain first. */#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) long expire = jiffies + p->physport->cad->timeout;#else unsigned long expire = jiffies + p->physport->cad->timeout;#endif int counter; switch (mode) { case ECR_PPF: /* Parallel Port FIFO mode */ case ECR_ECP: /* ECP Parallel Port mode */ /* Busy wait for 200us */ for (counter = 0; counter < 40; counter++) { if (inb (ECONTROL (p)) & 0x01) break; if (signal_pending (current)) break; udelay (5); } /* Poll slowly. */ while (!(inb (ECONTROL (p)) & 0x01)) { if (time_after_eq (jiffies, expire)) /* The FIFO is stuck. */ return -EBUSY; __set_current_state (TASK_INTERRUPTIBLE); schedule_timeout ((HZ + 99) / 100); if (signal_pending (current)) break; } } } if (mode >= 2 && m >= 2) { /* We have to go through mode 001 */ oecr &= ~(7 << 5); oecr |= ECR_PS2 << 5; ECR_WRITE (p, oecr); } /* Set the mode. */ oecr &= ~(7 << 5); oecr |= m << 5; ECR_WRITE (p, oecr); return 0;}#endif /* QCAMVC_PARPORT_DMA */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -