📄 auerswald.c
字号:
newbp->len = bp->len; /* insert new buffer in read list */ spin_lock_irqsave (&ccp->bufctl.lock, flags); list_add_tail (&newbp->buff_list, &ccp->bufctl.rec_buff_list); spin_unlock_irqrestore (&ccp->bufctl.lock, flags); dbg ("read buffer appended to rec_list"); /* wake up pending synchronous reads */ wake_up (&ccp->readwait);}/* Delete an auerswald driver context */static void auerswald_delete( pauerswald_t cp){ dbg( "auerswald_delete"); if (cp == NULL) return; /* Wake up all processes waiting for a buffer */ wake_up (&cp->bufferwait); /* Cleaning up */ auerswald_int_release (cp); auerchain_free (&cp->controlchain); auerbuf_free_buffers (&cp->bufctl); /* release the memory */ kfree( cp);}/* Delete an auerswald character context */static void auerchar_delete( pauerchar_t ccp){ dbg ("auerchar_delete"); if (ccp == NULL) return; /* wake up pending synchronous reads */ ccp->removed = 1; wake_up (&ccp->readwait); /* remove the read buffer */ if (ccp->readbuf) { auerbuf_releasebuf (ccp->readbuf); ccp->readbuf = NULL; } /* remove the character buffers */ auerbuf_free_buffers (&ccp->bufctl); /* release the memory */ kfree( ccp);}/* add a new service to the device scp->id must be set! return: 0 if OK, else error code*/static int auerswald_addservice (pauerswald_t cp, pauerscon_t scp){ int ret; /* is the device available? */ if (!cp->usbdev) { dbg ("usbdev == NULL"); return -EIO; /*no: can not add a service, sorry*/ } /* is the service available? */ if (cp->services[scp->id]) { dbg ("service is busy"); return -EBUSY; } /* device is available, service is free */ cp->services[scp->id] = scp; /* register service in device */ ret = auerchain_control_msg( &cp->controlchain, /* pointer to control chain */ cp->usbdev, /* pointer to device */ usb_sndctrlpipe (cp->usbdev, 0), /* pipe to control endpoint */ AUV_CHANNELCTL, /* USB message request value */ AUT_WREQ, /* USB message request type value */ 0x01, /* open USB message value */ scp->id, /* USB message index value */ NULL, /* pointer to the data to send */ 0, /* length in bytes of the data to send */ HZ * 2); /* time to wait for the message to complete before timing out */ if (ret < 0) { dbg ("auerswald_addservice: auerchain_control_msg returned error code %d", ret); /* undo above actions */ cp->services[scp->id] = NULL; return ret; } dbg ("auerswald_addservice: channel open OK"); return 0;}/* remove a service from the the device scp->id must be set! */static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp){ dbg ("auerswald_removeservice called"); /* check if we have a service allocated */ if (scp->id == AUH_UNASSIGNED) return; /* If there is a device: close the channel */ if (cp->usbdev) { /* Close the service channel inside the device */ int ret = auerchain_control_msg( &cp->controlchain, /* pointer to control chain */ cp->usbdev, /* pointer to device */ usb_sndctrlpipe (cp->usbdev, 0), /* pipe to control endpoint */ AUV_CHANNELCTL, /* USB message request value */ AUT_WREQ, /* USB message request type value */ 0x00, // close /* USB message value */ scp->id, /* USB message index value */ NULL, /* pointer to the data to send */ 0, /* length in bytes of the data to send */ HZ * 2); /* time to wait for the message to complete before timing out */ if (ret < 0) { dbg ("auerswald_removeservice: auerchain_control_msg returned error code %d", ret); } else { dbg ("auerswald_removeservice: channel close OK"); } } /* remove the service from the device */ cp->services[scp->id] = NULL; scp->id = AUH_UNASSIGNED;}/* --------------------------------------------------------------------- *//* Char device functions *//* Open a new character device */static int auerchar_open (struct inode *inode, struct file *file){ int dtindex = iminor(inode); pauerswald_t cp = NULL; pauerchar_t ccp = NULL; struct usb_interface *intf; int ret; /* minor number in range? */ if (dtindex < 0) { return -ENODEV; } intf = usb_find_interface(&auerswald_driver, dtindex); if (!intf) { return -ENODEV; } /* usb device available? */ cp = usb_get_intfdata (intf); if (cp == NULL) { return -ENODEV; } if (down_interruptible (&cp->mutex)) { return -ERESTARTSYS; } /* we have access to the device. Now lets allocate memory */ ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL); if (ccp == NULL) { err ("out of memory"); ret = -ENOMEM; goto ofail; } /* Initialize device descriptor */ memset( ccp, 0, sizeof(auerchar_t)); init_MUTEX( &ccp->mutex); init_MUTEX( &ccp->readmutex); auerbuf_init (&ccp->bufctl); ccp->scontext.id = AUH_UNASSIGNED; ccp->scontext.dispatch = auerchar_ctrlread_dispatch; ccp->scontext.disconnect = auerchar_disconnect; init_waitqueue_head (&ccp->readwait); ret = auerbuf_setup (&ccp->bufctl, AU_RBUFFERS, cp->maxControlLength+AUH_SIZE); if (ret) { goto ofail; } cp->open_count++; ccp->auerdev = cp; dbg("open %s as /dev/%s", cp->dev_desc, cp->name); up (&cp->mutex); /* file IO stuff */ file->f_pos = 0; file->private_data = ccp; return nonseekable_open(inode, file); /* Error exit */ofail: up (&cp->mutex); auerchar_delete (ccp); return ret;}/* IOCTL functions */static int auerchar_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ pauerchar_t ccp = (pauerchar_t) file->private_data; int ret = 0; audevinfo_t devinfo; pauerswald_t cp = NULL; unsigned int u; unsigned int __user *user_arg = (unsigned int __user *)arg; dbg ("ioctl"); /* get the mutexes */ if (down_interruptible (&ccp->mutex)) { return -ERESTARTSYS; } cp = ccp->auerdev; if (!cp) { up (&ccp->mutex); return -ENODEV; } if (down_interruptible (&cp->mutex)) { up(&ccp->mutex); return -ERESTARTSYS; } /* Check for removal */ if (!cp->usbdev) { up(&cp->mutex); up(&ccp->mutex); return -ENODEV; } switch (cmd) { /* return != 0 if Transmitt channel ready to send */ case IOCTL_AU_TXREADY: dbg ("IOCTL_AU_TXREADY"); u = ccp->auerdev && (ccp->scontext.id != AUH_UNASSIGNED) && !list_empty (&cp->bufctl.free_buff_list); ret = put_user (u, user_arg); break; /* return != 0 if connected to a service channel */ case IOCTL_AU_CONNECT: dbg ("IOCTL_AU_CONNECT"); u = (ccp->scontext.id != AUH_UNASSIGNED); ret = put_user (u, user_arg); break; /* return != 0 if Receive Data available */ case IOCTL_AU_RXAVAIL: dbg ("IOCTL_AU_RXAVAIL"); if (ccp->scontext.id == AUH_UNASSIGNED) { ret = -EIO; break; } u = 0; /* no data */ if (ccp->readbuf) { int restlen = ccp->readbuf->len - ccp->readoffset; if (restlen > 0) u = 1; } if (!u) { if (!list_empty (&ccp->bufctl.rec_buff_list)) { u = 1; } } ret = put_user (u, user_arg); break; /* return the max. buffer length for the device */ case IOCTL_AU_BUFLEN: dbg ("IOCTL_AU_BUFLEN"); u = cp->maxControlLength; ret = put_user (u, user_arg); break; /* requesting a service channel */ case IOCTL_AU_SERVREQ: dbg ("IOCTL_AU_SERVREQ"); /* requesting a service means: release the previous one first */ auerswald_removeservice (cp, &ccp->scontext); /* get the channel number */ ret = get_user (u, user_arg); if (ret) { break; } if ((u < AUH_FIRSTUSERCH) || (u >= AUH_TYPESIZE)) { ret = -EIO; break; } dbg ("auerchar service request parameters are ok"); ccp->scontext.id = u; /* request the service now */ ret = auerswald_addservice (cp, &ccp->scontext); if (ret) { /* no: revert service entry */ ccp->scontext.id = AUH_UNASSIGNED; } break; /* get a string descriptor for the device */ case IOCTL_AU_DEVINFO: dbg ("IOCTL_AU_DEVINFO"); if (copy_from_user (&devinfo, (void __user *) arg, sizeof (audevinfo_t))) { ret = -EFAULT; break; } u = strlen(cp->dev_desc)+1; if (u > devinfo.bsize) { u = devinfo.bsize; } ret = copy_to_user(devinfo.buf, cp->dev_desc, u) ? -EFAULT : 0; break; /* get the max. string descriptor length */ case IOCTL_AU_SLEN: dbg ("IOCTL_AU_SLEN"); u = AUSI_DLEN; ret = put_user (u, user_arg); break; default: dbg ("IOCTL_AU_UNKNOWN"); ret = -ENOIOCTLCMD; break; } /* release the mutexes */ up(&cp->mutex); up(&ccp->mutex); return ret;}/* Read data from the device */static ssize_t auerchar_read (struct file *file, char __user *buf, size_t count, loff_t * ppos){ unsigned long flags; pauerchar_t ccp = (pauerchar_t) file->private_data; pauerbuf_t bp = NULL; wait_queue_t wait; dbg ("auerchar_read"); /* Error checking */ if (!ccp) return -EIO; if (*ppos) return -ESPIPE; if (count == 0) return 0; /* get the mutex */ if (down_interruptible (&ccp->mutex)) return -ERESTARTSYS; /* Can we expect to read something? */ if (ccp->scontext.id == AUH_UNASSIGNED) { up (&ccp->mutex); return -EIO; } /* only one reader per device allowed */ if (down_interruptible (&ccp->readmutex)) { up (&ccp->mutex); return -ERESTARTSYS; } /* read data from readbuf, if available */doreadbuf: bp = ccp->readbuf; if (bp) { /* read the maximum bytes */ int restlen = bp->len - ccp->readoffset; if (restlen < 0) restlen = 0; if (count > restlen) count = restlen; if (count) { if (copy_to_user (buf, bp->bufp+ccp->readoffset, count)) { dbg ("auerswald_read: copy_to_user failed"); up (&ccp->readmutex); up (&ccp->mutex); return -EFAULT; } } /* advance the read offset */ ccp->readoffset += count;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -