/* The defaults are chosen to work with the latest versions of leJOS and NQC.
*/
/* Some legacy software likes to receive packets in one piece. * In this case read_buffer_size should exceed the maximal packet length * (417 for datalog uploads), and packet_timeout should be set.
*/ staticint read_buffer_size = 480;
module_param(read_buffer_size, int, 0);
MODULE_PARM_DESC(read_buffer_size, "Read buffer size");
/* Some legacy software likes to send packets in one piece. * In this case write_buffer_size should exceed the maximal packet length * (417 for firmware and program downloads). * A problem with long writes is that the following read may time out * if the software is not prepared to wait long enough.
*/ staticint write_buffer_size = 480;
module_param(write_buffer_size, int, 0);
MODULE_PARM_DESC(write_buffer_size, "Write buffer size");
/* Some legacy software expects reads to contain whole LASM packets. * To achieve this, characters which arrive before a packet timeout * occurs will be returned in a single read operation. * A problem with long reads is that the software may time out * if it is not prepared to wait long enough. * The packet timeout should be greater than the time between the * reception of subsequent characters, which should arrive about * every 5ms for the standard 2400 baud. * Set it to 0 to disable.
*/ staticint packet_timeout = 50;
module_param(packet_timeout, int, 0);
MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms");
/* Some legacy software expects blocking reads to time out. * Timeout occurs after the specified time of read and write inactivity. * Set it to 0 to disable.
*/ staticint read_timeout = 200;
module_param(read_timeout, int, 0);
MODULE_PARM_DESC(read_timeout, "Read timeout in ms");
/* As of kernel version 2.6.4 ehci-hcd uses an * "only one interrupt transfer per frame" shortcut * to simplify the scheduling of periodic transfers. * This conflicts with our standard 1ms intervals for in and out URBs. * We use default intervals of 2ms for in and 8ms for out transfers, * which is fast enough for 2400 baud and allows a small additional load. * Increase the interval to allow more devices that do interrupt transfers, * or set to 0 to use the standard interval from the endpoint descriptors.
*/ staticint interrupt_in_interval = 2;
module_param(interrupt_in_interval, int, 0);
MODULE_PARM_DESC(interrupt_in_interval, "Interrupt in interval in ms");
staticint interrupt_out_interval = 8;
module_param(interrupt_out_interval, int, 0);
MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms");
/* Define these values to match your device */ #define LEGO_USB_TOWER_VENDOR_ID 0x0694 #define LEGO_USB_TOWER_PRODUCT_ID 0x0001
/* table of devices that work with this driver */ staticconststruct usb_device_id tower_table[] = {
{ USB_DEVICE(LEGO_USB_TOWER_VENDOR_ID, LEGO_USB_TOWER_PRODUCT_ID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, tower_table);
#define LEGO_USB_TOWER_MINOR_BASE 160
/* Structure to hold all of our device specific stuff */ struct lego_usb_tower { struct mutex lock; /* locks this structure */ struct usb_device *udev; /* save off the usb device pointer */ unsignedchar minor; /* the starting minor number for this device */
int open_count; /* number of times this port has been opened */ unsignedlong disconnected:1;
char *read_buffer;
size_t read_buffer_length; /* this much came in */
size_t read_packet_length; /* this much will be returned on read */
spinlock_t read_buffer_lock; int packet_timeout_jiffies; unsignedlong read_last_arrival;
/* * usb class driver info in order to get a minor number from the usb core, * and to have the device registered with the driver core
*/ staticstruct usb_class_driver tower_class = {
.name = "legousbtower%d",
.devnode = legousbtower_devnode,
.fops = &tower_fops,
.minor_base = LEGO_USB_TOWER_MINOR_BASE,
};
/* usb specific object needed to register this driver with the usb subsystem */ staticstruct usb_driver tower_driver = {
.name = "legousbtower",
.probe = tower_probe,
.disconnect = tower_disconnect,
.id_table = tower_table,
};
dev = file->private_data; if (dev == NULL) {
retval = -ENODEV; gotoexit;
}
mutex_lock(&dev->lock);
if (dev->disconnected) { /* the device was unplugged before the file was released */
/* unlock here as tower_delete frees dev */
mutex_unlock(&dev->lock);
tower_delete(dev); gotoexit;
}
/* wait until write transfer is finished */ if (dev->interrupt_out_busy) {
wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy,
2 * HZ);
}
/* * tower_check_for_read_packet * * To get correct semantics for signals and non-blocking I/O * with packetizing we pretend not to see any data in the read buffer * until it has been there unchanged for at least * dev->packet_timeout_jiffies, or until the buffer is full.
*/ staticvoid tower_check_for_read_packet(struct lego_usb_tower *dev)
{
spin_lock_irq(&dev->read_buffer_lock); if (!packet_timeout
|| time_after(jiffies, dev->read_last_arrival + dev->packet_timeout_jiffies)
|| dev->read_buffer_length == read_buffer_size) {
dev->read_packet_length = dev->read_buffer_length;
}
dev->interrupt_in_done = 0;
spin_unlock_irq(&dev->read_buffer_lock);
}
/* * tower_probe * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in.
*/ staticint tower_probe(struct usb_interface *interface, conststruct usb_device_id *id)
{ struct device *idev = &interface->dev; struct usb_device *udev = interface_to_usbdev(interface); struct lego_usb_tower *dev; struct tower_get_version_reply get_version_reply; int retval = -ENOMEM; int result;
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) gotoexit;
/* get the firmware version and log it */
result = usb_control_msg_recv(udev, 0,
LEGO_USB_TOWER_REQUEST_GET_VERSION,
USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
0,
0,
&get_version_reply, sizeof(get_version_reply),
1000, GFP_KERNEL); if (result) {
dev_err(idev, "get version request failed: %d\n", result);
retval = result; goto error;
}
dev_info(&interface->dev, "LEGO USB Tower firmware version is %d.%d build %d\n",
get_version_reply.major,
get_version_reply.minor,
le16_to_cpu(get_version_reply.build_no));
/* we can register the device now, as it is ready */
usb_set_intfdata(interface, dev);
retval = usb_register_dev(interface, &tower_class); if (retval) { /* something prevented us from registering this driver */
dev_err(idev, "Not able to get a minor for this device.\n"); goto error;
}
dev->minor = interface->minor;
/* let the user know what node this device is now attached to */
dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major " "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE),
USB_MAJOR, dev->minor);
exit: return retval;
error:
tower_delete(dev); return retval;
}
/* * tower_disconnect * * Called by the usb core when the device is removed from the system.
*/ staticvoid tower_disconnect(struct usb_interface *interface)
{ struct lego_usb_tower *dev; int minor;
dev = usb_get_intfdata(interface);
minor = dev->minor;
/* give back our minor and prevent further open() */
usb_deregister_dev(interface, &tower_class);
/* if the device is not opened, then we clean up right now */ if (!dev->open_count) {
mutex_unlock(&dev->lock);
tower_delete(dev);
} else {
dev->disconnected = 1; /* wake up pollers */
wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait);
mutex_unlock(&dev->lock);
}
dev_info(&interface->dev, "LEGO USB Tower #%d now disconnected\n",
(minor - LEGO_USB_TOWER_MINOR_BASE));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.