📄 ieee1394_core.c
字号:
length, flags);
if (rcode < 0) {
hpsb_free_packet(packet);
return;
}
fill_async_readblock_resp(packet, rcode, length);
send_packet_nocare(packet);
return;
case TCODE_LOCK_REQUEST:
length = data[3] >> 16;
extcode = data[3] & 0xffff;
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
packet = create_reply_packet(host, data, 8);
if (!packet)
return;
if (extcode == 0 || extcode >= 7) {
/* let switch default handle error */
length = 0;
}
switch (length) {
case 4:
rcode = highlevel_lock(host, source, packet->data, addr,
data[4], 0, extcode, flags);
fill_async_lock_resp(packet, rcode, extcode, 4);
break;
case 8:
if (extcode != EXTCODE_FETCH_ADD &&
extcode != EXTCODE_LITTLE_ADD) {
rcode = highlevel_lock(host, source,
packet->data, addr,
data[5], data[4],
extcode, flags);
fill_async_lock_resp(packet, rcode, extcode, 4);
} else {
rcode = highlevel_lock64(host, source,
(octlet_t *)packet->data, addr,
*(octlet_t *)(data + 4), 0ULL,
extcode, flags);
fill_async_lock_resp(packet, rcode, extcode, 8);
}
break;
case 16:
rcode = highlevel_lock64(host, source,
(octlet_t *)packet->data, addr,
*(octlet_t *)(data + 6),
*(octlet_t *)(data + 4),
extcode, flags);
fill_async_lock_resp(packet, rcode, extcode, 8);
break;
default:
rcode = RCODE_TYPE_ERROR;
fill_async_lock_resp(packet, rcode, extcode, 0);
}
if (rcode < 0)
hpsb_free_packet(packet);
else
send_packet_nocare(packet);
return;
}
}
/**
* hpsb_packet_received - hand over received packet to the core
*
* For host driver module usage.
*
* The contents of data are expected to be the full packet but with the CRCs
* left out (data block follows header immediately), with the header (i.e. the
* first four quadlets) in machine byte order and the data block in big endian.
* *@data can be safely overwritten after this call.
*
* If the packet is a write request, @write_acked is to be set to true if it was
* ack_complete'd already, false otherwise. This argument is ignored for any
* other packet type.
*/
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
int write_acked)
{
int tcode;
if (unlikely(host->in_bus_reset)) {
HPSB_DEBUG("received packet during reset; ignoring");
return;
}
dump_packet("received packet", data, size, -1);
tcode = (data[0] >> 4) & 0xf;
switch (tcode) {
case TCODE_WRITE_RESPONSE:
case TCODE_READQ_RESPONSE:
case TCODE_READB_RESPONSE:
case TCODE_LOCK_RESPONSE:
handle_packet_response(host, tcode, data, size);
break;
case TCODE_WRITEQ:
case TCODE_WRITEB:
case TCODE_READQ:
case TCODE_READB:
case TCODE_LOCK_REQUEST:
handle_incoming_packet(host, tcode, data, size, write_acked);
break;
case TCODE_CYCLE_START:
/* simply ignore this packet if it is passed on */
break;
default:
HPSB_DEBUG("received packet with bogus transaction code %d",
tcode);
break;
}
}
static void abort_requests(struct hpsb_host *host)
{
struct hpsb_packet *packet, *p;
struct list_head tmp;
unsigned long flags;
host->driver->devctl(host, CANCEL_REQUESTS, 0);
INIT_LIST_HEAD(&tmp);
spin_lock_irqsave(&pending_packets_lock, flags);
list_splice_init(&host->pending_packets, &tmp);
spin_unlock_irqrestore(&pending_packets_lock, flags);
list_for_each_entry_safe(packet, p, &tmp, queue) {
list_del_init(&packet->queue);
packet->state = hpsb_complete;
packet->ack_code = ACKX_ABORTED;
queue_packet_complete(packet);
}
}
void abort_timedouts(unsigned long __opaque)
{
struct hpsb_host *host = (struct hpsb_host *)__opaque;
struct hpsb_packet *packet, *p;
struct list_head tmp;
unsigned long flags, expire, j;
spin_lock_irqsave(&host->csr.lock, flags);
expire = host->csr.expire;
spin_unlock_irqrestore(&host->csr.lock, flags);
j = jiffies;
INIT_LIST_HEAD(&tmp);
spin_lock_irqsave(&pending_packets_lock, flags);
list_for_each_entry_safe(packet, p, &host->pending_packets, queue) {
if (time_before(packet->sendtime + expire, j))
list_move_tail(&packet->queue, &tmp);
else
/* Since packets are added to the tail, the oldest
* ones are first, always. When we get to one that
* isn't timed out, the rest aren't either. */
break;
}
if (!list_empty(&host->pending_packets))
mod_timer(&host->timeout, j + host->timeout_interval);
spin_unlock_irqrestore(&pending_packets_lock, flags);
list_for_each_entry_safe(packet, p, &tmp, queue) {
list_del_init(&packet->queue);
packet->state = hpsb_complete;
packet->ack_code = ACKX_TIMEOUT;
queue_packet_complete(packet);
}
}
static struct task_struct *khpsbpkt_thread;
static LIST_HEAD(hpsbpkt_queue);
static void queue_packet_complete(struct hpsb_packet *packet)
{
unsigned long flags;
if (packet->no_waiter) {
hpsb_free_packet(packet);
return;
}
if (packet->complete_routine != NULL) {
spin_lock_irqsave(&pending_packets_lock, flags);
list_add_tail(&packet->queue, &hpsbpkt_queue);
spin_unlock_irqrestore(&pending_packets_lock, flags);
wake_up_process(khpsbpkt_thread);
}
return;
}
/*
* Kernel thread which handles packets that are completed. This way the
* packet's "complete" function is asynchronously run in process context.
* Only packets which have a "complete" function may be sent here.
*/
static int hpsbpkt_thread(void *__hi)
{
struct hpsb_packet *packet, *p;
struct list_head tmp;
int may_schedule;
current->flags |= PF_NOFREEZE;
while (!kthread_should_stop()) {
INIT_LIST_HEAD(&tmp);
spin_lock_irq(&pending_packets_lock);
list_splice_init(&hpsbpkt_queue, &tmp);
spin_unlock_irq(&pending_packets_lock);
list_for_each_entry_safe(packet, p, &tmp, queue) {
list_del_init(&packet->queue);
packet->complete_routine(packet->complete_data);
}
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irq(&pending_packets_lock);
may_schedule = list_empty(&hpsbpkt_queue);
spin_unlock_irq(&pending_packets_lock);
if (may_schedule)
schedule();
__set_current_state(TASK_RUNNING);
}
return 0;
}
static int __init ieee1394_init(void)
{
int i, ret;
/* non-fatal error */
if (hpsb_init_config_roms()) {
HPSB_ERR("Failed to initialize some config rom entries.\n");
HPSB_ERR("Some features may not be available\n");
}
khpsbpkt_thread = kthread_run(hpsbpkt_thread, NULL, "khpsbpkt");
if (IS_ERR(khpsbpkt_thread)) {
HPSB_ERR("Failed to start hpsbpkt thread!\n");
ret = PTR_ERR(khpsbpkt_thread);
goto exit_cleanup_config_roms;
}
if (register_chrdev_region(IEEE1394_CORE_DEV, 256, "ieee1394")) {
HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
ret = -ENODEV;
goto exit_release_kernel_thread;
}
ret = bus_register(&ieee1394_bus_type);
if (ret < 0) {
HPSB_INFO("bus register failed");
goto release_chrdev;
}
for (i = 0; fw_bus_attrs[i]; i++) {
ret = bus_create_file(&ieee1394_bus_type, fw_bus_attrs[i]);
if (ret < 0) {
while (i >= 0) {
bus_remove_file(&ieee1394_bus_type,
fw_bus_attrs[i--]);
}
bus_unregister(&ieee1394_bus_type);
goto release_chrdev;
}
}
ret = class_register(&hpsb_host_class);
if (ret < 0)
goto release_all_bus;
hpsb_protocol_class = class_create(THIS_MODULE, "ieee1394_protocol");
if (IS_ERR(hpsb_protocol_class)) {
ret = PTR_ERR(hpsb_protocol_class);
goto release_class_host;
}
ret = init_csr();
if (ret) {
HPSB_INFO("init csr failed");
ret = -ENOMEM;
goto release_class_protocol;
}
if (disable_nodemgr) {
HPSB_INFO("nodemgr and IRM functionality disabled");
/* We shouldn't contend for IRM with nodemgr disabled, since
nodemgr implements functionality required of ieee1394a-2000
IRMs */
hpsb_disable_irm = 1;
return 0;
}
if (hpsb_disable_irm) {
HPSB_INFO("IRM functionality disabled");
}
ret = init_ieee1394_nodemgr();
if (ret < 0) {
HPSB_INFO("init nodemgr failed");
goto cleanup_csr;
}
return 0;
cleanup_csr:
cleanup_csr();
release_class_protocol:
class_destroy(hpsb_protocol_class);
release_class_host:
class_unregister(&hpsb_host_class);
release_all_bus:
for (i = 0; fw_bus_attrs[i]; i++)
bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
bus_unregister(&ieee1394_bus_type);
release_chrdev:
unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
exit_release_kernel_thread:
kthread_stop(khpsbpkt_thread);
exit_cleanup_config_roms:
hpsb_cleanup_config_roms();
return ret;
}
static void __exit ieee1394_cleanup(void)
{
int i;
if (!disable_nodemgr)
cleanup_ieee1394_nodemgr();
cleanup_csr();
class_destroy(hpsb_protocol_class);
class_unregister(&hpsb_host_class);
for (i = 0; fw_bus_attrs[i]; i++)
bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
bus_unregister(&ieee1394_bus_type);
kthread_stop(khpsbpkt_thread);
hpsb_cleanup_config_roms();
unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
}
fs_initcall(ieee1394_init); /* same as ohci1394 */
module_exit(ieee1394_cleanup);
/* Exported symbols */
/** hosts.c **/
EXPORT_SYMBOL(hpsb_alloc_host);
EXPORT_SYMBOL(hpsb_add_host);
EXPORT_SYMBOL(hpsb_resume_host);
EXPORT_SYMBOL(hpsb_remove_host);
EXPORT_SYMBOL(hpsb_update_config_rom_image);
/** ieee1394_core.c **/
EXPORT_SYMBOL(hpsb_speedto_str);
EXPORT_SYMBOL(hpsb_protocol_class);
EXPORT_SYMBOL(hpsb_set_packet_complete_task);
EXPORT_SYMBOL(hpsb_alloc_packet);
EXPORT_SYMBOL(hpsb_free_packet);
EXPORT_SYMBOL(hpsb_send_packet);
EXPORT_SYMBOL(hpsb_reset_bus);
EXPORT_SYMBOL(hpsb_read_cycle_timer);
EXPORT_SYMBOL(hpsb_bus_reset);
EXPORT_SYMBOL(hpsb_selfid_received);
EXPORT_SYMBOL(hpsb_selfid_complete);
EXPORT_SYMBOL(hpsb_packet_sent);
EXPORT_SYMBOL(hpsb_packet_received);
EXPORT_SYMBOL_GPL(hpsb_disable_irm);
/** ieee1394_transactions.c **/
EXPORT_SYMBOL(hpsb_get_tlabel);
EXPORT_SYMBOL(hpsb_free_tlabel);
EXPORT_SYMBOL(hpsb_make_readpacket);
EXPORT_SYMBOL(hpsb_make_writepacket);
EXPORT_SYMBOL(hpsb_make_streampacket);
EXPORT_SYMBOL(hpsb_make_lockpacket);
EXPORT_SYMBOL(hpsb_make_lock64packet);
EXPORT_SYMBOL(hpsb_make_phypacket);
EXPORT_SYMBOL(hpsb_read);
EXPORT_SYMBOL(hpsb_write);
EXPORT_SYMBOL(hpsb_packet_success);
/** highlevel.c **/
EXPORT_SYMBOL(hpsb_register_highlevel);
EXPORT_SYMBOL(hpsb_unregister_highlevel);
EXPORT_SYMBOL(hpsb_register_addrspace);
EXPORT_SYMBOL(hpsb_unregister_addrspace);
EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace);
EXPORT_SYMBOL(hpsb_get_hostinfo);
EXPORT_SYMBOL(hpsb_create_hostinfo);
EXPORT_SYMBOL(hpsb_destroy_hostinfo);
EXPORT_SYMBOL(hpsb_set_hostinfo_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
EXPORT_SYMBOL(hpsb_set_hostinfo);
/** nodemgr.c **/
EXPORT_SYMBOL(hpsb_node_fill_packet);
EXPORT_SYMBOL(hpsb_node_write);
EXPORT_SYMBOL(__hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
/** csr.c **/
EXPORT_SYMBOL(hpsb_update_config_rom);
/** dma.c **/
EXPORT_SYMBOL(dma_prog_region_init);
EXPORT_SYMBOL(dma_prog_region_alloc);
EXPORT_SYMBOL(dma_prog_region_free);
EXPORT_SYMBOL(dma_region_init);
EXPORT_SYMBOL(dma_region_alloc);
EXPORT_SYMBOL(dma_region_free);
EXPORT_SYMBOL(dma_region_sync_for_cpu);
EXPORT_SYMBOL(dma_region_sync_for_device);
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);
EXPORT_SYMBOL(hpsb_iso_recv_flush);
/** csr1212.c **/
EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
EXPORT_SYMBOL(csr1212_get_keyval);
EXPORT_SYMBOL(csr1212_new_directory);
EXPORT_SYMBOL(csr1212_parse_keyval);
EXPORT_SYMBOL(csr1212_read);
EXPORT_SYMBOL(csr1212_release_keyval);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -