📄 auerswald.c
字号:
restlen -= count; // reuse the read buffer if (restlen <= 0) { auerbuf_releasebuf (bp); ccp->readbuf = NULL; } /* return with number of bytes read */ if (count) { up (&ccp->readmutex); up (&ccp->mutex); return count; } } /* a read buffer is not available. Try to get the next data block. */doreadlist: /* Preparing for sleep */ init_waitqueue_entry (&wait, current); set_current_state (TASK_INTERRUPTIBLE); add_wait_queue (&ccp->readwait, &wait); bp = NULL; spin_lock_irqsave (&ccp->bufctl.lock, flags); if (!list_empty (&ccp->bufctl.rec_buff_list)) { /* yes: get the entry */ struct list_head *tmp = ccp->bufctl.rec_buff_list.next; list_del (tmp); bp = list_entry (tmp, auerbuf_t, buff_list); } spin_unlock_irqrestore (&ccp->bufctl.lock, flags); /* have we got data? */ if (bp) { ccp->readbuf = bp; ccp->readoffset = AUH_SIZE; /* for headerbyte */ set_current_state (TASK_RUNNING); remove_wait_queue (&ccp->readwait, &wait); goto doreadbuf; /* now we can read! */ } /* no data available. Should we wait? */ if (file->f_flags & O_NONBLOCK) { dbg ("No read buffer available, returning -EAGAIN"); set_current_state (TASK_RUNNING); remove_wait_queue (&ccp->readwait, &wait); up (&ccp->readmutex); up (&ccp->mutex); return -EAGAIN; /* nonblocking, no data available */ } /* yes, we should wait! */ up (&ccp->mutex); /* allow other operations while we wait */ schedule(); remove_wait_queue (&ccp->readwait, &wait); if (signal_pending (current)) { /* waked up by a signal */ up (&ccp->readmutex); return -ERESTARTSYS; } /* Anything left to read? */ if ((ccp->scontext.id == AUH_UNASSIGNED) || ccp->removed) { up (&ccp->readmutex); return -EIO; } if (down_interruptible (&ccp->mutex)) { up (&ccp->readmutex); return -ERESTARTSYS; } /* try to read the incoming data again */ goto doreadlist;}/* Write a data block into the right service channel of the device */static ssize_t auerchar_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos){ pauerchar_t ccp = (pauerchar_t) file->private_data; pauerswald_t cp = NULL; pauerbuf_t bp; unsigned long flags; int ret; wait_queue_t wait; dbg ("auerchar_write %zd bytes", len); /* Error checking */ if (!ccp) return -EIO; if (*ppos) return -ESPIPE; if (len == 0) return 0;write_again: /* get the mutex */ if (down_interruptible (&ccp->mutex)) return -ERESTARTSYS; /* Can we expect to write something? */ if (ccp->scontext.id == AUH_UNASSIGNED) { up (&ccp->mutex); return -EIO; } cp = ccp->auerdev; if (!cp) { up (&ccp->mutex); return -ERESTARTSYS; } if (down_interruptible (&cp->mutex)) { up (&ccp->mutex); return -ERESTARTSYS; } if (!cp->usbdev) { up (&cp->mutex); up (&ccp->mutex); return -EIO; } /* Prepare for sleep */ init_waitqueue_entry (&wait, current); set_current_state (TASK_INTERRUPTIBLE); add_wait_queue (&cp->bufferwait, &wait); /* Try to get a buffer from the device pool. We can't use a buffer from ccp->bufctl because the write command will last beond a release() */ bp = NULL; spin_lock_irqsave (&cp->bufctl.lock, flags); if (!list_empty (&cp->bufctl.free_buff_list)) { /* yes: get the entry */ struct list_head *tmp = cp->bufctl.free_buff_list.next; list_del (tmp); bp = list_entry (tmp, auerbuf_t, buff_list); } spin_unlock_irqrestore (&cp->bufctl.lock, flags); /* are there any buffers left? */ if (!bp) { up (&cp->mutex); up (&ccp->mutex); /* NONBLOCK: don't wait */ if (file->f_flags & O_NONBLOCK) { set_current_state (TASK_RUNNING); remove_wait_queue (&cp->bufferwait, &wait); return -EAGAIN; } /* BLOCKING: wait */ schedule(); remove_wait_queue (&cp->bufferwait, &wait); if (signal_pending (current)) { /* waked up by a signal */ return -ERESTARTSYS; } goto write_again; } else { set_current_state (TASK_RUNNING); remove_wait_queue (&cp->bufferwait, &wait); } /* protect against too big write requests */ if (len > cp->maxControlLength) len = cp->maxControlLength; /* Fill the buffer */ if (copy_from_user ( bp->bufp+AUH_SIZE, buf, len)) { dbg ("copy_from_user failed"); auerbuf_releasebuf (bp); /* Wake up all processes waiting for a buffer */ wake_up (&cp->bufferwait); up (&cp->mutex); up (&ccp->mutex); return -EFAULT; } /* set the header byte */ *(bp->bufp) = ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT; /* Set the transfer Parameters */ bp->len = len+AUH_SIZE; bp->dr->bRequestType = AUT_WREQ; bp->dr->bRequest = AUV_WBLOCK; bp->dr->wValue = cpu_to_le16 (0); bp->dr->wIndex = cpu_to_le16 (ccp->scontext.id | AUH_DIRECT | AUH_UNSPLIT); bp->dr->wLength = cpu_to_le16 (len+AUH_SIZE); usb_fill_control_urb (bp->urbp, cp->usbdev, usb_sndctrlpipe (cp->usbdev, 0), (unsigned char*)bp->dr, bp->bufp, len+AUH_SIZE, auerchar_ctrlwrite_complete, bp); /* up we go */ ret = auerchain_submit_urb (&cp->controlchain, bp->urbp); up (&cp->mutex); if (ret) { dbg ("auerchar_write: nonzero result of auerchain_submit_urb %d", ret); auerbuf_releasebuf (bp); /* Wake up all processes waiting for a buffer */ wake_up (&cp->bufferwait); up (&ccp->mutex); return -EIO; } else { dbg ("auerchar_write: Write OK"); up (&ccp->mutex); return len; }}/* Close a character device */static int auerchar_release (struct inode *inode, struct file *file){ pauerchar_t ccp = (pauerchar_t) file->private_data; pauerswald_t cp; dbg("release"); /* get the mutexes */ if (down_interruptible (&ccp->mutex)) { return -ERESTARTSYS; } cp = ccp->auerdev; if (cp) { if (down_interruptible (&cp->mutex)) { up (&ccp->mutex); return -ERESTARTSYS; } /* remove an open service */ auerswald_removeservice (cp, &ccp->scontext); /* detach from device */ if ((--cp->open_count <= 0) && (cp->usbdev == NULL)) { /* usb device waits for removal */ up (&cp->mutex); auerswald_delete (cp); } else { up (&cp->mutex); } cp = NULL; ccp->auerdev = NULL; } up (&ccp->mutex); auerchar_delete (ccp); return 0;}/*----------------------------------------------------------------------*//* File operation structure */static struct file_operations auerswald_fops ={ .owner = THIS_MODULE, .llseek = no_llseek, .read = auerchar_read, .write = auerchar_write, .ioctl = auerchar_ioctl, .open = auerchar_open, .release = auerchar_release,};static struct usb_class_driver auerswald_class = { .name = "auer%d", .fops = &auerswald_fops, .minor_base = AUER_MINOR_BASE,};/* --------------------------------------------------------------------- *//* Special USB driver functions *//* Probe if this driver wants to serve an USB device This entry point is called whenever a new device is attached to the bus. Then the device driver has to create a new instance of its internal data structures for the new device. The dev argument specifies the device context, which contains pointers to all USB descriptors. The interface argument specifies the interface number. If a USB driver wants to bind itself to a particular device and interface it has to return a pointer. This pointer normally references the device driver's context structure. Probing normally is done by checking the vendor and product identifications or the class and subclass definitions. If they match the interface number is compared with the ones supported by the driver. When probing is done class based it might be necessary to parse some more USB descriptors because the device properties can differ in a wide range.*/static int auerswald_probe (struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *usbdev = interface_to_usbdev(intf); pauerswald_t cp = NULL; unsigned int u = 0; __le16 *pbuf; int ret; dbg ("probe: vendor id 0x%x, device id 0x%x", le16_to_cpu(usbdev->descriptor.idVendor), le16_to_cpu(usbdev->descriptor.idProduct)); /* we use only the first -and only- interface */ if (intf->altsetting->desc.bInterfaceNumber != 0) return -ENODEV; /* allocate memory for our device and initialize it */ cp = kmalloc (sizeof(auerswald_t), GFP_KERNEL); if (cp == NULL) { err ("out of memory"); goto pfail; } /* Initialize device descriptor */ memset (cp, 0, sizeof(auerswald_t)); init_MUTEX (&cp->mutex); cp->usbdev = usbdev; auerchain_init (&cp->controlchain); auerbuf_init (&cp->bufctl); init_waitqueue_head (&cp->bufferwait); ret = usb_register_dev(intf, &auerswald_class); if (ret) { err ("Not able to get a minor for this device."); goto pfail; } /* Give the device a name */ sprintf (cp->name, "usb/auer%d", intf->minor); /* Store the index */ cp->dtindex = intf->minor; /* Get the usb version of the device */ cp->version = le16_to_cpu(cp->usbdev->descriptor.bcdDevice); dbg ("Version is %X", cp->version); /* allow some time to settle the device */ msleep(334); /* Try to get a suitable textual description of the device */ /* Device name:*/ ret = usb_string( cp->usbdev, AUSI_DEVICE, cp->dev_desc, AUSI_DLEN-1); if (ret >= 0) { u += ret; /* Append Serial Number */ memcpy(&cp->dev_desc[u], ",Ser# ", 6); u += 6; ret = usb_string( cp->usbdev, AUSI_SERIALNR, &cp->dev_desc[u], AUSI_DLEN-u-1); if (ret >= 0) { u += ret; /* Append subscriber number */ memcpy(&cp->dev_desc[u], ", ", 2); u += 2; ret = usb_string( cp->usbdev, AUSI_MSN, &cp->dev_desc[u], AUSI_DLEN-u-1); if (ret >= 0) { u += ret; } } } cp->dev_desc[u] = '\0'; info("device is a %s", cp->dev_desc); /* get the maximum allowed control transfer length */ pbuf = (__le16 *) kmalloc (2, GFP_KERNEL); /* use an allocated buffer because of urb target */ if (!pbuf) { err( "out of memory"); goto pfail; } ret = usb_control_msg(cp->usbdev, /* pointer to device */ usb_rcvctrlpipe( cp->usbdev, 0 ), /* pipe to control endpoint */ AUV_GETINFO, /* USB message request value */ AUT_RREQ, /* USB message request type value */ 0, /* USB message value */ AUDI_MBCTRANS, /* USB message index value */ pbuf, /* pointer to the receive buffer */ 2, /* length of the buffer */ 2000); /* time to wait for the message to complete before timing out */ if (ret == 2) { cp->maxControlLength = le16_to_cpup(pbuf); kfree(pbuf); dbg("setup: max. allowed control transfersize is %d bytes", cp->maxControlLength); } else { kfree(pbuf); err("setup: getting max. allowed control transfer length failed with error %d", ret); goto pfail; } /* allocate a chain for the control messages */ if (auerchain_setup (&cp->controlchain, AUCH_ELEMENTS)) { err ("out of memory"); goto pfail; } /* allocate buffers for control messages */ if (auerbuf_setup (&cp->bufctl, AU_RBUFFERS, cp->maxControlLength+AUH_SIZE)) { err ("out of memory"); goto pfail; } /* start the interru
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -