[Linux1394-cvslog] rev 808 - branches/linux-2.4
Brought to you by:
aeb,
bencollins
From: SVN U. <dm...@li...> - 2003-03-01 00:25:53
|
Author: dmaas Date: 2003-02-28 19:24:50 -0500 (Fri, 28 Feb 2003) New Revision: 808 Added: branches/linux-2.4/iso.c branches/linux-2.4/iso.h branches/linux-2.4/raw1394-private.h Modified: branches/linux-2.4/Makefile branches/linux-2.4/dv1394.c branches/linux-2.4/hosts.h branches/linux-2.4/ieee1394-ioctl.h branches/linux-2.4/ieee1394_core.c branches/linux-2.4/ohci1394.c branches/linux-2.4/raw1394.c branches/linux-2.4/raw1394.h Log: sync raw1394 and iso with trunk (rawiso merge part 1) Added: branches/linux-2.4/iso.h ============================================================================== --- branches/linux-2.4/iso.h (original) +++ branches/linux-2.4/iso.h 2003-02-28 19:24:52.000000000 -0500 @@ -0,0 +1,184 @@ +/* + * IEEE 1394 for Linux + * + * kernel ISO transmission/reception + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#ifndef IEEE1394_ISO_H +#define IEEE1394_ISO_H + +#include "hosts.h" +#include "dma.h" + +/* high-level ISO interface */ + +/* This API sends and receives isochronous packets on a large, + virtually-contiguous kernel memory buffer. The buffer may be mapped + into a user-space process for zero-copy transmission and reception. + + There are no explicit boundaries between packets in the buffer. A + packet may be transmitted or received at any location. However, + low-level drivers may impose certain restrictions on alignment or + size of packets. (e.g. in OHCI no packet may cross a page boundary, + and packets should be quadlet-aligned) +*/ + +/* Packet descriptor - the API maintains a ring buffer of these packet + descriptors in kernel memory (hpsb_iso.infos[]). */ + +struct hpsb_iso_packet_info { + /* offset of data payload relative to the first byte of the buffer */ + __u32 offset; + + /* length of the data payload, in bytes (not including the isochronous header) */ + __u16 len; + + /* (recv only) the cycle number (mod 8000) on which the packet was received */ + __u16 cycle; + + /* (recv only) channel on which the packet was received */ + __u8 channel; + + /* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */ + __u8 tag; + __u8 sy; +}; + +enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 }; + +struct hpsb_iso { + enum hpsb_iso_type type; + + /* pointer to low-level driver and its private data */ + struct hpsb_host *host; + void *hostdata; + + /* a function to be called (from interrupt context) after + outgoing packets have been sent, or incoming packets have + arrived */ + void (*callback)(struct hpsb_iso*); + + /* wait for buffer space */ + wait_queue_head_t waitq; + + int speed; /* SPEED_100, 200, or 400 */ + int channel; /* -1 if multichannel */ + + /* greatest # of packets between interrupts - controls + the maximum latency of the buffer */ + int irq_interval; + + /* the buffer for packet data payloads */ + struct dma_region data_buf; + + /* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */ + unsigned int buf_size; + + /* ringbuffer of packet descriptors in regular kernel memory */ + struct hpsb_iso_packet_info *infos; + + /* # of packets in the ringbuffer */ + unsigned int buf_packets; + + /* protects packet cursors */ + spinlock_t lock; + + /* the index of the next packet that will be produced + or consumed by the user */ + int first_packet; + + /* the index of the next packet that will be transmitted + or received by the 1394 hardware */ + int pkt_dma; + + /* how many packets, starting at first_packet: + (transmit) are ready to be filled with data + (receive) contain received data */ + int n_ready_packets; + + /* how many times the buffer has overflowed or underflowed */ + atomic_t overflows; + + /* private flags to track initialization progress */ +#define HPSB_ISO_DRIVER_INIT (1<<0) +#define HPSB_ISO_DRIVER_STARTED (1<<1) + unsigned int flags; + + /* # of packets left to prebuffer (xmit only) */ + int prebuffer; + + /* starting cycle for DMA (xmit only) */ + int start_cycle; + + /* cycle at which next packet will be transmitted, + -1 if not known */ + int xmit_cycle; +}; + +/* functions available to high-level drivers (e.g. raw1394) */ + +/* allocate the buffer and DMA context */ + +struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int speed, + int irq_interval, + void (*callback)(struct hpsb_iso*)); + +/* note: if channel = -1, multi-channel receive is enabled */ +struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)); + +/* multi-channel only */ +int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel); +int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel); +int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask); + +/* start/stop DMA */ +int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle, int prebuffer); +int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle, int tag_mask, int sync); +void hpsb_iso_stop(struct hpsb_iso *iso); + +/* deallocate buffer and DMA context */ +void hpsb_iso_shutdown(struct hpsb_iso *iso); + +/* queue a packet for transmission. 'offset' is relative to the beginning of the + DMA buffer, where the packet's data payload should already have been placed */ +int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy); + +/* wait until all queued packets have been transmitted to the bus */ +int hpsb_iso_xmit_sync(struct hpsb_iso *iso); + +/* N packets have been read out of the buffer, re-use the buffer space */ +int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, unsigned int n_packets); + +/* returns # of packets ready to send or receive */ +int hpsb_iso_n_ready(struct hpsb_iso *iso); + +/* the following are callbacks available to low-level drivers */ + +/* call after a packet has been transmitted to the bus (interrupt context is OK) + 'cycle' is the _exact_ cycle the packet was sent on + 'error' should be non-zero if some sort of error occurred when sending the packet +*/ +void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error); + +/* call after a packet has been received (interrupt context OK) */ +void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, + u16 cycle, u8 channel, u8 tag, u8 sy); + +/* call to wake waiting processes after buffer space has opened up. */ +void hpsb_iso_wake(struct hpsb_iso *iso); + +#endif /* IEEE1394_ISO_H */ Modified: branches/linux-2.4/ieee1394_core.c ============================================================================== --- branches/linux-2.4/ieee1394_core.c (original) +++ branches/linux-2.4/ieee1394_core.c 2003-02-28 19:24:52.000000000 -0500 @@ -43,6 +43,7 @@ #include "nodemgr.h" #include "ieee1394_hotplug.h" #include "dma.h" +#include "iso.h" /* * Disable the nodemgr detection and config rom reading functionality. @@ -1144,14 +1145,17 @@ module_exit(ieee1394_cleanup); /* Exported symbols */ + +/** hosts.c **/ EXPORT_SYMBOL(hpsb_alloc_host); EXPORT_SYMBOL(hpsb_add_host); EXPORT_SYMBOL(hpsb_remove_host); EXPORT_SYMBOL(hpsb_ref_host); EXPORT_SYMBOL(hpsb_unref_host); + +/** ieee1394_core.c **/ EXPORT_SYMBOL(hpsb_speedto_str); EXPORT_SYMBOL(hpsb_add_packet_complete_task); - EXPORT_SYMBOL(alloc_hpsb_packet); EXPORT_SYMBOL(free_hpsb_packet); EXPORT_SYMBOL(hpsb_send_packet); @@ -1161,7 +1165,12 @@ EXPORT_SYMBOL(hpsb_selfid_complete); EXPORT_SYMBOL(hpsb_packet_sent); EXPORT_SYMBOL(hpsb_packet_received); +EXPORT_SYMBOL(ieee1394_register_chardev); +EXPORT_SYMBOL(ieee1394_unregister_chardev); +EXPORT_SYMBOL(ieee1394_devfs_handle); +EXPORT_SYMBOL(ieee1394_procfs_entry); +/** ieee1394_transactions.c **/ EXPORT_SYMBOL(get_tlabel); EXPORT_SYMBOL(free_tlabel); EXPORT_SYMBOL(fill_async_readquad); @@ -1188,6 +1197,7 @@ EXPORT_SYMBOL(hpsb_write); EXPORT_SYMBOL(hpsb_lock); +/** highlevel.c **/ EXPORT_SYMBOL(hpsb_register_highlevel); EXPORT_SYMBOL(hpsb_unregister_highlevel); EXPORT_SYMBOL(hpsb_register_addrspace); @@ -1202,6 +1212,7 @@ EXPORT_SYMBOL(highlevel_remove_host); EXPORT_SYMBOL(highlevel_host_reset); +/** nodemgr.c **/ EXPORT_SYMBOL(hpsb_guid_get_entry); EXPORT_SYMBOL(hpsb_nodeid_get_entry); EXPORT_SYMBOL(hpsb_node_fill_packet); @@ -1214,12 +1225,6 @@ EXPORT_SYMBOL(hpsb_unregister_protocol); EXPORT_SYMBOL(hpsb_release_unit_directory); -EXPORT_SYMBOL(ieee1394_register_chardev); -EXPORT_SYMBOL(ieee1394_unregister_chardev); -EXPORT_SYMBOL(ieee1394_devfs_handle); - -EXPORT_SYMBOL(ieee1394_procfs_entry); - /** dma.c **/ EXPORT_SYMBOL(dma_prog_region_init); EXPORT_SYMBOL(dma_prog_region_alloc); @@ -1231,3 +1236,21 @@ EXPORT_SYMBOL(dma_region_mmap); EXPORT_SYMBOL(dma_region_offset_to_bus); +/** iso.c **/ +EXPORT_SYMBOL(hpsb_iso_xmit_init); +EXPORT_SYMBOL(hpsb_iso_recv_init); +EXPORT_SYMBOL(hpsb_iso_xmit_start); +EXPORT_SYMBOL(hpsb_iso_recv_start); +EXPORT_SYMBOL(hpsb_iso_recv_listen_channel); +EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel); +EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask); +EXPORT_SYMBOL(hpsb_iso_stop); +EXPORT_SYMBOL(hpsb_iso_shutdown); +EXPORT_SYMBOL(hpsb_iso_xmit_queue_packet); +EXPORT_SYMBOL(hpsb_iso_xmit_sync); +EXPORT_SYMBOL(hpsb_iso_recv_release_packets); +EXPORT_SYMBOL(hpsb_iso_n_ready); +EXPORT_SYMBOL(hpsb_iso_packet_sent); +EXPORT_SYMBOL(hpsb_iso_packet_received); +EXPORT_SYMBOL(hpsb_iso_wake); + Modified: branches/linux-2.4/ohci1394.c ============================================================================== --- branches/linux-2.4/ohci1394.c (original) +++ branches/linux-2.4/ohci1394.c 2003-02-28 19:24:52.000000000 -0500 @@ -1969,6 +1969,7 @@ .get_rom = ohci_get_rom, .transmit_packet = ohci_transmit, .devctl = ohci_devctl, + .isoctl = NULL, /* temporary */ .hw_csr_reg = ohci_hw_csr_reg, }; Modified: branches/linux-2.4/ieee1394-ioctl.h ============================================================================== --- branches/linux-2.4/ieee1394-ioctl.h (original) +++ branches/linux-2.4/ieee1394-ioctl.h 2003-02-28 19:24:52.000000000 -0500 @@ -68,4 +68,38 @@ #define VIDEO1394_IOC_LISTEN_POLL_BUFFER \ _IOWR('#', 0x18, struct video1394_wait) + +/* Raw1394's ISO interface */ +#define RAW1394_IOC_ISO_XMIT_INIT \ + _IOW ('#', 0x1a, struct raw1394_iso_status) +#define RAW1394_IOC_ISO_RECV_INIT \ + _IOWR('#', 0x1b, struct raw1394_iso_status) +#define RAW1394_IOC_ISO_RECV_START \ + _IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3) +#define RAW1394_IOC_ISO_XMIT_START \ + _IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2) +#define RAW1394_IOC_ISO_XMIT_RECV_STOP \ + _IO ('#', 0x1e) +#define RAW1394_IOC_ISO_GET_STATUS \ + _IOR ('#', 0x1f, struct raw1394_iso_status) +#define RAW1394_IOC_ISO_SHUTDOWN \ + _IO ('#', 0x20) +#define RAW1394_IOC_ISO_QUEUE_ACTIVITY \ + _IO ('#', 0x21) +#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL \ + _IOW ('#', 0x22, unsigned char) +#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL \ + _IOW ('#', 0x23, unsigned char) +#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK \ + _IOW ('#', 0x24, __u64) +#define RAW1394_IOC_ISO_RECV_PACKETS \ + _IOW ('#', 0x25, struct raw1394_iso_packets) +#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS \ + _IOW ('#', 0x26, unsigned int) +#define RAW1394_IOC_ISO_XMIT_PACKETS \ + _IOW ('#', 0x27, struct raw1394_iso_packets) +#define RAW1394_IOC_ISO_XMIT_SYNC \ + _IO ('#', 0x28) + + #endif /* __IEEE1394_IOCTL_H */ Modified: branches/linux-2.4/raw1394.c ============================================================================== --- branches/linux-2.4/raw1394.c (original) +++ branches/linux-2.4/raw1394.c 2003-02-28 19:24:52.000000000 -0500 @@ -46,9 +46,10 @@ #include "ieee1394_core.h" #include "hosts.h" #include "highlevel.h" +#include "iso.h" #include "ieee1394_transactions.h" #include "raw1394.h" - +#include "raw1394-private.h" #if BITS_PER_LONG == 64 #define int2ptr(x) ((void *)x) @@ -90,10 +91,10 @@ static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store, u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags); static struct hpsb_address_ops arm_ops = { - read: arm_read, - write: arm_write, - lock: arm_lock, - lock64: arm_lock64, + .read = arm_read, + .write = arm_write, + .lock = arm_lock, + .lock64 = arm_lock64, }; static void queue_complete_cb(struct pending_request *req); @@ -132,18 +133,25 @@ kfree(req); } +/* fi->reqlists_lock must be taken */ +static void __queue_complete_req(struct pending_request *req) +{ + struct file_info *fi = req->file_info; + list_del(&req->list); + list_add_tail(&req->list, &fi->req_complete); + + up(&fi->complete_sem); + wake_up_interruptible(&fi->poll_wait_complete); +} + static void queue_complete_req(struct pending_request *req) { unsigned long flags; struct file_info *fi = req->file_info; spin_lock_irqsave(&fi->reqlists_lock, flags); - list_del(&req->list); - list_add_tail(&req->list, &fi->req_complete); + __queue_complete_req(req); spin_unlock_irqrestore(&fi->reqlists_lock, flags); - - up(&fi->complete_sem); - wake_up_interruptible(&fi->poll_wait_complete); } static void queue_complete_cb(struct pending_request *req) @@ -2000,6 +2008,323 @@ return retval; } +/* rawiso operations */ + +/* check if any RAW1394_REQ_RAWISO_ACTIVITY event is already in the + * completion queue (reqlists_lock must be taken) */ +static inline int __rawiso_event_in_queue(struct file_info *fi) +{ + struct list_head *lh; + struct pending_request *req; + + list_for_each(lh, &fi->req_complete) { + req = list_entry(lh, struct pending_request, list); + if(req->req.type == RAW1394_REQ_RAWISO_ACTIVITY) { + return 1; + } + } + + return 0; +} + +/* put a RAWISO_ACTIVITY event in the queue, if one isn't there already */ +static void queue_rawiso_event(struct file_info *fi) +{ + unsigned long flags; + + spin_lock_irqsave(&fi->reqlists_lock, flags); + + /* only one ISO activity event may be in the queue */ + if(!__rawiso_event_in_queue(fi)) { + struct pending_request *req = __alloc_pending_request(SLAB_ATOMIC); + + if(req) { + req->file_info = fi; + req->req.type = RAW1394_REQ_RAWISO_ACTIVITY; + req->req.generation = get_hpsb_generation(fi->host); + __queue_complete_req(req); + } else { + /* on allocation failure, signal an overflow */ + if(fi->iso_handle) { + atomic_inc(&fi->iso_handle->overflows); + } + } + } + spin_unlock_irqrestore(&fi->reqlists_lock, flags); +} + +static void rawiso_activity_cb(struct hpsb_iso *iso) +{ + unsigned long flags; + struct list_head *lh; + struct host_info *hi; + + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(iso->host); + + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + struct file_info *fi = list_entry(lh, struct file_info, list); + if(fi->iso_handle == iso) + queue_rawiso_event(fi); + } + } + + spin_unlock_irqrestore(&host_info_lock, flags); +} + +/* helper function - gather all the kernel iso status bits for returning to user-space */ +static void raw1394_iso_fill_status(struct hpsb_iso *iso, struct raw1394_iso_status *stat) +{ + stat->config.data_buf_size = iso->buf_size; + stat->config.buf_packets = iso->buf_packets; + stat->config.channel = iso->channel; + stat->config.speed = iso->speed; + stat->config.irq_interval = iso->irq_interval; + stat->n_packets = hpsb_iso_n_ready(iso); + stat->overflows = atomic_read(&iso->overflows); + stat->xmit_cycle = iso->xmit_cycle; +} + +static int raw1394_iso_xmit_init(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_status stat; + + if(copy_from_user(&stat, uaddr, sizeof(stat))) + return -EFAULT; + + fi->iso_handle = hpsb_iso_xmit_init(fi->host, + stat.config.data_buf_size, + stat.config.buf_packets, + stat.config.channel, + stat.config.speed, + stat.config.irq_interval, + rawiso_activity_cb); + if(!fi->iso_handle) + return -ENOMEM; + + fi->iso_state = RAW1394_ISO_XMIT; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; + + /* queue an event to get things started */ + rawiso_activity_cb(fi->iso_handle); + + return 0; +} + +static int raw1394_iso_recv_init(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_status stat; + + if(copy_from_user(&stat, uaddr, sizeof(stat))) + return -EFAULT; + + fi->iso_handle = hpsb_iso_recv_init(fi->host, + stat.config.data_buf_size, + stat.config.buf_packets, + stat.config.channel, + stat.config.irq_interval, + rawiso_activity_cb); + if(!fi->iso_handle) + return -ENOMEM; + + fi->iso_state = RAW1394_ISO_RECV; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; + return 0; +} + +static int raw1394_iso_get_status(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_status stat; + struct hpsb_iso *iso = fi->iso_handle; + + raw1394_iso_fill_status(fi->iso_handle, &stat); + if(copy_to_user(uaddr, &stat, sizeof(stat))) + return -EFAULT; + + /* reset overflow counter */ + atomic_set(&iso->overflows, 0); + + return 0; +} + +/* copy N packet_infos out of the ringbuffer into user-supplied array */ +static int raw1394_iso_recv_packets(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_packets upackets; + unsigned int packet = fi->iso_handle->first_packet; + int i; + + if(copy_from_user(&upackets, uaddr, sizeof(upackets))) + return -EFAULT; + + if(upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) + return -EINVAL; + + /* ensure user-supplied buffer is accessible and big enough */ + if(verify_area(VERIFY_WRITE, upackets.infos, + upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + /* copy the packet_infos out */ + for(i = 0; i < upackets.n_packets; i++) { + if(__copy_to_user(&upackets.infos[i], + &fi->iso_handle->infos[packet], + sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + packet = (packet + 1) % fi->iso_handle->buf_packets; + } + + return 0; +} + +/* copy N packet_infos from user to ringbuffer, and queue them for transmission */ +static int raw1394_iso_send_packets(struct file_info *fi, void *uaddr) +{ + struct raw1394_iso_packets upackets; + int i, rv; + + if(copy_from_user(&upackets, uaddr, sizeof(upackets))) + return -EFAULT; + + if(upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle)) + return -EINVAL; + + /* ensure user-supplied buffer is accessible and big enough */ + if(verify_area(VERIFY_READ, upackets.infos, + upackets.n_packets * sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + /* copy the infos structs in and queue the packets */ + for(i = 0; i < upackets.n_packets; i++) { + struct raw1394_iso_packet_info info; + + if(__copy_from_user(&info, &upackets.infos[i], + sizeof(struct raw1394_iso_packet_info))) + return -EFAULT; + + rv = hpsb_iso_xmit_queue_packet(fi->iso_handle, info.offset, + info.len, info.tag, info.sy); + if(rv) + return rv; + } + + return 0; +} + +static void raw1394_iso_shutdown(struct file_info *fi) +{ + if(fi->iso_handle) + hpsb_iso_shutdown(fi->iso_handle); + + fi->iso_handle = NULL; + fi->iso_state = RAW1394_ISO_INACTIVE; +} + +/* mmap the rawiso xmit/recv buffer */ +static int raw1394_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct file_info *fi = file->private_data; + + if(fi->iso_state == RAW1394_ISO_INACTIVE) + return -EINVAL; + + return dma_region_mmap(&fi->iso_handle->data_buf, file, vma); +} + +/* ioctl is only used for rawiso operations */ +static int raw1394_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct file_info *fi = file->private_data; + + switch(fi->iso_state) { + case RAW1394_ISO_INACTIVE: + switch(cmd) { + case RAW1394_IOC_ISO_XMIT_INIT: + return raw1394_iso_xmit_init(fi, (void*) arg); + case RAW1394_IOC_ISO_RECV_INIT: + return raw1394_iso_recv_init(fi, (void*) arg); + default: + break; + } + break; + case RAW1394_ISO_RECV: + switch(cmd) { + case RAW1394_IOC_ISO_RECV_START: { + /* copy args from user-space */ + int args[3]; + if(copy_from_user(&args[0], (void*) arg, sizeof(args))) + return -EFAULT; + return hpsb_iso_recv_start(fi->iso_handle, args[0], args[1], args[2]); + } + case RAW1394_IOC_ISO_XMIT_RECV_STOP: + hpsb_iso_stop(fi->iso_handle); + return 0; + case RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL: + return hpsb_iso_recv_listen_channel(fi->iso_handle, arg); + case RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL: + return hpsb_iso_recv_unlisten_channel(fi->iso_handle, arg); + case RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK: { + /* copy the u64 from user-space */ + u64 mask; + if(copy_from_user(&mask, (void*) arg, sizeof(mask))) + return -EFAULT; + return hpsb_iso_recv_set_channel_mask(fi->iso_handle, mask); + } + case RAW1394_IOC_ISO_GET_STATUS: + return raw1394_iso_get_status(fi, (void*) arg); + case RAW1394_IOC_ISO_RECV_PACKETS: + return raw1394_iso_recv_packets(fi, (void*) arg); + case RAW1394_IOC_ISO_RECV_RELEASE_PACKETS: + return hpsb_iso_recv_release_packets(fi->iso_handle, arg); + case RAW1394_IOC_ISO_SHUTDOWN: + raw1394_iso_shutdown(fi); + return 0; + case RAW1394_IOC_ISO_QUEUE_ACTIVITY: + queue_rawiso_event(fi); + return 0; + } + break; + case RAW1394_ISO_XMIT: + switch(cmd) { + case RAW1394_IOC_ISO_XMIT_START: { + /* copy two ints from user-space */ + int args[2]; + if(copy_from_user(&args[0], (void*) arg, sizeof(args))) + return -EFAULT; + return hpsb_iso_xmit_start(fi->iso_handle, args[0], args[1]); + } + case RAW1394_IOC_ISO_XMIT_SYNC: + return hpsb_iso_xmit_sync(fi->iso_handle); + case RAW1394_IOC_ISO_XMIT_RECV_STOP: + hpsb_iso_stop(fi->iso_handle); + return 0; + case RAW1394_IOC_ISO_GET_STATUS: + return raw1394_iso_get_status(fi, (void*) arg); + case RAW1394_IOC_ISO_XMIT_PACKETS: + return raw1394_iso_send_packets(fi, (void*) arg); + case RAW1394_IOC_ISO_SHUTDOWN: + raw1394_iso_shutdown(fi); + return 0; + case RAW1394_IOC_ISO_QUEUE_ACTIVITY: + queue_rawiso_event(fi); + return 0; + } + break; + default: + break; + } + + return -EINVAL; +} + static unsigned int raw1394_poll(struct file *file, poll_table *pt) { struct file_info *fi = file->private_data; @@ -2060,6 +2385,9 @@ struct arm_addr *arm_addr = NULL; int another_host; + if(fi->iso_state != RAW1394_ISO_INACTIVE) + raw1394_iso_shutdown(fi); + for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { hpsb_unlisten_channel(hl_handle, fi->host, i); @@ -2121,7 +2449,7 @@ spin_unlock_irq(&host_info_lock); if (fail > 0) { printk(KERN_ERR "raw1394: during addr_list-release " - "error(s) occured \n"); + "error(s) occurred \n"); } while (!done) { @@ -2167,7 +2495,9 @@ static struct file_operations file_ops = { .owner = THIS_MODULE, .read = raw1394_read, - .write = raw1394_write, + .write = raw1394_write, + .mmap = raw1394_mmap, + .ioctl = raw1394_ioctl, .poll = raw1394_poll, .open = raw1394_open, .release = raw1394_release, Modified: branches/linux-2.4/raw1394.h ============================================================================== --- branches/linux-2.4/raw1394.h (original) +++ branches/linux-2.4/raw1394.h 2003-02-28 19:24:52.000000000 -0500 @@ -1,8 +1,7 @@ #ifndef IEEE1394_RAW1394_H #define IEEE1394_RAW1394_H -#define RAW1394_DEVICE_MAJOR 171 -#define RAW1394_DEVICE_NAME "raw1394" +/* header for the raw1394 API that is exported to user-space */ #define RAW1394_KERNELAPI_VERSION 4 @@ -36,10 +35,11 @@ #define RAW1394_REQ_PHYPACKET 500 /* kernel to user */ -#define RAW1394_REQ_BUS_RESET 10000 -#define RAW1394_REQ_ISO_RECEIVE 10001 -#define RAW1394_REQ_FCP_REQUEST 10002 -#define RAW1394_REQ_ARM 10003 +#define RAW1394_REQ_BUS_RESET 10000 +#define RAW1394_REQ_ISO_RECEIVE 10001 +#define RAW1394_REQ_FCP_REQUEST 10002 +#define RAW1394_REQ_ARM 10003 +#define RAW1394_REQ_RAWISO_ACTIVITY 10004 /* error codes */ #define RAW1394_ERROR_NONE 0 @@ -93,21 +93,21 @@ }; typedef struct arm_request { - nodeid_t destination_nodeid; - nodeid_t source_nodeid; - nodeaddr_t destination_offset; - u8 tlabel; - u8 tcode; - u_int8_t extended_transaction_code; - u_int32_t generation; - arm_length_t buffer_length; - byte_t *buffer; + __u16 destination_nodeid; + __u16 source_nodeid; + __u64 destination_offset; + __u8 tlabel; + __u8 tcode; + __u8 extended_transaction_code; + __u32 generation; + __u16 buffer_length; + __u8 *buffer; } *arm_request_t; typedef struct arm_response { - int response_code; - arm_length_t buffer_length; - byte_t *buffer; + __s32 response_code; + __u16 buffer_length; + __u8 *buffer; } *arm_response_t; typedef struct arm_request_response { @@ -115,68 +115,60 @@ struct arm_response *response; } *arm_request_response_t; -#ifdef __KERNEL__ +/* rawiso API */ +#include "ieee1394-ioctl.h" -struct iso_block_store { - atomic_t refcount; - size_t data_size; - quadlet_t data[0]; +/* per-packet metadata embedded in the ringbuffer */ +/* must be identical to hpsb_iso_packet_info in iso.h! */ +struct raw1394_iso_packet_info { + __u32 offset; + __u16 len; + __u16 cycle; /* recv only */ + __u8 channel; /* recv only */ + __u8 tag; + __u8 sy; }; -struct file_info { - struct list_head list; - - enum { opened, initialized, connected } state; - unsigned int protocol_version; - - struct hpsb_host *host; +/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */ +struct raw1394_iso_packets { + __u32 n_packets; + struct raw1394_iso_packet_info *infos; +}; - struct list_head req_pending; - struct list_head req_complete; - struct semaphore complete_sem; - spinlock_t reqlists_lock; - wait_queue_head_t poll_wait_complete; +struct raw1394_iso_config { + /* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */ + __u32 data_buf_size; - struct list_head addr_list; + /* # of packets to buffer */ + __u32 buf_packets; - u8 *fcp_buffer; + /* iso channel (set to -1 for multi-channel recv) */ + __s32 channel; - u64 listen_channels; - quadlet_t *iso_buffer; - size_t iso_buffer_length; + /* xmit only - iso transmission speed */ + __u8 speed; - u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */ + /* max. latency of buffer, in packets (-1 if you don't care) */ + __s32 irq_interval; }; -struct arm_addr { - struct list_head addr_list; /* file_info list */ - u64 start, end; - u64 arm_tag; - u8 access_rights; - u8 notification_options; - u8 client_transactions; - u64 recvb; - u16 rec_length; - u8 *addr_space_buffer; /* accessed by read/write/lock */ -}; +/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */ +struct raw1394_iso_status { + /* current settings */ + struct raw1394_iso_config config; -struct pending_request { - struct list_head list; - struct file_info *file_info; - struct hpsb_packet *packet; - struct tq_struct tq; - struct iso_block_store *ibs; - quadlet_t *data; - int free_data; - struct raw1394_request req; -}; + /* number of packets waiting to be filled with data (ISO transmission) + or containing data received (ISO reception) */ + __u32 n_packets; -struct host_info { - struct list_head list; - struct hpsb_host *host; - struct list_head file_info_list; -}; + /* approximate number of packets dropped due to overflow or + underflow of the packet buffer (a value of zero guarantees + that no packets have been dropped) */ + __u32 overflows; -#endif /* __KERNEL__ */ + /* cycle number at which next packet will be transmitted; + -1 if not known */ + __s16 xmit_cycle; +}; #endif /* IEEE1394_RAW1394_H */ Added: branches/linux-2.4/raw1394-private.h ============================================================================== --- branches/linux-2.4/raw1394-private.h (original) +++ branches/linux-2.4/raw1394-private.h 2003-02-28 19:24:52.000000000 -0500 @@ -0,0 +1,79 @@ +#ifndef IEEE1394_RAW1394_PRIVATE_H +#define IEEE1394_RAW1394_PRIVATE_H + +/* header for definitions that are private to the raw1394 driver + and not visible to user-space */ + +#define RAW1394_DEVICE_MAJOR 171 +#define RAW1394_DEVICE_NAME "raw1394" + +struct iso_block_store { + atomic_t refcount; + size_t data_size; + quadlet_t data[0]; +}; + +enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0, + RAW1394_ISO_RECV = 1, + RAW1394_ISO_XMIT = 2 }; + +struct file_info { + struct list_head list; + + enum { opened, initialized, connected } state; + unsigned int protocol_version; + + struct hpsb_host *host; + + struct list_head req_pending; + struct list_head req_complete; + struct semaphore complete_sem; + spinlock_t reqlists_lock; + wait_queue_head_t poll_wait_complete; + + struct list_head addr_list; + + u8 *fcp_buffer; + + /* old ISO API */ + u64 listen_channels; + quadlet_t *iso_buffer; + size_t iso_buffer_length; + + u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */ + + /* new rawiso API */ + enum raw1394_iso_state iso_state; + struct hpsb_iso *iso_handle; +}; + +struct arm_addr { + struct list_head addr_list; /* file_info list */ + u64 start, end; + u64 arm_tag; + u8 access_rights; + u8 notification_options; + u8 client_transactions; + u64 recvb; + u16 rec_length; + u8 *addr_space_buffer; /* accessed by read/write/lock */ +}; + +struct pending_request { + struct list_head list; + struct file_info *file_info; + struct hpsb_packet *packet; + struct tq_struct tq; + struct iso_block_store *ibs; + quadlet_t *data; + int free_data; + struct raw1394_request req; +}; + +struct host_info { + struct list_head list; + struct hpsb_host *host; + struct list_head file_info_list; +}; + +#endif /* IEEE1394_RAW1394_PRIVATE_H */ Modified: branches/linux-2.4/Makefile ============================================================================== --- branches/linux-2.4/Makefile (original) +++ branches/linux-2.4/Makefile 2003-02-28 19:24:52.000000000 -0500 @@ -4,11 +4,11 @@ O_TARGET := ieee1394drv.o -export-objs := ieee1394_core.o ohci1394.o cmp.o +export-objs := ieee1394_core.o ohci1394.o cmp.o iso.o list-multi := ieee1394.o ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ - highlevel.o csr.o nodemgr.o dma.o + highlevel.o csr.o nodemgr.o dma.o iso.o obj-$(CONFIG_IEEE1394) += ieee1394.o obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o Modified: branches/linux-2.4/hosts.h ============================================================================== --- branches/linux-2.4/hosts.h (original) +++ branches/linux-2.4/hosts.h 2003-02-28 19:24:52.000000000 -0500 @@ -19,6 +19,7 @@ #define CSR_CONFIG_ROM_SIZE 0x100 struct hpsb_packet; +struct hpsb_iso; struct hpsb_host { struct list_head host_list; @@ -109,6 +110,31 @@ ISO_UNLISTEN_CHANNEL }; +enum isoctl_cmd { + /* rawiso API - see iso.h for the meanings of these commands + * INIT = allocate resources + * START = begin transmission/reception + * STOP = halt transmission/reception + * QUEUE/RELEASE = produce/consume packets + * SHUTDOWN = deallocate resources + */ + + XMIT_INIT, + XMIT_START, + XMIT_STOP, + XMIT_QUEUE, + XMIT_SHUTDOWN, + + RECV_INIT, + RECV_LISTEN_CHANNEL, /* multi-channel only */ + RECV_UNLISTEN_CHANNEL, /* multi-channel only */ + RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */ + RECV_START, + RECV_STOP, + RECV_RELEASE, + RECV_SHUTDOWN, +}; + enum reset_types { /* 166 microsecond reset -- only type of reset available on non-1394a capable IEEE 1394 controllers */ @@ -146,6 +172,12 @@ */ int (*devctl) (struct hpsb_host *host, enum devctl_cmd command, int arg); + /* rawiso transmission/reception functions. Return 0 on success, -1 + * (or -EXXX errno code) on failure. If the low-level driver does not + * support the rawiso API, set isoctl to NULL. + */ + int (*isoctl) (struct hpsb_iso *iso, enum isoctl_cmd command, unsigned long arg); + /* This function is mainly to redirect local CSR reads/locks to the iso * management registers (bus manager id, bandwidth available, channels * available) to the hardware registers in OHCI. reg is 0,1,2,3 for bus Added: branches/linux-2.4/iso.c ============================================================================== --- branches/linux-2.4/iso.c (original) +++ branches/linux-2.4/iso.c 2003-02-28 19:24:52.000000000 -0500 @@ -0,0 +1,439 @@ +/* + * IEEE 1394 for Linux + * + * kernel ISO transmission/reception + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include <linux/slab.h> +#include "iso.h" + +void hpsb_iso_stop(struct hpsb_iso *iso) +{ + if(!iso->flags & HPSB_ISO_DRIVER_STARTED) + return; + + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? + XMIT_STOP : RECV_STOP, 0); + iso->flags &= ~HPSB_ISO_DRIVER_STARTED; +} + +void hpsb_iso_shutdown(struct hpsb_iso *iso) +{ + if(iso->flags & HPSB_ISO_DRIVER_INIT) { + hpsb_iso_stop(iso); + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? + XMIT_SHUTDOWN : RECV_SHUTDOWN, 0); + iso->flags &= ~HPSB_ISO_DRIVER_INIT; + } + + dma_region_free(&iso->data_buf); + kfree(iso->infos); + kfree(iso); +} + +static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_iso_type type, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)) +{ + struct hpsb_iso *iso; + int dma_direction; + + /* make sure driver supports the ISO API */ + if(!host->driver->isoctl) { + printk(KERN_INFO "ieee1394: host driver '%s' does not support the rawiso API\n", + host->driver->name); + return NULL; + } + + /* sanitize parameters */ + + if(buf_packets < 2) + buf_packets = 2; + + if(irq_interval < 1 || irq_interval > buf_packets / 2) + irq_interval = buf_packets / 2; + + if(channel < -1 || channel >= 64) + return NULL; + + /* channel = -1 is OK for multi-channel recv but not for xmit */ + if(type == HPSB_ISO_XMIT && channel < 0) + return NULL; + + /* allocate and write the struct hpsb_iso */ + + iso = kmalloc(sizeof(*iso), SLAB_KERNEL); + if(!iso) + return NULL; + + /* allocate ringbuffer of packet descriptors */ + iso->infos = kmalloc(buf_packets * sizeof(struct hpsb_iso_packet_info), SLAB_KERNEL); + if(!iso->infos) + return NULL; + + iso->type = type; + iso->host = host; + iso->hostdata = NULL; + iso->callback = callback; + init_waitqueue_head(&iso->waitq); + iso->channel = channel; + iso->irq_interval = irq_interval; + dma_region_init(&iso->data_buf); + iso->buf_size = round_up_to_page(data_buf_size); + iso->buf_packets = buf_packets; + iso->pkt_dma = 0; + iso->first_packet = 0; + spin_lock_init(&iso->lock); + + if(iso->type == HPSB_ISO_XMIT) { + iso->n_ready_packets = iso->buf_packets; + dma_direction = PCI_DMA_TODEVICE; + } else { + iso->n_ready_packets = 0; + dma_direction = PCI_DMA_FROMDEVICE; + } + + atomic_set(&iso->overflows, 0); + iso->flags = 0; + iso->prebuffer = 0; + + /* allocate the packet buffer */ + if(dma_region_alloc(&iso->data_buf, iso->buf_size, host->pdev, dma_direction)) + goto err; + + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +int hpsb_iso_n_ready(struct hpsb_iso* iso) +{ + unsigned long flags; + int val; + + spin_lock_irqsave(&iso->lock, flags); + val = iso->n_ready_packets; + spin_unlock_irqrestore(&iso->lock, flags); + + return val; +} + + +struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int speed, + int irq_interval, + void (*callback)(struct hpsb_iso*)) +{ + struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT, + data_buf_size, buf_packets, + channel, irq_interval, callback); + if(!iso) + return NULL; + + iso->speed = speed; + + /* tell the driver to start working */ + if(host->driver->isoctl(iso, XMIT_INIT, 0)) + goto err; + + iso->flags |= HPSB_ISO_DRIVER_INIT; + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)) +{ + struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV, + data_buf_size, buf_packets, + channel, irq_interval, callback); + if(!iso) + return NULL; + + /* tell the driver to start working */ + if(host->driver->isoctl(iso, RECV_INIT, 0)) + goto err; + + iso->flags |= HPSB_ISO_DRIVER_INIT; + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel) +{ + if(iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel); +} + +int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel) +{ + if(iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel); +} + +int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) +{ + if(iso->type != HPSB_ISO_RECV || iso->channel != -1) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK, (unsigned long) &mask); +} + +static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle) +{ + int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle); + if(retval) + return retval; + + iso->flags |= HPSB_ISO_DRIVER_STARTED; + return retval; +} + +int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer) +{ + if(iso->type != HPSB_ISO_XMIT) + return -1; + + if(iso->flags & HPSB_ISO_DRIVER_STARTED) + return 0; + + if(cycle < -1) + cycle = -1; + else if(cycle >= 8000) + cycle %= 8000; + + iso->xmit_cycle = cycle; + + if(prebuffer < 0) + prebuffer = iso->buf_packets; + else if(prebuffer == 0) + prebuffer = 1; + + if(prebuffer > iso->buf_packets) + prebuffer = iso->buf_packets; + + iso->prebuffer = prebuffer; + + /* remember the starting cycle; DMA will commence from xmit_queue_packets() + once enough packets have been buffered */ + iso->start_cycle = cycle; + + return 0; +} + +int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync) +{ + int retval = 0; + int isoctl_args[3]; + + if(iso->type != HPSB_ISO_RECV) + return -1; + + if(iso->flags & HPSB_ISO_DRIVER_STARTED) + return 0; + + if(cycle < -1) + cycle = -1; + else if(cycle >= 8000) + cycle %= 8000; + + isoctl_args[0] = cycle; + + if(tag_mask < 0) + /* match all tags */ + tag_mask = 0xF; + isoctl_args[1] = tag_mask; + + isoctl_args[2] = sync; + + retval = iso->host->driver->isoctl(iso, RECV_START, (unsigned long) &isoctl_args[0]); + if(retval) + return retval; + + iso->flags |= HPSB_ISO_DRIVER_STARTED; + return retval; +} + +/* check to make sure the user has not supplied bogus values of offset/len + that would cause the kernel to access memory outside the buffer */ + +static int hpsb_iso_check_offset_len(struct hpsb_iso *iso, + unsigned int offset, unsigned short len, + unsigned int *out_offset, unsigned short *out_len) +{ + if(offset >= iso->buf_size) + return -EFAULT; + + /* make sure the packet does not go beyond the end of the buffer */ + if(offset + len > iso->buf_size) + return -EFAULT; + + /* check for wrap-around */ + if(offset + len < offset) + return -EFAULT; + + /* now we can trust 'offset' and 'length' */ + *out_offset = offset; + *out_len = len; + + return 0; +} + + +int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy) +{ + struct hpsb_iso_packet_info *info; + unsigned long flags; + int rv; + + if(iso->type != HPSB_ISO_XMIT) + return -EINVAL; + + /* is there space in the buffer? */ + if(iso->n_ready_packets <= 0) { + return -EBUSY; + } + + info = &iso->infos[iso->first_packet]; + + /* check for bogus offset/length */ + if(hpsb_iso_check_offset_len(iso, offset, len, &info->offset, &info->len)) + return -EFAULT; + + info->tag = tag; + info->sy = sy; + + spin_lock_irqsave(&iso->lock, flags); + + rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long) info); + if(rv) + goto out; + + /* increment cursors */ + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + iso->xmit_cycle = (iso->xmit_cycle+1) % 8000; + iso->n_ready_packets--; + + if(iso->prebuffer != 0) { + iso->prebuffer--; + if(iso->prebuffer <= 0) { + iso->prebuffer = 0; + rv = do_iso_xmit_start(iso, iso->start_cycle); + } + } + +out: + spin_unlock_irqrestore(&iso->lock, flags); + return rv; +} + +int hpsb_iso_xmit_sync(struct hpsb_iso *iso) +{ + if(iso->type != HPSB_ISO_XMIT) + return -EINVAL; + + return wait_event_interruptible(iso->waitq, hpsb_iso_n_ready(iso) == iso->buf_packets); +} + +void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error) +{ + unsigned long flags; + spin_lock_irqsave(&iso->lock, flags); + + /* predict the cycle of the next packet to be queued */ + + /* jump ahead by the number of packets that are already buffered */ + cycle += iso->buf_packets - iso->n_ready_packets; + cycle %= 8000; + + iso->xmit_cycle = cycle; + iso->n_ready_packets++; + iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets; + + if(iso->n_ready_packets == iso->buf_packets || error != 0) { + /* the buffer has run empty! */ + atomic_inc(&iso->overflows); + } + + spin_unlock_irqrestore(&iso->lock, flags); +} + +void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, + u16 cycle, u8 channel, u8 tag, u8 sy) +{ + unsigned long flags; + spin_lock_irqsave(&iso->lock, flags); + + if(iso->n_ready_packets == iso->buf_packets) { + /* overflow! */ + atomic_inc(&iso->overflows); + } else { + struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma]; + info->offset = offset; + info->len = len; + info->cycle = cycle; + info->channel = channel; + info->tag = tag; + info->sy = sy; + + iso->pkt_dma = (iso->pkt_dma+1) % iso->buf_packets; + iso->n_ready_packets++; + } + + spin_unlock_irqrestore(&iso->lock, flags); +} + +int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) +{ + unsigned long flags; + unsigned int i; + int rv = 0; + + if(iso->type != HPSB_ISO_RECV) + return -1; + + spin_lock_irqsave(&iso->lock, flags); + for(i = 0; i < n_packets; i++) { + rv = iso->host->driver->isoctl(iso, RECV_RELEASE, + (unsigned long) &iso->infos[iso->first_packet]); + if(rv) + break; + + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + iso->n_ready_packets--; + } + spin_unlock_irqrestore(&iso->lock, flags); + return rv; +} + +void hpsb_iso_wake(struct hpsb_iso *iso) +{ + wake_up_interruptible(&iso->waitq); + + if(iso->callback) + iso->callback(iso); +} Modified: branches/linux-2.4/dv1394.c ============================================================================== --- branches/linux-2.4/dv1394.c (original) +++ branches/linux-2.4/dv1394.c 2003-02-28 19:24:53.000000000 -0500 @@ -138,7 +138,7 @@ (will cause undeflows if your machine is too slow!) */ -#define DV1394_DEBUG_LEVEL 1 +#define DV1394_DEBUG_LEVEL 0 /* for debugging use ONLY: allow more than one open() of the device */ /* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */ |