📄 cpia_pp.c
字号:
if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) { DBG("Error writing command\n"); return err; } if(command[0] == DATA_IN) { u8 buffer[8]; if(data == NULL) { DBG("Internal driver error: data is NULL\n"); return -EINVAL; } if((err = ReadPacket(cam, buffer, 8)) < 0) { DBG("Error reading command result\n"); return err; } memcpy(data, buffer, databytes); } else if(command[0] == DATA_OUT) { if(databytes > 0) { if(data == NULL) { DBG("Internal driver error: data is NULL\n"); retval = -EINVAL; } else { if((err=WritePacket(cam, data, databytes)) < 0){ DBG("Error writing command data\n"); return err; } } } } else { DBG("Unexpected first byte of command: %x\n", command[0]); retval = -EINVAL; } return retval;}/**************************************************************************** * * cpia_pp_upload_mode * ***************************************************************************/static int cpia_pp_upload_mode(void *privdata ){ struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata; switch (cam->upload_mode) { case IEEE1284_MODE_ECP: return 3; break; case IEEE1284_MODE_ECPSWE: return 2; break; case IEEE1284_MODE_NIBBLE: return 1; break; } return 0;}/**************************************************************************** * * cpia_pp_open * ***************************************************************************/static int cpia_pp_open(void *privdata , int alt ){ struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata; /* alt has no meaning for parport cameras */ if (cam == NULL) return -EINVAL; if(cam->open_count == 0) { if (parport_claim(cam->pdev)) { LOG("cpia_pp: failed to claim parport%d\n", cam->port->portnum); return -EBUSY; } DBG("cpia_pp: claim parport%d\n",cam->port->portnum); parport_negotiate(cam->port, IEEE1284_MODE_COMPAT); parport_data_forward(cam->port); parport_write_control(cam->port, PARPORT_CONTROL_SELECT); udelay(50); parport_write_control(cam->port, PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT); } else return -EBUSY; ++cam->open_count; return 0;}/**************************************************************************** * * cpia_pp_registerCallback * ***************************************************************************/static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void *cbdata){ struct pp_cam_entry *cam = privdata; int retval = 0; if(cam->port->irq != PARPORT_IRQ_NONE) {#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) cam->cb_task.routine = cb; cam->cb_task.data = cbdata;#else INIT_WORK(&cam->cb_task, cb, cbdata);#endif } else { retval = -1; } return retval;}/**************************************************************************** * * cpia_pp_close * ***************************************************************************/static int cpia_pp_close(void *privdata){ struct pp_cam_entry *cam = privdata; if (--cam->open_count == 0) { /* delay to allow parport status lines to reset: * seems to fix problems when lp is also registered on port(?)*/ if(cam->port->ops->read_status(cam->port) != 80) mdelay(40); DBG("cpia_pp: releasing parport%d\n",cam->port->portnum,status); parport_release(cam->pdev); } return 0;}/**************************************************************************** * * cpia_pp_register * ***************************************************************************/static int cpia_pp_register(struct parport *port){ struct pardevice *pdev = NULL; struct pp_cam_entry *cam; struct cam_data *cpia; if (!(port->modes & PARPORT_MODE_PCSPP)) { printk ("Unsupported (non-IEEE1284) Parallel Port.\n"); return -ENODEV; } cam = kmalloc(sizeof(struct pp_cam_entry), GFP_KERNEL); if (cam == NULL) { LOG("failed to allocate camera structure\n"); return -ENOMEM; } memset(cam,0,sizeof(struct pp_cam_entry)); pdev = parport_register_device(port, "cpia_pp", NULL, NULL, NULL, 0, cam); if (!pdev) { LOG("failed to parport_register_device\n"); kfree(cam); return -ENXIO; } cam->pdev = pdev; cam->port = port; init_waitqueue_head(&cam->wq_stream); cam->streaming = 0; cam->stream_irq = 0; cam->upload_mode = IEEE1284_MODE_NIBBLE; if (port->modes & PARPORT_MODE_TRISTATE) cam->upload_mode = IEEE1284_MODE_ECPSWE; if (port->modes & PARPORT_MODE_ECP) cam->upload_mode = IEEE1284_MODE_ECP; if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) { LOG("failed to cpia_register_camera\n"); parport_unregister_device(pdev); kfree(cam); return -ENXIO; } /* (for testing:) * if cam->upload_mode = IEEE1284_MODE_ECPSWE or IEEE1284_NIBBLE * is set here, even if "better" modes are detected, this mode will * be used for uploads from the camera. */ //cam->upload_mode = IEEE1284_MODE_NIBBLE; //cam->upload_mode = IEEE1284_MODE_ECPSWE; switch(cam->upload_mode) { case IEEE1284_MODE_ECP: if(port->modes & PARPORT_MODE_DMA) {#ifdef CPIA_PARPORT_DMA printk("ECP Parallel Port with DMA detected: "#else printk("ECP Parallel Port (DMA not enabled in cpia_pp): "#endif "image stream should be fast\n"); } else { printk("ECP Parallel Port without DMA detected: " "image stream should be fast\n"); } break; case IEEE1284_MODE_ECPSWE: printk("Bidirectional Parallel Port will emulate ECP mode: " "image stream may be slow\n"); break; case IEEE1284_MODE_NIBBLE: default: printk("Non-bidirectional Parallel Port will use" " \"nibble\" mode: image stream will be slow\n"); } spin_lock( &cam_list_lock_pp ); list_add( &cpia->cam_data_list, &cam_list ); spin_unlock( &cam_list_lock_pp ); return 0;}static void cpia_pp_detach (struct parport *port){ struct list_head *tmp; struct cam_data *cpia = NULL; struct pp_cam_entry *cam; spin_lock( &cam_list_lock_pp ); list_for_each (tmp, &cam_list) { cpia = list_entry(tmp, struct cam_data, cam_data_list); cam = (struct pp_cam_entry *) cpia->lowlevel_data; if (cam && cam->port->number == port->number) { list_del(&cpia->cam_data_list); break; } cpia = NULL; } spin_unlock( &cam_list_lock_pp ); if (!cpia) { DBG("cpia_pp_detach failed to find cam_data in cam_list\n"); return; } cam = (struct pp_cam_entry *) cpia->lowlevel_data; cpia_unregister_camera(cpia); if(cam->open_count > 0) cpia_pp_close(cam); parport_unregister_device(cam->pdev); cpia->lowlevel_data = NULL; kfree(cam);}static void cpia_pp_attach (struct parport *port){ unsigned int i; switch (parport_nr[0]) { case PPCPIA_PARPORT_UNSPEC: case PPCPIA_PARPORT_AUTO: if (port->probe_info[0].class != PARPORT_CLASS_MEDIA || port->probe_info[0].cmdset == NULL || strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0) return; cpia_pp_register(port); break; default: for (i = 0; i < PARPORT_MAX; ++i) { if (port->number == parport_nr[i]) { cpia_pp_register(port); break; } } break; }}static struct parport_driver cpia_pp_driver = { "cpia_pp", cpia_pp_attach, cpia_pp_detach, NULL};int cpia_pp_init(void){ printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT, CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER); if(parport_nr[0] == PPCPIA_PARPORT_OFF) { printk(" disabled\n"); return 0; } spin_lock_init( &cam_list_lock_pp ); if (parport_register_driver (&cpia_pp_driver)) { LOG ("unable to register with parport\n"); return -EIO; } return 0;}#ifdef MODULEint init_module(void){ if (parport[0]) { /* The user gave some parameters. Let's see what they were. */ if (!strncmp(parport[0], "auto", 4)) { parport_nr[0] = PPCPIA_PARPORT_AUTO; } else { int n; for (n = 0; n < PARPORT_MAX && parport[n]; n++) { if (!strncmp(parport[n], "none", 4)) { parport_nr[n] = PPCPIA_PARPORT_NONE; } else { char *ep; unsigned long r = simple_strtoul(parport[n], &ep, 0); if (ep != parport[n]) { parport_nr[n] = r; } else { LOG("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 cpia_pp_init();}void cleanup_module(void){ parport_unregister_driver (&cpia_pp_driver); return;}#else /* !MODULE */static int __init cpia_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] = PPCPIA_PARPORT_AUTO; } else if (!strcmp(str, "none")) { parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE; } return 0;}__setup("cpia_pp=", cpia_pp_setup);#endif /* !MODULE */#ifdef CPIA_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 /* CPIA_PARPORT_DMA */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -